How to: Customize an Entity Data Model to Work with Custom Objects (Entity Framework)

If you want to use custom data classes with an Entity Data Model (EDM), the entity types and properties defined in the conceptual schema definition language (CSDL) file must match the custom data classes. The Entity Framework tools generate a set of mapping files in which the entity types and entity sets in the CSDL file match the tables in the database. The process to update these mapping files for custom data classes is as follows:

  1. Update the CSDL file to match the custom data classes.

  2. Update the mapping in the mapping specification language (MSL) file.

  3. Update the store schema definition language (SSDL) file, if necessary.

  4. Validate the updated mapping files.

  5. Stop Visual Studio from generating the object layer.

To run the example in this topic, you must have already used the EDM Generator (EdmGen.exe) utility or the Entity Data Model Wizard to generate the EDM mapping files. For more information, see How to: Use EdmGen.exe to Generate an Entity Data Model (Entity Framework). If you are using the Entity Data Model Designer in Visual Studio, you must also disable object layer generation based on the updated CSDL file. Otherwise, you will have duplicate data classes in your project.

To update the CSDL file to reflect the custom data objects

  1. Open the CSDL file in Visual Studio or in notepad.exe.

  2. Rename the EntityType and EntitySet elements to reflect the names of the custom data classes.

  3. Remove the EntityType and EntitySet elements for any entity that does not have a corresponding custom data class.

  4. Rename the Property elements of each type to match the name of the properties in the custom data class.

  5. Remove the Property elements for any properties that do not exist in the custom data class.

  6. Save the changes to the CSDL file.

To update the MSL file to map custom data objects to objects in the data source

  1. Open the MSL file in Visual Studio or in notepad.exe.

  2. Rename the EntitySetMapping element and the TypeName attribute to reflect the names of the custom classes.

  3. Remove the EntitySetMapping element for any entity that does not have a corresponding custom data class.

  4. Rename the ScalarProperty elements of each type to match the names of the properties in the custom data class.

  5. Remove the ScalarProperty element for any properties that do not exist in the custom data class.

  6. Rename the EndProperty element in the AssociationSetMapping to reflect the names of the custom classes.

  7. Rename the ScalarProperty elements in each AssociationSetMapping to match the names of the properties in the custom data class.

    Note

    Do not change any of the ColumnName properties.

  8. Remove the AssociationSetMapping element for associations between any entities that do not exist in the custom data classes.

  9. Save the changes to the MSL file.

To update the SSDL file to remove entities that do not exist in custom data classes

  1. Open the SSDL file in Visual Studio or in notepad.exe.

  2. Remove the EntityType elements for any entities that are not mapped to custom data classes.

  3. Remove the ScalarProperty elements for any properties that are not mapped to properties of the custom data classes.

  4. Save the changes to the SSDL file.

To validate the updated mapping files

  1. Run the EdmGen.exe utility in the directory that contains the mapping files. Use the following command:

    %windir%\Microsoft.NET\Framework\v3.5\edmgen.exe /mode:ValidateArtifacts  
    /inssdl:.\YourModel.ssdl /inmsl:.\YourModel.msl /incsdl:.\YourModel.csdl 
    

    Note

    Remove line breaks and replace YourModel with the name used for your mapping files.

  2. Review the output and repair any validation errors.

To regenerate, save, and remove autogenerated object code

  1. In the Solution Explorer in Visual Studio, right-click the CSDL ** file and select Run Custom Tool.

    This regenerates the object layer based on the modified CSDL file.

  2. Expand the CSDL file node, open the designer file, and save the file as a different file name.

    This saves the autogenerated object layer file. Code from this file is used in the topic How to: Use Object Services with Custom Objects (Entity Framework).

  3. Exclude the designer file from the project.

  4. Select the CSDL file and clear the Custom Tool value in the Properties window.

    This will stop the object layer file from being regenerated. To generate this file in the future, type EntityModelCodeGenerator for Custom Tool in the Properties window and repeat step 1.

Example

The following CSDL file has been customized to support the Orders and LineItem custom data classes.

