none
EF - Inheritance with base and derived classes in different assemblies

    Question

  • I'm trying to set up a new DAL / BL framework based on LINQ for use in future applications. What I want to do is:
    • Assembly "Framework" contains a class "BaseEntity" with common fields such as PrimaryKey, CreatedDate, LastUpdatedDate...
    • it also contains some basic entity classes commonly used, such as "Language", containing all available Languages. These derive from BaseEntity.
    • Assembly "Application" contains application specific classes such as "Customer", they also derive from Framework.BaseEntity and add specific fields like "CustomerName".

    • This customer entity contains an association to Framework.Language to record the language of the customer.
    I first tried to implement this project using LINQ for SQL, but gave up, since it doesn't seem to be designed for cases such as this (instead it insists of having all entity classes in one assembly, otherwise you cannot use the "InheritanceMapping" attribute, and there are numerous other problems with this approach).

    Now I want to ask if this scenario is better supported in ADO.NET Entity Framework? How about the visual designers, do they support inheritance when the base class is in a different assembly?

    And a second question: LINQ to SQL does a great job at optimizing the performance of the generated SQL, such as analyzing the Expression Tree, using TOUPPER() instead of String.ToUpper() and so on. It is also possible to use DataShape / LoadWith to customize Lazy Loading behaviour, which I think is an awesome feature. Is there anything similar there for the EF?

    Thanks for any help
    Urs

    Monday, November 12, 2007 4:36 PM

Answers

  • EF supports the scenario partially. We support the scenario of Entity types in one assembly deriving from Entity types in another assembly. But we have a restriction currently that Associations can not span across assemblies.

    To refer to EntityTypes defined in a different model, you would have to use "Using" construct in CSDL. The EF designer does not support this concept. Every model you create has be self contained in the designer. If you are not using Designer and are creating CSDL file by hand, you can use this feature. You can use EdmGen tool to generate the code for the base schema and then compile this into an assembly. And then you would use EdmGen again to generate the code for the dependent CSDL schemas and compile it into a different assembly.

     

    Below I have pasted an example in which the a CSDL schema uses types and EntityContainer defined in another CSDL schema.

     

    Thanks

    Srikanth.

     

    First Schema:

    <Schema Namespace="Microsoft.CDP.Samples.Northwind" Alias="Self" xmlns:cg="http://schemas.microsoft.com/ado/2006/04/codegeneration" xmlns:edm="http://schemas.microsoft.com/ado/2006/04/edm" xmlns="http://schemas.microsoft.com/ado/2006/04/edm">
      <EntityContainer Name="Microsoft_CDP_Samples_Northwind_NorthwindContainer">
        <EntitySet Name="Products" EntityType="Self.Product"/>
      </EntityContainer>
     
      <EntityType Name="Product">
        <Key>
          <PropertyRef Name="ProductID" />
        </Key>
        <Property Name="ProductID" Type="Int32" Nullable="false"/>
        <Property Name="ProductName" Type="String" MaxLength="40"/>
        <Property Name="QuantityPerUnit" Type="String" MaxLength="20"/>
        <Property Name="UnitPrice" Type="Decimal" Precision="28" Scale="4" />
        <Property Name="UnitsInStock" Type="Int16" />
        <Property Name="UnitsOnOrder" Type="Int16" />
        <Property Name="ReorderLevel" Type="Int16" />
      </EntityType>

      <EntityType Name="Category">
        <Key>
          <PropertyRef Name="CategoryID" />
        </Key>
        <Property Name="CategoryID" Type="Int32" Nullable="false" />
        <Property Name="CategoryName" Type="String" MaxLength="15" />
        <Property Name="CategoryDescription" Type="String" MaxLength="max" />
      </EntityType>
    </Schema>

     

    Second Schema:

    <?xml version="1.0" encoding="utf-8"?>
    <Schema Namespace="Microsoft.CDP.Samples.Northwind.Container" Alias="Self" xmlns:cg="http://schemas.microsoft.com/ado/2006/04/codegeneration" xmlns:edm="http://schemas.microsoft.com/ado/2006/04/edm" xmlns="http://schemas.microsoft.com/ado/2006/04/edm">
      <Using Namespace="Microsoft.CDP.Samples.Northwind" Alias="Types" />
      <EntityContainer Name="Microsoft_CDP_Samples_Northwind_NorthwindContainer_Using" Extends="Microsoft_CDP_Samples_Northwind_NorthwindContainer">
        <!-- EntitySet definitions -->
        <EntitySet Name="Categories" EntityType="Types.Category" />
      </EntityContainer>
    </Schema>

     

    Monday, November 12, 2007 7:57 PM

