ADO.NET Tech Preview: Entity Data Model
Microsoft Corporation
June 2006
Applies to:
ADO.NET
Entity Data Model
Summary: Review a precise and complete definition of the Entity Data Model (EDM). (35 printed pages)
Contents
Introduction
Basic Concepts
EDM Instances
EDM Primitive Types
EDM Future Directions
Introduction
The Entity Data Model is an Entity-Relationship data model. The ER model is familiar to most if not all database application developers, and has been used successfully for about 30 years. The central concepts in the EDM are entities and relationships. Entities are instances of Entity Types (e.g., Customer, Employee) which are richly structured records with a key. An entity key is formed from a subset of properties of the Entity Type. The key (e.g., CustId, EmpId) is a fundamental concept to uniquely identify and update entity instances and to allow entity instances to participate in relationships. Entities are grouped in Entity Sets (i.e., Customers is a set of Customer instances). Relationships are instances of Relationship Types which are associations among two or more entity types (e.g., Employee WorksFor Department). Relationships are grouped in Relationship Sets.
The EDM works in conjunction with a new query language eSQL, a SQL-like query language designed to enable set-oriented, declarative queries and updates in terms of entities and relationships. EDM can work with other query languages as well.
The EDM and eSQL together represent a richer data model and query language and have been designed to enable applications such as CRM, ERP, data-intensive services such as Reporting Services, Business Intelligence, Replication, Synchronization, and data-intensive application developers to model and manipulate data at a level of structure and semantics that is closer to their needs.
This document is the specification of the EDM. It is intended to provide a precise and complete definition of the EDM.
Document Outline
This document consists of 4 major sections.
Part 1: Basic concepts describing the core EDM
Part II: Constructs describing instantiation of EDM schema
Part III: Constructs describing management of EDM instances
Part IV: EDM Primitive Types
Basic Concepts
The EDM concepts can be categorized into two kinds. One set of concepts for defining types or structure and the other set for managing instances of these types.
Types
- EntityType: An EntityType defines the principal data objects about which information has to be managed such as person, places, things or activities relevant to the application. An Entity is an instance of an EntityType. It has a unique identity, independent existence, and forms the operational unit of consistency.
- Property: An EntityType can have one or more properties of the specified SimpleType, ComplexType, or RowType. Properties can be either single-valued or multi-valued.
- EntityKey: All instances of an EntityType are uniquely identified by the value of its identifying properties. This set of identifying properties is called an EntityKey.
- ComplexType: A ComplexType represents a set of related information. Like EntityType, it consists of one or more properties of SimpleType, ComplexType, or RowType. However unlike EntityType, ComplexType is not associated with an EntityKey.
- RowType: RowType is an anonymous type that is structurally similar to ComplexType except that it cannot participate in type-inheritance. Two (anonymous) RowType instances are comparable if their corresponding RowTypes have the same number, sequence and type of properties.
- RelationshipType: While EntityTypes are like nouns of a data model, RelationshipTypes are the verbs that connect those nouns. A RelationshipType is described over two or more participating EntityTypes. The EDM supports two kinds of RelationshipTypes, Association and Containment. An Association is like a peer-to-peer relationship while Containment is a parent-child relationship with specific membership semantics
- Schema: All EDM types are contained within some namespace. The Schema concept defines a namespace that describes the scope of EDM types.
Instances
- EntitySet: An EntitySet for an EntityType holds instances of its EntityType or any of its subtypes. Multiple EntitySets may be defined for a given EntityType.
- A RelationshipSet for a given relationship type may hold instances of that type. The relationship instance connects entity instances contained by the EntitySets participating in this RelationshipSet. A RelationshipSet description includes the RelationshipType and the corresponding EntitySets of the EntityTypes described in RelationshipType.
- EntityContainer: All EDM instance-based concepts like EntitySets and RelationshipSets are defined in the scope of an EntityContainer. Users can have one or more instances of EntityContainer. An EntityContainer can reference one or more Schemas.
Abstract Syntax
We use an Extended Backus-Naur Form (EBNF) based notation to describe syntax for creating EDM concepts. The abstract syntax is described using the following notation:
- Constants, keywords or terminals are expressed using UPPERCASE-BOLD
- Literals are expressed using mixed-case italics
- Non-terminals are expressed using Mixed-case-bold
- Default values are under-lined
Schema Definition Language (SDL)
We use an XML-based data-definition language based on the abstract syntax to describe EDM schemas, thus this language is called Schema Definition Language (SDL). The complete SDL is described in Section Error! Reference source not found.. We will be using SDL fragments to illustrate EDM concepts throughout this document.
Simple Types
SimpleTypes are atomic and consist of primitive types and EnumerationType.
Primitive Types
The EDM uses an abstract type system to define its primitive types such as String, Boolean, SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, UInt64, Float, Decimal, Xml, Guid and DateTime. For a complete description of EDM primitive types see Section 0 below.
An Enumeration type defines a set of symbolic names – such as (red, blue, green) or (spring, summer, autumn, winter). An instance of an enumeration type has a value that is a member of this set. The following SDL example shows the definition of an enumeration type:
Example 1
1. <EnumerationType Name="Seasons"> 2. <EnumerationMember Name="Spring" /> 3. <EnumerationMember Name="Summer" /> 4. <EnumerationMember Name="Autumn" /> 5. <EnumerationMember Name="Winter" /> 6. </EnumerationType>
This defines a type called Seasons. Instances of this type can only take on one of the 4 values specified in lines 2-5. An instance of Enumeration type is treated as an EDM simple type. The Enumeration type values are un-ordered, in other words, they can participate in equality checks but not in sort operations.
EntityType
An Entity is an instance of an EntityType. It has a unique identity, independent existence and forms the operational unit of consistency. Intuitively, EntityTypes model the "top-level" concepts within a data model—such as Customers, Orders, Suppliers, etc (to take the example of a typical line-of-business system). An Entity-instance represents one particular instance of the EntityType such as a specific customer or a specific order. An EntityType can be either abstract or concrete where the former cannot have instances.
An EntityType has a name, a payload consisting of one or more properties and an EntityKey that describes the set of properties, values of which uniquely identify the instance of an entity within an entity set.
The type of a property can be a primitiveType, enumerationType, complexType, or a rowType. See on page 19 for a complete description of PrimitiveType and its applicable facets.
EntityKey
An entity-type contains an entity key consisting of one or more of its properties. Any set of non-nullable, immutable, SimpleType properties can serve as the key. Complex type and multivalued properties cannot be part of a key. However, a single-value SimpleType property of a ComplexType can be part of the entity key. Example shows specification of a key composed of a single SimpleType property.
Example 2
1. <EntityType Name="Person" Key="Id"> 2. <Property Name="Id" Type="String" Nullable="false"/> 3. <Property Name="Name" Type="Name"/> 4. <Property Name="PhoneNumbers" Multiplicity="*"/> 5. </EntityType>
Abstract Syntax
The abstract syntax for describing an EntityType is given below:
EntityType ::= ENTITYTYPE entityTypeName [BASE entityTypeName] [ABSTRACT true|false] KEY propertyName [, propertyName]* {(propertyName PropertyType [PropertyFacet]*) +} PropertyType ::= ((PrimitiveType [PrimitiveTypeFacets]*) | (complexOrEnumTypeName) | RowType PropertyFacet ::= ( [NULLABLE true | false] | [DEFAULT defaultVal] | [MULTIPLICITY [ 1|*] ] ) PropertyTypeFacet ::= LENGTH|MAXLENGTH|PRECISION|SCALE|UNICODE|COLLATION | DATETIMEKIND|PRESERVESECONDS PrimitiveType ::= BINARY | BOOLEAN |DATETIME|DOUBLE|DECIMAL|FLOAT|GUID|SBYTE|INT16| INT32 | INT64 | BYTE | UINT16 | UINT32 | UINT64 | STRING | XML | MONEY)
Property
Properties describe some aspect of an EntityType (or ComplexType) by associating with it a unique name and type. A property description consists of its name, type and a set of facets like nullable, default, etc. The property's type can be any primitive type, ComplexType, or a RowType. The facets associated with a property can be classified as type-specific and type-agnostic. The type-agnostic facets are applicable to all properties while type-specific are applicable to EDM primitive types. The next section describes the set of type-agnostic facets.
Facets
Nullable
All properties except for those participating in an EntityKey can be nullable. The value of a nullable property can be NULL. This is a boolean facet with the default value as true. The example shown below describes this facet's usage.
Example 3
1. <EntityType Name="Person" Key="EmailID"> 2. <Property Name="Name" Type="String" /> 3. <Property Name="EmailID" Type="String" Nullable="false"/> 4. <Property Name="Address" Type="AddressType"/> 5. <Property Name="PhoneNumbers" Multiplicity="*" Type="String"/> 6. </EntityType>
The EmailID property cannot be NULL, indicating that a Person instance has a non-NULL email. Note also that Nullable is allowed on complex-typed and multivalued properties. For example, the Address property can be NULL, indicating that an Address value need not be supplied for the Address property.
Default
The default facet may contain a "default" value for a property. If no explicit value has been specified during instantiation, then the property gets assigned its default value. In EDM v1.0 the default facet is applicable for single-valued SimpleType properties. The facet's type is same as property's type and its value can be any constant of that type.
Multiplicity
The notion of multiplicity describes the cardinality of a property. Entity properties can be either single or multi-valued. The value "1" denotes single-valued and "*" denotes multi-valued properties where the default is "1". The collection semantics for the multi-valued property is that of a bag or multi-set, the individual items in a multi-valued property are un-ordered and may have duplicates. The following example describes the usage of this facet.
Example 4
1. <EntityType Name="Person" Key="EmailID"> 2. <Property Name="Name" Type="String" /> 3. <Property Name="EmailID" Type="String" Nullable="false"/> 4. <Property Name="PhoneNumbers" Type="String" Multiplicity="*" /> 5. </EntityType>
The PhoneNumbers property described on line 4 is a multivalued string property, indicating that PhoneNumbers can contain zero or more string values.
ComplexType
A ComplexType provides a mechanism to create properties with a rich (structured) payload as shown in the example below. A ComplexType may derive form another ComplexType. Its definition includes its name, an optional base-ComplexType and payload. The payload of a ComplexType is very similar to that of an EntityType as shown in the abstract syntax described below.
Example 5
1. <ComplexType Name="AddressType"> 2. <Property Name="Street" Type="string" nullable="false"/> 3. <Property Name="City" Type="string"/> 4. <Property Name="State" Type="string" fixedLength="2" nullable="false"/> 5. </ComplexType> 6. <EntityType Name="Customer" Key="CustomerId"> 7. <Property Name="CustomerId" Type="String"/> 8. <Property Name="Address" type="AddressType"/> 9. <!--Other Properties--> 10. </EntityType>
Lines 1-5 describe ComplexType "AddressType". Line 8 shows the definition of a ComplexType property.
Abstract Syntax
The abstract syntax representation for describing ComplexType is shown below:
ComplexType ::= COMPLEXTYPE name [BASE complexTypeName] [ABSTRACT true|false] { (propertyName PropertyType PropertyFacet* )* }
RowType
The EDM types seen so far are all nominal or named types. This section introduces the only anonymous EDM type, the RowType. Structurally it is similar to a ComplexType except it cannot have a name or derive from another type. The payload of a RowType is exactly the same as that of a ComplexType as shown below:
Example 6
1. <EntityType Name="Customer" Key="CustomerId"> 2. <Property Name="CustomerId" Type="String"/> 3. <Property Name="Address"> 4. <RowType> 5. <Property Name="Street" Type="string" nullable="false"/> 6. <Property Name="City" Type="string"/> 7. <Property Name="State" Type="string" fixedLength="2" /> 8. </RowType> 9. </Property> 10. <!--Other Properties--> 11. </EntityType>
Lines 4-8 describe the declaration of the RowType-valued Address Property. Since RowType cannot have a name that a property can refer to, it has to be defined inline in the scope of a property.
The SDL (XML based DDL) for EDM v1.0 will not support the declaration of RowType-valued properties. However, eSQL query results may contain transient RowType-valued properties.
Abstract Syntax
An abstract syntax representation for RowType is shown below:
RowType ::= ROWTYPE { (propertyName PropertyType PropertyFacet* )+ }
Type Equality
The instances of named-type are considered comparable if their types have the same name. The same mechanism may not be applicable for anonymous types. This section describes the semantics for determining comparability of two anonymous types. Two RowTypes are considered comparable if they are structurally equivalent that means they have the same number, sequence and type of properties. The property name is not significant for the purposes of comparing RowTypes.
Relationship Type
While entity types are the nouns of a data model, relationships are the verbs that connect those nouns. A relationship denotes a connection (a.k.a. relation or link) between two or more Entities. An example of relationship would be: A customer places one or more orders, an order contains order details, a product is available from on or more suppliers, and so on. In these sentences, we have shown entity in italics and underlined the relationships among them. The relationship concept is borrowed from the classic Entity-Relation data model and made a first-class concept in EDM.
In EDM the relationship type is an abstract notion, the two concrete relationship types are Association and Containment, described later in this section.
Characterization
Relationships are primarily characterized by its degree, multiplicity, direction and kind. This section describes these terms in more detail.
Degree
The degree (or arity) of a relationship is the number of EntityTypes associated with it. The most common form of relationship is a binary relationship that relates two EntityTypes, ternary relates three EntityTypes and the most general form is the n-ary relationship that can relate n EntityTypes.
EDM v1.0 support is restricted to binary relationships.
Multiplicity
The multiplicity of a relationship describes the cardinality or number of instances of an EntityType that can be associated with the instances of another EntityType. The basic types of multiplicity are: one-one, one-many and many-many as shown below:
Figure 1. Relationship to Multiplicty
A one-many is a special case of many-many and one-one is a special case of one-many relationship. Similarly cardinality or zero (implying that it's optional) can be seen as a special case of the above relationships. For instance 0 or 1 to many is a special case of 1 to many. The example shown below shows the usage of multiplicity in a relationship.
Example 7
1. <Association Name="CustomerOrder"> 2. <End Type="Customer" Multiplicity="1"> 3. <End Type="Order" Multiplicity="*"> 4. <OnDelete Action="Cascade" /> 5. </End> 6. </Association>
The "Multiplicity" facet defines the cardinality of a relationship end. In this example, we specify that there is exactly one Customer (value is "1" on line 2) for zero or more Order instances (value is "*" on line 3). Other values for this facet are:
"0..1"– zero or one
"1" – exactly one
"*" – zero or more
"1..*" – one or more
"n" – exactly n
"n..m" – between n and m, inclusive, where n is less than or equal to m.
Direction
In EDM v1.0 all relationships are bi-directional. Conceptually they may be viewed as two mutually inverse relations. In a future version of EDM, we may add support for uni-directional relationships.
Role
A bi-directional relationship instance can be seen as connecting entity-instances in both directions. The label or name given to a relationship-end is called role. Role names are unique within a relationship**.**
Kind
There are different kinds of relationships. The two kinds supported in EDM v1.0 are Association and Containment. Future versions of the EDM may add support for other relationship notions that capture common semantic patterns required by applications and services such as Composition, Identifying, and Part-Whole.
Operational Behavior
For certain kinds of operations it is useful to operate on related entities as a single unit. This section describes the kinds of operations and their associated behavior that may be specified on the relationship-type.
Operations and Actions
The operational semantics are described on the RelationshipType by specifying the desired Operation and its corresponding action.
Example 8
1. <EntityType Name="Order" Key="OrderId"> 2. <Property Name="OrderId" Type="String"/> 3. <!--Other Properties--> 4. </EntityType> 6. <EntityType Name="Customer" Key="CustomerId"> 7. <Property Name="CustomerId" Type="String"/> 8. <!--Other Properties--> 9. </EntityType> 10. 11. <Association Name="CustomerOrder"> 12. <End Type="Customer" Multiplicity="1"> 13. <OnDelete Action="Cascade" /> 14. </End> 15. <End Type="Order" Multiplicity="*"/> 16. </Association>
In the above example the <Association> element on line 11 is used to define the relationship. The <OnDelete> element on line 13 describes the operational behavior by specifying the OnDelete operation and the Cascade action for the "CustomerOrder" association.
Operations
OnDelete: This operation specifies the action for resolving the relationship-instance associated with a deleted entity-instance. For the purposes illustration lets assume a relationship is like an edge of a graph that connects two vertices. The deletion of one vertex may result in an invalid edge that may be resolved by choosing one of the following options: 1) delete the specified vertex, other vertex and the edge, 2) disallow deletion of a connected vertex, or 3) delete the specified vertex and the edge. A similar set of options are available when an entity-instance participating in a relationship is deleted. The next section describes the details of the actions available for OnDelete.
In EDM v1.0, the OnDelete operation on an Association may be specified on exactly one end of the relationship-type.
Actions
- Cascade: This action instructs the operation-processor to delete the relationship instance and apply the action on the entity-instance at the other end of the relationship. For instance delete all Orders belonging to the Customer as shown in the example above.
- Restrict: The operation on the entity-instance be restricted. For instance prevent deletion of a Customer when outstanding Orders exist.
- RemoveAssociation: Perform the operation on the specified entity-instance at either end of an Association relationship and remove the Association-instance between the two entity-instances.
Association
This is one of the most common and general-purpose relationships. It defines a peer-to-peer relationship between participating entity-types and can support any multiplicity at either end. The OnDelete operational behavior can be specified at any end of the relationship.
A classic example of an association is the relationship between the Customer and Order entities. Typically, this relationship has the following characteristics:
- Multiplicity: each Order is associated with exactly one Customer. Every Customer has zero or more Orders.
- Operational Behavior: OnDelete Cascade; when an Order with one or more OrderLines is deleted the corresponding OrderLines(s) also get deleted.
The SDL uses the <Association> element to create this relationship, as shown below:
Example 9
1. <Association Name="CustomerOrder"> 2. <End Type="Customer" Multiplicity="1" role="Orders" > 3. <OnDelete Action="Cascade" /> 4. </End> 5. <End Type="Order" Multiplicity="*" role="OrderedBy" /> 6. </Association>
The <Association> element in line 1 defines the CustomerOrder relationship between Customer and Order EntityType.
Abstract Syntax
The abstract syntax for describing Association relationship is shown below:
AssociationType ::= ASSOCIATION associationName (EndDescription EndDescription) EndDescription ::= ENTITYTYPE entityTypeName [ROLE roleName] MULTIPLICITY (0..1 | 1 | * | 1..* | n | n..m) [Operation]* Operation ::= ONDELETE (CASCADE| RESTRICT | REMOVEASSOCIATION)
Containment
This is a kind of relationship with the following characteristics:
- Direction: It is a bi-directional relationship with different semantics for each direction of the relationship.
- Multiplicity: This relationship is 1 to 0..N where the cardinality of one end is always 1. For convenience, we will refer to the 1-end as the parent, and the other end as the child.
- Exclusive membership constraint: A child entity-type may participate in multiple Containment relationships however a child entity-instance can be a member of exactly one Containment relationship-instance. In other words, a child entity-instance at all times is contained in exactly one parent entity-instance.
- Operational Behavior: A Containment child entity-instance always lives in the scope of its parent entity-instance. As a result the Action on OnDelete operation is restricted to be Cascade or Restrict with Cascade as the default.
The following example shows the definition of a Containment relationship:
Example 10
1. <Containment Name="Parent_Child"> 2. <End Type="Parent" role="Parent" /> 3. <End Type="Child" Multiplicity="*" role="Children" /> 4. </Containment>
The <Containment> element in line 1 defines the Parent_Child relationship between Parent and Child EntityType.
Abstract Syntax
The abstract syntax for describing Containment relationship is shown below:
ContainmentType ::= CONTAINMENT containmentName (ParentEnd, ChildEnd) ParentEnd ::= PARENT entityTypeName [ROLE roleName] [Operation] ChildEnd ::= CHILD entityTypeName [ROLE roleName] [ MULTIPLICITY (0..1 | 1 | * | 1..* | n | n..m) ] Operation ::= ONDELETE (CASCADE | RESTRICT)
Navigation Property
Navigation properties are pseudo-properties on entities that describe the ends of a relationship. Standard- properties describe a value associated with an entity, while pseudo-properties describe a navigation-path over a relationship. For example, given a relationship between Customer and Order entities, an Order entity-type may describe a navigation property "OrderedBy" that represents the Customer-instance associated with that particular Order-instance.
DataType
The datatype of a navigation property is always Ref<T> and has the same multiplicity as the associated relationship end. For example, assuming a 1-n relationship between Customer and Order, a navigation property "OrderedBy" on the Order entity would have type Ref<Customer>.
The following example describes the creation of a Navigation property:
Example 11
1. <EntityType Name="Customer" Key="CustomerId"> 2. ... 3. <NavigationProperty name="Orders" RelationshipType="CustOrderType" toRole="Orders" /> 5. 6. </EntityType> 6. 7. <EntityType Name="Order" Key="OrderId"> 8. ... 9. <NavigationProperty name="OrderedBy" fromRole="Order" RelationshipType="CustomerOrderType" toRole="Customer"/> 11. </EntityType> 12. 13. <Association Name="CustomerOrderType"> 14. <End Type="Customer" Multiplicity="1" Role="Customer" /> 15. <End Type="Order" Multiplicity="*" Role="Orders" /> 16. </Association> 17. 18. <!-- Alternative syntax for NavigationProperty --> 19. 20. <NavigationProperty Name="Orders" RelationshipType="CustomerOrderType" fromRole="Customer" toRole="Orders" /> 22. 23. <NavigationProperty Name="OrderedBy" RelationshipType="CustomerOrderType" fromRole="Orders" toRole="Customer" />
Abstract Syntax
The abstract syntax for describing Navigation property is shown below:
NavigationProperty::= NAVIGATIONPROPERTY NAME propertyName RELATIONSHIPTYPE relationshipName [FROMROLE role] TOROLE role
Inheritance
Inheritance is a fundamental modeling concept that allows different types to be related in a "Is a" relationship enabling extensibility and reuse of existing types. When type A inherits from type B, we say B is the base-type of A and A is a sub-type or derived-type of B. The derived-type inherits all properties of its base-type and these properties are called inherited-properties. The derived-type can be extended to have more properties and these additional properties are called direct-properties. The direct-property name may be the same as its inherited-property name in which case the direct-property has to be qualified with the new modifier. The name collision does not result in an ambiguity as based on the type of the instance at the point of access it resolves to either the direct or inherited-property. All valid derived-type instances at all times are also valid base type instances and can be substituted for the parent instance.
An EDM ComplexType can only inherit from another ComplexType; similarly an EntityType can only inherit from another EntityType. EDM v1.0 does not support inheritance of RelationshipTypes.
A derived entity type always inherits the definition of its key, from its base type which cannot be changed. The figure below shows an inheritance example for entity types.
Figure 2. Inheritance and Type Hierarchy
The SDL example below shows an EntityType "CustomerType" deriving from "ContactType".
Example 12
1. <EntityType Name="ContactType" Key="Id"> 2. <Property Name="Id" Type="String"/> 3. <!--Other Properties--> 4. </EntityType> 5. <EntityType Name="CustomerType" baseType="ContactType" > 6. <Property Name="CompanyName" Type="String" Nullable="false" /> 7. </EntityType>
Schemas
In general, type and data-model systems allow the created types to physically reside in a repository or file and logically, live in a namespace. This is similar to the notion of namespace in SQL, CLR, and XSD. All types reside in some namespace. The Schema is the EDM construct that allows creation of namespaces.
The contents of a namespace can be defined by one or more schema instances. The type names have to be unique within a namespace. For instance an EntityType cannot have the same name as a ComplexType within the same namespace. The namespace forms a part of the type's fully-qualified name. The following example demonstrates the use of the Schema construct.
Example 13
1. <Schema Namespace="MyCompany.LOBSchema"> 2. <EntityType Name="Customer" Key="CustomerId"> 3. ... 4. </EntityType> 5. <EntityType Name="Order" Key="OrderId"> 6. ... 7. </EntityType> 8. <ComplexType Name="Address"> 9. ... 10. </ComplexType> 11. </Schema>
This example shows that the Customer and Order are defined within the schema called MyCompany.LOBSchema. Note that every name defined within this schema also has a fully qualified name, e.g. MyCompany.LOBSchema.Customer.
A Schema can refer to contents of another Schema or namespace by importing it with the Using clause. The imported namespace can be associated with an alias which is then used to refer to its types or the types can be directly used by specifying its full-qualified name. The following SDL example illustrates these concepts:
Example 14
1. <Schema Namespace="MyCompany.MySchema"> 2. <Using Namespace="YourCompany.YourSchema"/> 3. <Using Namespace="AnotherCompany.AnotherSchema" Alias="Another"/> 4. <ComplexType Name="Type1" BaseType="YourType"> 5. ... 6. </ComplexType> 7. <EntityType Name="Type2" BaseType="Another.AnotherType"> 8. ... 9. </EntityType> 10. <EntityType Name="Type3" Key="..."> 11. <Property Name="Type3Prop1" Type="YourCompany.YourSchema.YourType" /> 13. ... 14. </EntityType> 15. </Schema>
Line 2 imports namespace YourCompany.YourSchema. YourType is defined in this schema and can be used without qualification (as its unique across all visible namespaces), shown in line 4. It is also possible to define an alias for an imported namespace, as shown in line 3. Types defined in this namespace can be referenced by qualifying them with the alias—as shown in line 8. The alias name cannot be the same as an existing namespace.
Abstract Syntax
The abstract syntax for describing Schema is shown below:
Schema ::= SCHEMA namespace [USING namespace [ALIAS aliasName]]* {(EntityType | ComplexType | RelationshipType | EnumerationType)*}
Taxonomy of EDM Types
So far we have seen the various categories of types available in the EDM. In this section, we provide a proper classification of types within the EDM type system. This is shown in the figure below
Figure 3. EDM Type System
EDM Instances
The EDM provides concepts for defining types and managing instances of those types. Top level Instances in EDM are called entities that are of type EntityType and belong to at most one EntitySet. Other types like relationship-types have instances in the context of a relationship-set while ComplexType, RowType, and SimpleType have instances in the context of the property of an entity-instance. This section describes the constructs used for managing instances.
EntitySet
An EntitySet ES for an entity type ET may contain instances of ET and any of its subtypes. Multiple entity sets may be defined for a given entity type. The EntitySet may contain any entity instance that satisfies the following three conditions:
The Entity instance's type is either the same as EntitySet's type or any of its subtype.
The Entity instance's key value uniquely identifies it in the EntitySet.
The Entity instance is not a member of any other EntitySet
The following SDL example shows declaration of an EntitySet
Example 15
1. <EntitySet Name="CustomerSet" EntityType="CustomerType"/>
This example shows the creation of EntitySet named CustomerSet of EntityType CustomerType.
Abstract Syntax
The abstract syntax for describing EntitySet is shown below:
EntitySet ::= ENTITYSET entitySetName ENTITYTYPE entityTypeName
RelationshipSet
A RelationshipSet contains relationship instances of the specified RelationshipType. A relationship instance connects two or more entity-instances belonging to the EntitySet(s) associated with the RelationshipSet. The RelationshipSet description includes EntitySet(s) that can hold instances of EntityTypes associated with ends of its RelationshipType.
Said in a more formal way: Given a RelationshipType RT, over EntityType ET1 and ET2, a RelationshipSet RS for RT, EntitySet ES1 and EntitySet ES2 holds instances of RT that connect entity-instances in ES1 and ES2.
RelationshipType and RelationshipSet are abstract concepts. For each concrete implementation of RelationshipType there exists a corresponding concrete RelationshipSet. For instance AssociationType is a concrete RelationshipType and AssociationSet is a concrete RelationshipSet. This section describes AssociationSet and ContainmentSet the two concrete RelationshipSets supported by EDM v1.0.
EDM v1.0 allows a maximum of one RelationshipSet per RelationshipType per EntitySet.
AssociationSet
An AssociationSet contains relationship-instances of the specified AssociationType. The AssociationType specifies the EntityTypes of the two end points while AssociationSet specifies the EntitySets that correspond to these EntityTypes. The association-instances contained in the AssociationSet relate entity-instances belonging to these EntitySets.
The following SDL example demonstrates the usage of AssociaitonSet
Example 16
1. <EntityType Name="Customer" Key="CustomerId"> 2. ... 3. </EntityType> 4. <EntityType Name="Order" Key="OrderId"> 5. ... 6. </EntityType> 7. <Association Name="CustomerOrderType"> 8. <End Type="Customer" Multiplicity="1" Role="OrderedBy" /> 9. <End Type="Order" Multiplicity="*" Role="Orders" /> 10. </Association> 11. 12. <EntitySet Name="CustomerSet" EntityType="Customer"/> 13. 14. <EntitySet Name="OrderSet" EntityType="Order"/> 15. 16. <AssociationSet Name="CustomerOrderSet" Association="CustomerOrderType"> 17. <End EntitySet="CustomerSet"/> 18. <End EntitySet="OrderSet"/> 19. </AssociationSet >
Lines 1 – 6 describe creation of EntityTypes "Customer" and "Order". Line 7 defines AssociationType "CustomerOrderType". Lines 12 to 14 describe creation of EntitySet "CustomerSet" and "OrderSet". The <AssociationSet> element on line 16 defines AssociationSet named "CustomerOrderSet" of type "CustomerOrderType" defined on line 7 above. The two EntitySets corresponding to the AssociationType-end EntityTypes are specified on line 17 and 18. The association instances will live in CustomerOrderSet and connect instances in CustomerSet and OrderSet.
Abstract Syntax
The abstract syntax for describing AssociationSet is shown below:
AssociationSet ::= ASSOCIATIONSET assocSetName TYPE assocType {EndDescription EndDescription} EndDescription ::= END ENTITYSET entitySetName
ContainmentSet
A ContainmentSet contains relationship-instances of the specified ContainmentType. The ContainmentType specifies the EntityTypes of the parent and child ends while ContainmentSet specifies the EntitySets that contain instances of these EntityTypes. The Containment instances contained in the ContainmentSet relate entity-instances belonging to these EntitySets.
The following SDL example demonstrates the usage of ContainmentSet
Example 17
1. <EntityType Name="Organization" Key="Id"> 2. ... 3. </EntityType> 4. <EntityType Name="Department" Key="Id"> 5. ... 6. </EntityType> 7. 8. <Containment Name="OrgHasDeptType"> 9. <Parent Type="Organization" Name="HasDept" /> 10. <Child Type="Department" Multiplicity="*" Name="ContainedBy" /> 11. </Containment> 12. <Containment Name="DeptHasDeptType"> 13. <Parent Type="Department" /> 14. <Child Type="Department" Multiplicity="*" Name="ContainedBy" /> 15. </Containment> 16. 17. <EntitySet Name="OrganizationSet" EntityType="Organization"/> 18. <EntitySet Name="DepartmentSet" EntityType="Department"/> 19. 20. <ContainmentSet Name="OrgHasDeptSet" Containment="OrgHasDeptType"> 21. <Parent EntitySet="OrganizationSet" /> 22. <Child EntitySet="DepartmentSet" /> 23. </ContainmentSet> 24. <ContainmentSet Name="DeptHasDeptSet" Containment="DeptHasDeptType"> 25. <Parent EntitySet="DepartmentSet" /> 26. <Child EntitySet="DepartmentSet" /> 27. </ContainmentSet>
Lines 1 – 6 describe creation of EntityTypes "Organization" and "Department". Lines 8 – 16 define ContainmentTypes "OrgHasDeptType" and "DeptHasDeptType" Lines 17 to 19 describe creation of EntitySet "OrganizationSet" and "DepartmentSet". The <ContainmentSet> element on line 20 defines ContainmentSet named "OrgHasDeptSet" of type "OrgHasDeptType" defined on line 8 above. The two EntitySets corresponding to the parent and child EntityTypes for ContainmentType are specified on line 21 and 22. Lines 25 – 28 describe another ContainmentSet "DeptHasDeptSet" over the same EntitySets but different ContainmentType.
Abstract Syntax
The abstract syntax for describing ContainmentSet is shown below:
ContainmentSet ::= CONTAINMENTSET name TYPE containmentTypeName { Parent Child } Parent ::= PARENT entitySetName Child ::= CHILD entitySetName
Entity Containers
All EDM types are defined in the scope of a namespace, created using the Schema construct. Similarly all EDM instances are contained in the EntitySet and RelationshipSets defined in the scope of an EntityContainer instance. The EntityContainer instance is created using the EntityContainer construct. It contains description of EntitySets and RelationshipSets that may use types defined in one or more namespaces. A RelationshipSet can only include EntitySets residing in its own EntityContainer.
The following SDL example shows the creation of an EntityContainer instance.
Example 18
1. <Schema Namespace="MyCompany.EntityTypes"> 2. <EntityType Name="Order" Key="OrderId"> 3. <Property Name="OrderId" Type="String"/> 4. <!--Other Properties--> 5. </EntityType> 6. <EntityType Name="Customer" Key="CustomerId"> 7. <Property Name="CustomerId" Type="String"/> 8. <!--Other Properties--> 9. </EntityType> 10. </Schema> 11. <Schema Namespace="MyCompany.RelationshipTypes"> 12. <Using Namespace="MyCompany.EntityTypes" Alias="basicTypes"/> 13. 14. <Association Name="CustomerOrder"> 15. <End Type="basicTypes.Customer" Multiplicity="1" /> 16. <End Type="basicTypes.Order" Multiplicity="*" /> 17. </Association> 18. </Schema> 19. <EntityContainer name="ContainerOne"> 20. <Using Namespace="MyCompany.EntityTypes" Alias="basicTypes"/> 21. <Using Namespace="MyCompany.RelationshipTypes" Alias="relnTypes"/> 22. 23. <EntitySet Name="CustomerSet" EntityType="basicTypes.Customer"/> 24. <EntitySet Name="OrderSet" EntityType="basicTypes.Order"/> 25. 26. <AssociationSet Name="CustOrdSet" Association="relnTypes.CustomerOrder"> 27. <End EntitySet="CustomerSet" Role="Orders"/> 28. <End EntitySet="OrderSet" Role="OrderedBy"/> 29. </AssociaitonSet > 30. </EntityContainer>
Abstract Syntax
The abstract syntax for describing EntityContainer is shown below:
ENTITYCONTAINER ::= ENTITYCONTAINER CONTAINERNAME [USING NAMESPACE [ALIAS ALIASNAME] ]* { (EntitySet | AssociationSet | ContainmentSet) * }
EDM Primitive Types
Primitive types are the atomic built-in types provided by the system. The EDM uses an abstract type system to define its primitive types such as Integer, String, Boolean, etc. EDM suggests the default mapping from these types to the corresponding primitive types in other canonical type systems like CLR, SQL and XSD which can host or instantiate EDM instances. EDM does not attempt to specify operational or conversion semantics on the abstract simple types. The concrete instances of these types will exhibit the semantics imposed by the hosting type system.
The data types described in this section are based on well known abstract concepts like integer and float. In order to support interoperability and optimal representation across multiple type systems these types support constraining facets which allow fine tuning of these types. This section describes the complete list of EDM primitive types.
Primitive Types
Binary
The binary data type is used to represent fixed or variable length binary data.
Facets
The EDM simple type facets applicable for this type are fixedLength and maxLength. These are a set of mutually exclusive facets where exactly one of them has to be specified for each declaration of this type.
fixedLength
The fixedLength facet is a positive integer with value ranging from 1 to 2^31. The size of an instance of a binary data type is always equal to value of the specified length.
maxLength
The maxLength facet is a positive integer with value ranging from 1 to 2^31. The maximum size of the declared binary data type value is specified by the value of the maxLength facet.
Boolean
The boolean data type is used to represent the mathematical concept of binary valued logic. There are no applicable facets for this type.
DateTime
The DateTime type represents date and time with values ranging from 12:00:00 midnight, January 1, 0001 A.D. through 11:59:59 P.M, December 1999 A.D. The maximum granularity of time is in milliseconds.
Facets
The DateTime type has two optional facets, one for specifying the time granularity and the other for associating TimeZone information.
preserveSeconds
The preserveSeconds facet is a boolean with a default value of true. The DateTime value preserves the seconds and milliseconds component of the specified time if preserveSeconds is true else it ignores it.
dateTimeKind
The DateTime value can be expressed using the Coordinated Universal Time (UTC) standard, the local time zone or it could be time zone agnostic. The dateTimeKind facet can be used to specify the desired time zone characteristic. It is an EDM enumerator type with values UTC, Local and Unspecified where Unspecified is the default.
Decimal
The Decimal type represents numeric values with fixed precision and scale. The required precision and scale can be specified using its optional precision and scale facets. This type can describe a numeric value ranging from negative 10^38 + 1 to positive 10^38 -1.
Facets
precision
This is a positive integer that specifies the maximum number of decimal digits that an instance of the decimal type can have, both to the left and to the right of the decimal point. The precision value can range from 1 through 38. The default precision is 18.
scale
This is a positive integer that specifies the maximum number of decimal digits to the right of the decimal point that an instance of this type can have. The scale value can range from 0 through the specified precision value. The default scale is 0.
Float
The float type represents a floating point number with 7 digits precision that can represent values with approximate range of ± 1.18e -38 through ± 3.40e +38.
Double
The double type represents a floating point number with 15 digits precision that can represent values with approximate range of ± 2.23e -308 through ± 1.79e +308.
Guid
This Guid type represents a 16 byte (128 bit) unique identifier value.
SByte
The sbyte type represents a signed 8 bit integer value
Int16
The int16 type represents a signed 16 bit integer value
Int32
The int32 type represents a signed 32 bit integer value
Int64
The int64 type represents a signed 64 bit integer value
Byte
The byte type represents an unsigned 8 bit integer value
UInt16
The uint16 type represents an unsigned 16 bit integer value
UInt32
The uint32 type represents an unsigned 32 bit integer value
UInt64
The uint64 type represents an unsigned 64 bit integer value
String
The string type represents fixed or variable length character data. The EDM simple type facets applicable to string type are described below.
Facets
The EDM simple type facets applicable for this type are unicode, collation, length and maxLength. The length and maxLength facets are mutually exclusive where exactly one of them has to be specified. The other facets Unicode and collation are optional.
unicode
The unicode facet is a boolean value. This value when set to true dictates the string type instance stores unicode characters else it's standard ASCII encoding. The default value for this facet is true.
Note: The string data type does not support the kind of unicode to be specified, and leaves it to the concrete type system hosting EDM to choose the appropriate flavor of Unicode.
fixedLength
The fixedLength facet specifies the length of an instance of the string type. For unicode equal to true the length can range from 1 to 2^30 otherwise 1 to 2^31.
maxLength
The maxLength facet specifies the maximum length an instance of the string type. For unicode equal to true the maxlength can range from 1 to 2^30 otherwise 1 to 2^31.
collation
The collation facet is a string value that specifies the collating sequence (or sorting sequence) to be used for performing comparison and ordering operations over string values.
Money
The money type represents monetary data which is a numeric value with the specified precision and a fixed scale of 4. The precision facet can be used to specify the desired precision value. This type can describe a value from negative 2^63 through 2^63 -1 with accuracy to a ten-thousandth of a monetary unit.
Facets
precision
This is a positive integer that specifies the number of bytes used for storing the money type instance; this also dictates the precision of the money type instance. The precision value for this type can be either 4 or 8 with 8 as the default.
Xml
The xml type is a rich type unlike other EDM simple types which are atomic in nature. An instance of this type is can contain well-formed XML or valid XML data. The facets described below allow more control the kind of XML data an instance of xml type can contain.
Facets
xmlFragment [Post EDM v1.0]
The xmlFragment is a boolean which is set to true to indicate the instance of xml type can contain fragments. A value of false conveys that it is a document and cannot contain fragments. This is an optional facet with default of true.
xmlSchema [Post EDM v1.0]
The xml data is by default un-typed and is not constraint by any xml schema. The xmlSchema facet describes the xml schema element that constraints the xml data contained by an instance of this type.
This is an optional facet with a default of xsd:any.
Applicable facets
EDM defines a number of simple type facets which are used to customize a specific instance of a simple type. There are a number of facets and not all are applicable to each simple type. The table below lists the simple types and their applicable facets.
Figure 4. Simple Types and Applicable Facets (Click on the image for a larger picture)
EDM and Canonical Type Systems
In terms of simple types EDM is analogous to the SQL scalar type system or the .NET Framework's common type system (CTS). EDM uses an abstract type system to define its simple types which can be mapped to concrete canonical type systems. The table below describes the suggested mapping of EDM simple types to other type systems. The intent is to have at least one way to map EDM types to these canonical type systems such that it preserves the fidelity of the data during round tripping across these type systems.
Binary [ML ::= 1 to 8000 || L ::= 1 to 8000 || ( ML>8000 || L>8000)]
L = 1 to 8000 | Ml = 1 to 8000 | (l>8000 && l<=2^31) || (ml > 8000 && ml<=2^31) | ||
---|---|---|---|---|
SQL Server | = | Binary [L] | varBinary [ML] | varBinary(max) |
CLR | = | Byte [L] | Byte[L]? | Byte[L]? |
XSD | = | HexBinary || Base64Binary? | HexBinary || Base64Binary? | HexBinary ||Base64Binary? |
Where: L=FixedLength, ML = MaxLength ; Fixedlength and maxLength facets are mutually exclusive.
Boolean
SQL Server | = | Bit |
CLR | = | Boolean |
XSD | = | Boolean |
DateTime [Kind ::= Unspecified | UTC | Local, preserveSeconds ::= Bool]
preserveSecond | True | False | |
SQL Server | = | DateTime | SmallDateTime |
CLR | = | DateTime(Kind) | DateTime(Kind) |
XSD | = | DateTime | DateTime |
Notes:
- Sql Server is thinking about extending its DateTime type to support Kind like facet – we need to align with the extended DateTime
- CLR supports the Kind facet – with the same semantics
- XSD does not support facets for TimeZone at the type level. However, XML serialization provides mechanism to encode/decode TimeZone information.
Decimal [precision ::= positiveInteger<x, scale::= positiveInteger<y]
SQL Server | = | Decimal (Precision, Scale) |
CLR | = | Decimal |
XSD | = | Decimal(totalDigits, fractionDigits) |
Notes:
CLR does not support explicit precision and scale facets.
For precision <=28, CLR can map to System.Decimal. Alternatively if precision>28 has to be supported, then EDM Decimal can be mapped to CLR SqlDecimal.
Guid
SQL Server | = | UniqueIdentifier |
CLR | = | Guid |
XSD | = | String* |
**Note **Both SqlServer and CLR support a 16 byte GUID
Different kinds of Integer
EDM type | = | Sbyte | Byte | Int16 | UInt16 | Int32 | UInt32 | Int64 | UInt16 |
SQL Server | = | tinyInt | tinyInt | smallInt | smallInt | Int | Int | BigInt | BigInt |
CLR | = | Sbyte | Byte | Int16 | UInt16 | Int32 | UInt32 | Int64 | UInt64 |
XSD | = | Byte | UByte | Short | UShort | Int | UInt | Long | ULong |
Notes:
- For brevity in illustration, we chose to represent all integer like types under a single integer section.
- For illustration purposes for XSD types, we use UByte to represent UnsignedByte. UInt for UnsignedInt and so on.
Float and Double
EDM Type | = | Float | Double |
SQL Server | = | Real || float (24) | Double || float(53) |
CLR | = | Single | Double |
XSD | = | Float | Double |
String [maxLength ::= 1 to 2^31, length ::= 1 to 2^31, unicode::=Bool]
Unicode=false
Max L=2^31 |
L=1 | L = 1 to 8000 | ML =1 to 8000 | L > 8000 || ML > 8000 | |
SQL Server | = | char[1] | char(L) | Varchar(ML) | varchar(max) |
Unicode=true
Max L=2^30 |
L=1 | L = 1 to 4000 | ML =1 to 4000 | L > 4000 || ML > 4000 | |
SQL Server | = | char[1] | Char(L) | Varchar(ML) | varchar(max) |
CLR | = | Char | String | String | String || StringBuilder? |
XSD | = | String | String | String | String |
Where: L=FixedLength, ML = MaxLength
**Note **We need to further specify 1) the default value for maxLength and 2) Add another facet for Collation and specify default collation?
Xml
SQL Server | = | Xml |
CLR | = | XElement, XmlDocument? |
XSD | = | Xsd:any or xsd:schema? |
Money [precision = 4 || 8]
precision = 4 | Precision=8 | ||
---|---|---|---|
SQL Server | = | SmallMoney | Money |
CLR | = | Decimal | Decimal |
XSD | = | Decimal(totalDigits=19, fractionDigits=4) | Decimal(totalDigits=19, fractionDigits=4) |
EDM Future Directions
This section describes some of the concepts being considered for a future version of EDM.
Conditional Association
A standard relationship instance connects two or more entity-instances identified by the value of their key-properties. The standard relationship-types are implicitly constrained to refer to entity-type's key-properties; it does not permit relating of entity-types on arbitrary properties. The Conditional Association relationship allows two entity-types to be related on any arbitrary set of type-compatible properties. The standard association instances have to be explicitly created whereas conditional-association instances are implicit; they are a function of the specified condition and implicitly connect the entity-instances satisfying the condition.
Example 1
1.<Association Name="RecentOrders"> 2 <End Type="CustomerType" role="Customer" /> 3. <End Type="OrderType" role="Orders" /> 4. <Condition> 5. Customer.CustomerId = Orders.CustomerId 6. </Condition> 7. </Association>
The <Condition> element on line 4 describes the condition that the qualifying association-instances must satisfy.
Relationships
EDM v1.0 Relationships allows relationship between exactly two EntityTypes where the Relationship itself cannot have any properties of its own. While this works for most cases there are many cases where it'd intuitive for relationships to have properties and be able to relate to more than two EntityTypes. This section describes the proposed extension to EDM v1.0 Relationships.
Relationships with Payload
The relationship concept allows capturing of relationships between entities. The current constraint that it not has any properties of its own is very limiting that we'd like to relax and allow it to have zero or more properties. These are relationship-properties, a relationship with properties is still a relationship and can be used in all places where a standard relationship could be used. Specifically it does not mean that relationship-with-properties can be an end of another relationship, an end of a relationship is always an entity. We use the Association relationship to further describe the concept of relationship with properties.
The SDL uses the <Association> element to create this relationship, as shown below:
Example 2
1. <Association Name="OfficeHistory"> 2. <End Type="Employee" Multiplicity="*" role="Employees" /> 3. <End Type="Office" Multiplicity="1" role="Office" /> 4. <Property Name="MoveInDate" Type="DateTime" /> 5. <Property Name="MoveOutDate" Type="DateTime" /> 6. </Association>
The <Association> element in line 1 defines the OfficeHistory relationship between Employee and Office EntityType.
N-ary Relationships
Binary relationships in most cases are sufficient for capturing the relationships in the user domain-model however there are many cases where a nary relationship would better serve in describing the domain- model. A nary relationship can have more than two ends (or a degree greater than two). We use the Association relationship to further describe the concept of n-ary relationships.
Example 3
1. <Association Name="Annotations"> 2. <End Type="Document" Multiplicity="1" role="Document" /> 3. <End Type="Contacts" Multiplicity="*" role="Contact" /> 4. <End Type="Comments" Multiplicity="*" role="Comment" /> 5. </Association>
The <Association> element in line 1 defines the Annotations relationship between Document and Contact and Comment EntityType.
Relationship Inheritance
EDM supports inheritance for EntityType and ComplexTypes however there is no support for Relationship inheritance. Consider supporting inheritance where the derived-relationship could choose to add more properties, constraint the entities at the relationship ends to be of a specific type or both.
Dynamic Entity Extensibility
One of the well known mechanisms of extensibility is through the notion of inheritance. EDM supports inheritance for EntityTypes and ComplexTypes. This kind of extensibility allows creation of a new type that extends from other types, a form of static extensibility. The other form of extensibility is dynamic-extensibility which allows extra structured data to be associated with any element instance. The entity extensibility mechanisms being considered are listed below:
- Static Extensibility
- A new EntityType can inherit from any existing EntityType
- Dynamic Extensibility
- A new set of non-queryable name-value property bags to be associated with any EntityType
- A new set of queryable name-value property bags can be associated with EntityType
- A new set of queryable strongly-typed queryable properties can be associated with EntityType
- All 3 of above can be associated with an EntityType scoped to a single EntitySet
- A new set of queryable strongly-typed properties can be associated with a specific entity-instance. Optionally the properties may be non-queryable or unTyped string.
Recursive ComplexType
A property P of a ComplexType CT can be of type ComplexType CT.