<Schema Namespace="Microsoft.Samples.Entity" Alias="Self" xmlns="https://schemas.microsoft.com/ado/2006/04/edm">
  <EntityContainer Name="SalesOrdersEntities">
    <EntitySet Name="LineItemSet" EntityType="Microsoft.Samples.Entity.LineItem" />
    <EntitySet Name="OrderSet" EntityType="Microsoft.Samples.Entity.Order" />
    <AssociationSet Name="LineItem_Order_OrderIdSet" Association="Microsoft.Samples.Entity.LineItem_Order_OrderId">
      <End Role="Order" EntitySet="OrderSet" />
      <End Role="LineItems" EntitySet="LineItemSet" />
    </AssociationSet>
  </EntityContainer>
  <EntityType Name="LineItem">
    <Key>
      <PropertyRef Name="OrderId" />
      <PropertyRef Name="LineItemId" />
    </Key>
    <Property Name="OrderId" Type="Int32" Nullable="false" />
    <Property Name="LineItemId" Type="Int32" Nullable="false" />
    <Property Name="TrackingNumber" Type="String" MaxLength="25" Unicode="true" FixedLength="false" />
    <Property Name="Quantity" Type="Int16" Nullable="false" />
    <Property Name="Product" Type="Int32" Nullable="false" />
    <Property Name="Special" Type="Int32" Nullable="false" />
    <Property Name="Price" Type="Decimal" Nullable="false" Precision="19" Scale="4" />
    <Property Name="Discount" Type="Decimal" Nullable="false" Precision="19" Scale="4" />
    <Property Name="RowGuid" Type="Guid" Nullable="false" />
    <Property Name="ModifiedDate" Type="DateTime" Nullable="false" />
    <NavigationProperty Name="Order" Relationship="Microsoft.Samples.Entity.LineItem_Order_OrderId" 
                        FromRole="LineItems" ToRole="Order" />
  </EntityType>
  <EntityType Name="Order">
    <Key>
      <PropertyRef Name="OrderId" />
    </Key>
    <Property Name="OrderId" Type="Int32" Nullable="false" />
    <Property Name="Revision" Type="Byte" Nullable="false" />
    <Property Name="OrderDate" Type="DateTime" Nullable="false" />
    <Property Name="DueDate" Type="DateTime" Nullable="false" />
    <Property Name="ShipDate" Type="DateTime" />
    <Property Name="Status" Type="Byte" Nullable="false" />
    <Property Name="OnlineOrder" Type="Boolean" Nullable="false" />
    <Property Name="Customer" Type="Int32" Nullable="false" />
    <Property Name="Contact" Type="Int32" Nullable="false" />
    <Property Name="BillToAddress" Type="Int32" Nullable="false" />
    <Property Name="ShipToAddress" Type="Int32" Nullable="false" />
    <Property Name="ShipMethod" Type="Int32" Nullable="false" />
    <Property Name="SubTotal" Type="Decimal" Nullable="false" Precision="19" Scale="4" />
    <Property Name="Tax" Type="Decimal" Nullable="false" Precision="19" Scale="4" />
    <Property Name="Freight" Type="Decimal" Nullable="false" Precision="19" Scale="4" />
    <Property Name="RowGuid" Type="Guid" Nullable="false" />
    <Property Name="ModifiedDate" Type="DateTime" Nullable="false" />
    <Property Name="ExtendedInfo" Type="Self.OrderInfo" Nullable="false" />
    <NavigationProperty Name="LineItems" Relationship="Microsoft.Samples.Entity.LineItem_Order_OrderId" 
                        FromRole="Order" ToRole="LineItems" />
  </EntityType>
  <ComplexType Name="OrderInfo">
    <Property Name="OrderNumber" Type="String" Nullable="false" MaxLength="25" />
    <Property Name="PurchaseOrder" Type="String" MaxLength="25" />
    <Property Name="AccountNumber" Type="String" MaxLength="15" />
    <Property Name="Comment" Type="String" MaxLength="128" />
  </ComplexType>
  <Association Name="LineItem_Order_OrderId">
    <End Role="Order" Type="Microsoft.Samples.Entity.Order" Multiplicity="1">
      <OnDelete Action="Cascade" />
    </End>
    <End Role="LineItems" Type="Microsoft.Samples.Entity.LineItem" Multiplicity="*" />
    <ReferentialConstraint>
      <Principal Role="Order">
        <PropertyRef Name="OrderId" />
      </Principal>
      <Dependent Role="LineItems">
        <PropertyRef Name="OrderId" />
      </Dependent>
    </ReferentialConstraint>
  </Association>
</Schema>

The following MSL file has been customized to map the Orders and LineItem custom data classes to the SalesOrderHeader and SalesOrderDetail tables in the AdventureWorks database.