All replies

  • EF supports the scenario partially. We support the scenario of Entity types in one assembly deriving from Entity types in another assembly. But we have a restriction currently that Associations can not span across assemblies.

    To refer to EntityTypes defined in a different model, you would have to use "Using" construct in CSDL. The EF designer does not support this concept. Every model you create has be self contained in the designer. If you are not using Designer and are creating CSDL file by hand, you can use this feature. You can use EdmGen tool to generate the code for the base schema and then compile this into an assembly. And then you would use EdmGen again to generate the code for the dependent CSDL schemas and compile it into a different assembly.

     

    Below I have pasted an example in which the a CSDL schema uses types and EntityContainer defined in another CSDL schema.

     

    Thanks

    Srikanth.

     

    First Schema:

    <Schema Namespace="Microsoft.CDP.Samples.Northwind" Alias="Self" xmlns:cg="http://schemas.microsoft.com/ado/2006/04/codegeneration" xmlns:edm="http://schemas.microsoft.com/ado/2006/04/edm" xmlns="http://schemas.microsoft.com/ado/2006/04/edm">
      <EntityContainer Name="Microsoft_CDP_Samples_Northwind_NorthwindContainer">
        <EntitySet Name="Products" EntityType="Self.Product"/>
      </EntityContainer>
     
      <EntityType Name="Product">
        <Key>
          <PropertyRef Name="ProductID" />
        </Key>
        <Property Name="ProductID" Type="Int32" Nullable="false"/>
        <Property Name="ProductName" Type="String" MaxLength="40"/>
        <Property Name="QuantityPerUnit" Type="String" MaxLength="20"/>
        <Property Name="UnitPrice" Type="Decimal" Precision="28" Scale="4" />
        <Property Name="UnitsInStock" Type="Int16" />
        <Property Name="UnitsOnOrder" Type="Int16" />
        <Property Name="ReorderLevel" Type="Int16" />
      </EntityType>

      <EntityType Name="Category">
        <Key>
          <PropertyRef Name="CategoryID" />
        </Key>
        <Property Name="CategoryID" Type="Int32" Nullable="false" />
        <Property Name="CategoryName" Type="String" MaxLength="15" />
        <Property Name="CategoryDescription" Type="String" MaxLength="max" />
      </EntityType>
    </Schema>

     

    Second Schema:

    <?xml version="1.0" encoding="utf-8"?>
    <Schema Namespace="Microsoft.CDP.Samples.Northwind.Container" Alias="Self" xmlns:cg="http://schemas.microsoft.com/ado/2006/04/codegeneration" xmlns:edm="http://schemas.microsoft.com/ado/2006/04/edm" xmlns="http://schemas.microsoft.com/ado/2006/04/edm">
      <Using Namespace="Microsoft.CDP.Samples.Northwind" Alias="Types" />
      <EntityContainer Name="Microsoft_CDP_Samples_Northwind_NorthwindContainer_Using" Extends="Microsoft_CDP_Samples_Northwind_NorthwindContainer">
        <!-- EntitySet definitions -->
        <EntitySet Name="Categories" EntityType="Types.Category" />
      </EntityContainer>
    </Schema>

     

    Monday, November 12, 2007 7:57 PM
  • With regard to your question about DataShape/LoadWith, the EF supports this concept (we call it span or eager loading) using a method called Include which can specify additional related entities to be retrieved along with the primary entities specified in a query.

     

    Certainly the EF has spent significant time optimizing the generated SQL as well, and in beta 3 you will see even better results from the EF than in beta 2.

     

    - Danny

     

    Tuesday, November 13, 2007 12:39 AM
  • Hi,

    I'm also trying to have a BaseEntity class with common properties like ID, creationDate, creationUser, modificationDate and modificationUser. I want to use the Entity Framework, but I don't know how to do it.

    I've completed the database creation and I've created a new Entity Model based on it. I've seen that for Linq to SQL, it is possible to specify a BaseEntity, but only with the line command tool. How do we do with the Entity Framework ? Do I have to manually create a BaseEntity class and inherite all the classes in the generated .cs file from it ? Is it working so ?

    I've a database containing about 15 tables and the generated source file is quite big already. What is the correct way to proceed? Should we create many models with each one representing a smaller part of the database? I guess we could do it if one part of the DB is separated from the other part, but what happens to a table mapped on two different models?


    dvarrin
    Wednesday, April 15, 2009 7:56 AM
  • Hi *,

    you may create objects completely from scratch - check http://blog.vyvojar.cz/jirka/archive/2008/10/12/how-to-map-your-custom-objects-in-entity-framework.aspx and http://blog.vyvojar.cz/jirka/archive/2008/10/13/how-to-use-custom-objects-with-associations-in-entity-framework.aspx. But it's a lot of work. The pure POCO is planned for next version.

    And I think the best balance between work and result will be create some base interface (because by default every objects derives from EntityObject), that every entity will implement (generated code is using partial classes, hence it's not a problem).
    Jiri {x2} Cincura
    Sunday, April 19, 2009 2:16 PM
  • ... But we have a restriction currently that Associations can not span across assemblies.


    This is turning into a major headache for me given my current application design. Is this something that will change in a future EF release?
    Monday, April 20, 2009 4:28 PM
  • ... But we have a restriction currently that Associations can not span across assemblies.


    This is turning into a major headache for me given my current application design. Is this something that will change in a future EF release?

    I'd like to know this, too... will this be possible with EF 4?
    Wednesday, October 07, 2009 10:52 AM
  • I have done quite a lot of work on this particular issue:  how to implement associations that span across multiple databases and the related problem (it turns out)  of associations that are defined by CLR Interfaces rather than by Classes.  I am currently working on a real client application that involves heavy use of this pattern.  You might like to read these blog entities that I have written about it, which include the various workarounds (of varying degrees of elegance!) that I came up with:

    http://blog.nakedobjects.net/?p=60
    http://blog.nakedobjects.net/?p=101

    The second one also includes a link to a video about this. This is using our own technology (Naked Entities), but the same principles could be used with raw EF.  If this is of interest to you, I'd be glad to give you a few pointers on how we did it.

    Richard
    Wednesday, October 07, 2009 11:36 AM
  • Thank you for your reply; I had a quick look at your solution. I'm trying to get this to work with POCO classes, so I don't really want something like the additional ItemAssociation property. Maybe this could be implemented by using PostSharp to inject this additional property or something...

    My original problem occured when I tried to load the metadata using MetadataWorkspace.LoadFromAssembly(), causing this circular dependency problem (A is associated with B, loading B's assembly gives an exception that it needs A and vice versa). So, what I would like to have is something like MetadataWorkspace.RegisterAssembly(A) etc., finally loading everything with MetadataWorkspace.LoadFromRegisteredAssemblies().
    Wednesday, October 07, 2009 3:22 PM