<Mapping Space="C-S" xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS">
  <EntityContainerMapping StorageEntityContainer="MicrosoftSamplesEntityStoreContainer" 
                          CdmEntityContainer="SalesOrdersEntities">
    <EntitySetMapping Name="LineItemSet">
      <EntityTypeMapping TypeName="IsTypeOf(Microsoft.Samples.Entity.LineItem)">
        <MappingFragment StoreEntitySet="SalesOrderDetail">
          <ScalarProperty Name="OrderId" ColumnName="SalesOrderID" />
          <ScalarProperty Name="LineItemId" ColumnName="SalesOrderDetailID" />
          <ScalarProperty Name="TrackingNumber" ColumnName="CarrierTrackingNumber" />
          <ScalarProperty Name="Quantity" ColumnName="OrderQty" />
          <ScalarProperty Name="Product" ColumnName="ProductID" />
          <ScalarProperty Name="Special" ColumnName="SpecialOfferID" />
          <ScalarProperty Name="Price" ColumnName="UnitPrice" />
          <ScalarProperty Name="Discount" ColumnName="UnitPriceDiscount" />
          <ScalarProperty Name="RowGuid" ColumnName="rowguid" />
          <ScalarProperty Name="ModifiedDate" ColumnName="ModifiedDate" />
        </MappingFragment>
      </EntityTypeMapping>
    </EntitySetMapping>
    <EntitySetMapping Name="OrderSet">
      <EntityTypeMapping TypeName="IsTypeOf(Microsoft.Samples.Entity.Order)">
        <MappingFragment StoreEntitySet="SalesOrderHeader">
          <ScalarProperty Name="OrderId" ColumnName="SalesOrderID" />
          <ScalarProperty Name="Revision" ColumnName="RevisionNumber" />
          <ScalarProperty Name="OrderDate" ColumnName="OrderDate" />
          <ScalarProperty Name="DueDate" ColumnName="DueDate" />
          <ScalarProperty Name="ShipDate" ColumnName="ShipDate" />
          <ScalarProperty Name="Status" ColumnName="Status" />
          <ScalarProperty Name="OnlineOrder" ColumnName="OnlineOrderFlag" />
          <ScalarProperty Name="Customer" ColumnName="CustomerID" />
          <ScalarProperty Name="Contact" ColumnName="ContactID" />
          <ScalarProperty Name="BillToAddress" ColumnName="BillToAddressID" />
          <ScalarProperty Name="ShipToAddress" ColumnName="ShipToAddressID" />
          <ScalarProperty Name="ShipMethod" ColumnName="ShipMethodID" />
          <ScalarProperty Name="SubTotal" ColumnName="SubTotal" />
          <ScalarProperty Name="Tax" ColumnName="TaxAmt" />
          <ScalarProperty Name="Freight" ColumnName="Freight" />
          <ScalarProperty Name="RowGuid" ColumnName="rowguid" />
          <ScalarProperty Name="ModifiedDate" ColumnName="ModifiedDate" />
          <ComplexProperty Name ="ExtendedInfo" TypeName ="Microsoft.Samples.Entity.OrderInfo">
            <ScalarProperty Name="OrderNumber" ColumnName="SalesOrderNumber" />
            <ScalarProperty Name="PurchaseOrder" ColumnName="PurchaseOrderNumber" />
            <ScalarProperty Name="AccountNumber" ColumnName="AccountNumber" />
            <ScalarProperty Name="Comment" ColumnName="Comment" />
          </ComplexProperty>
        </MappingFragment>
      </EntityTypeMapping>
    </EntitySetMapping>
    <AssociationSetMapping Name="LineItem_Order_OrderIdSet" 
                           TypeName="Microsoft.Samples.Entity.LineItem_Order_OrderId" 
                           StoreEntitySet="SalesOrderDetail">
      <EndProperty Name="Order">
        <ScalarProperty Name="OrderId" ColumnName="SalesOrderID" />
      </EndProperty>
      <EndProperty Name="LineItems">
        <ScalarProperty Name="OrderId" ColumnName="SalesOrderID" />
        <ScalarProperty Name="LineItemId" ColumnName="SalesOrderDetailID" />
      </EndProperty>
    </AssociationSetMapping>
  </EntityContainerMapping>
</Mapping>

The following SSDL file has been customized to support the Orders and LineItem custom data classes using the SalesOrderHeader and SalesOrderDetail tables in the AdventureWorks database.

<Schema Namespace="Microsoft.Samples.Entity.Store" Alias="Self" Provider="System.Data.SqlClient" 
        ProviderManifestToken="2005" 
        xmlns:store="https://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" 
        xmlns="https://schemas.microsoft.com/ado/2006/04/edm/ssdl">
  <EntityContainer Name="MicrosoftSamplesEntityStoreContainer">
    <EntitySet Name="SalesOrderDetail" EntityType="Microsoft.Samples.Entity.Store.SalesOrderDetail" 
               store:Type="Tables" Schema="Sales" />
    <EntitySet Name="SalesOrderHeader" EntityType="Microsoft.Samples.Entity.Store.SalesOrderHeader" 
               store:Type="Tables" Schema="Sales" />
    <AssociationSet Name="FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID" 
                    Association="Microsoft.Samples.Entity.Store.FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID">
      <End Role="SalesOrderHeader" EntitySet="SalesOrderHeader" />
      <End Role="SalesOrderDetail" EntitySet="SalesOrderDetail" />
    </AssociationSet>
  </EntityContainer>
  <EntityType Name="SalesOrderDetail">
    <Key>
      <PropertyRef Name="SalesOrderID" />
      <PropertyRef Name="SalesOrderDetailID" />
    </Key>
    <Property Name="SalesOrderID" Type="int" Nullable="false" />
    <Property Name="SalesOrderDetailID" Type="int" Nullable="false" 
              StoreGeneratedPattern="Identity" />
    <Property Name="CarrierTrackingNumber" Type="nvarchar" MaxLength="25" />
    <Property Name="OrderQty" Type="smallint" Nullable="false" />
    <Property Name="ProductID" Type="int" Nullable="false" />
    <Property Name="SpecialOfferID" Type="int" Nullable="false" />
    <Property Name="UnitPrice" Type="money" Nullable="false" />
    <Property Name="UnitPriceDiscount" Type="money" Nullable="false" />
    <Property Name="LineTotal" Type="numeric" Nullable="false" Precision="38" Scale="6" 
              StoreGeneratedPattern="Computed" />
    <Property Name="rowguid" Type="uniqueidentifier" Nullable="false" />
    <Property Name="ModifiedDate" Type="datetime" Nullable="false" />
    <Property Name="CreationDate" Type="datetime" />
  </EntityType>
  <EntityType Name="SalesOrderHeader">
    <Key>
      <PropertyRef Name="SalesOrderID" />
    </Key>
    <Property Name="SalesOrderID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
    <Property Name="RevisionNumber" Type="tinyint" Nullable="false" />
    <Property Name="OrderDate" Type="datetime" Nullable="false" />
    <Property Name="DueDate" Type="datetime" Nullable="false" />
    <Property Name="ShipDate" Type="datetime" />
    <Property Name="Status" Type="tinyint" Nullable="false" />
    <Property Name="OnlineOrderFlag" Type="bit" Nullable="false" />
    <Property Name="SalesOrderNumber" Type="nvarchar" Nullable="false" MaxLength="25" 
              StoreGeneratedPattern="Computed" />
    <Property Name="PurchaseOrderNumber" Type="nvarchar" MaxLength="25" />
    <Property Name="AccountNumber" Type="nvarchar" MaxLength="15" />
    <Property Name="CustomerID" Type="int" Nullable="false" />
    <Property Name="ContactID" Type="int" Nullable="false" />
    <Property Name="SalesPersonID" Type="int" />
    <Property Name="TerritoryID" Type="int" />
    <Property Name="BillToAddressID" Type="int" Nullable="false" />
    <Property Name="ShipToAddressID" Type="int" Nullable="false" />
    <Property Name="ShipMethodID" Type="int" Nullable="false" />
    <Property Name="CreditCardID" Type="int" />
    <Property Name="CreditCardApprovalCode" Type="varchar" MaxLength="15" />
    <Property Name="CurrencyRateID" Type="int" />
    <Property Name="SubTotal" Type="money" Nullable="false" />
    <Property Name="TaxAmt" Type="money" Nullable="false" />
    <Property Name="Freight" Type="money" Nullable="false" />
    <Property Name="TotalDue" Type="money" Nullable="false" StoreGeneratedPattern="Computed" />
    <Property Name="Comment" Type="nvarchar" MaxLength="128" />
    <Property Name="rowguid" Type="uniqueidentifier" Nullable="false" />
    <Property Name="ModifiedDate" Type="datetime" Nullable="false" />
  </EntityType>
  <Association Name="FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID">
    <End Role="SalesOrderHeader" Type="Microsoft.Samples.Entity.Store.SalesOrderHeader" Multiplicity="1">
      <OnDelete Action="Cascade" />
    </End>
    <End Role="SalesOrderDetail" Type="Microsoft.Samples.Entity.Store.SalesOrderDetail" Multiplicity="*" />
    <ReferentialConstraint>
      <Principal Role="SalesOrderHeader">
        <PropertyRef Name="SalesOrderID" />
      </Principal>
      <Dependent Role="SalesOrderDetail">
        <PropertyRef Name="SalesOrderID" />
      </Dependent>
    </ReferentialConstraint>
  </Association>
</Schema>

See Also

Concepts

Customizing Objects (Entity Framework)

Other Resources

Schemas and Mapping Specification (Entity Framework)
Working with Custom Objects (Entity Framework Tasks)