none
Using Different Entities Declared in Different Assemblies for a DataContext RRS feed

  • Question

  • Hello

    I'm writing you because I'm in a hurry after wasting lot of time trying to solve the problem I'm going to describe in the following lines.

    The point is I'm testing a proof of concept scenario using IPOCOs (self tracking entities) where I use two edmx files with the following entities 

    + SalesModule.edmx Entities:

    - Order: It has a navigation property to OrderDetail (Association: OrderOrderDetail (1,*))

    - OrderDetail: It has a navigation property to Order   (Association: OrderOrderDetail (1,*))  and another one to Product (Association: OrderDetailProduct (*, 0..1))

    - Product: No navigation properties

    + ProductModule.edmx : Product


    Each edmx is within an assembly together with the repository and the unitOfwork which uses it: Data.SalesModule.csproj and Data.ProductModule.csproj respectively.
    Furthermore its respective entities are in two different assemblies Domain.SalesModule.csproj and Domain.ProductModule.csproj


    The point is the Product entity is shared between the two edmx so I modified the T4 Sales model file to do not create the Product.cs file, instead of it the context has an import for using Product class within the ProductModule assembly in order to reuse code. So Data.SalesModule has references to Domain.SalesModule and to Domain.ProductModule since that it needs those for compiling the DataContext.


    The problem is when I try to add a new Product entity using the SalesModule datacontext I obtain the following error:

    "Server Error in '/' Application.Metadata information for the relationship 'Customer' could not be retrieved. If mapping attributes are used, make sure that the EdmRelationshipAttribute for the relationship has been defined in the assembly. When using convention-based mapping, metadata information for relationships between detached entities cannot be determined.Parameter name: relationshipNameDescription: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
    Exception Details: System.ArgumentException: Metadata information for the relationship 'OrderDetailProduct' could not be retrieved. If mapping attributes are used, make sure that the EdmRelationshipAttribute for the relationship has been defined in the assembly. When using convention-based mapping, metadata information for relationships between detached entities cannot be determined.Parameter name: relationshipName"


    I've made an attempt using the same namespace for the two Domain modules. To be sure the problem was not that the entities used within the data context should have the same namespace, however but it didn't worked.


    Nevertheless if I create the Product entity class within the Domain.SalesModule instead of creating it in the Domain.ProductsModule it works without problems.

    I also have taken a look to this post 


    I'm working on a big scenario and I need to reuse the entities code. Is there any way of having the entities of a context declared in two or more different assemblies? I also have tried a solution provided by Zeeshand Irani for a not similar but related problem http://weblogs.asp.net/zeeshanhirani/archive/2010/03/23/placing-model-in-separate-assembly.aspx?CommentPosted=true#commentmessage which consist on loading the Domain.ProductModule before you create the SalesModule DataContext. However it didnt' work. 

    I also have revised this popular post, eventhought I haven't found there any explanation to my problem.

    http://blogs.msdn.com/b/adonet/archive/2008/11/25/working-with-large-models-in-entity-framework-part-2.aspx

    Any idea? 

    Best Regards!

    Wednesday, June 29, 2011 10:54 PM

All replies

  • Hi,

    You can't split your database schema into different models and work with the entities across contexts even if the same entity is defined in both models. It's not possible without having the whole relationship structure to your Product both places, and then you would probably have the complete model both places anyway.

    Explaining why is a bit to complicated to do without having code examples.

    I suggest that you merge these two together and only use one even if it doesn't suit your needs.

    If you still want the two, I would rather suggest that you don't add Product to your SalesModel, but you extend your OrderDetail entity class (which is a partial class) with a new partial class with a navigation property that retrieves data from the ProductModel for you.

    Eg.:

    public partial class OrderDetail
    {
      private ProductModel.Product product;
      public ProductModel.Product Product
      {
        get
        {
          if(product == null && ProductId != null)
          {
            using(ProductModel.Context context = new ProductModel.Context())
            {
              product = context.Products.FirstOrDefault(row => row.Id == ProductId);
            }
          }
          return product;
        }
        set
        {
          if(product != value)
          {
            product = value;
            if(product != null)
              ProductId = product.Id;
            else
              ProductId = null;
          }
        }
      }
    }
    

    This will give you a link without having to use the same entity in different models.

    The drawback is that you can't save changes done in the Product while working with SalesModel entities. But this can be solved by overriding SavingChanges.

    Hope this helps a bit...

     


    --Rune
    Thursday, June 30, 2011 6:43 AM
  • Hello Rune

    BINGO!!!

    Your solution it's enough for me and with a very simple implementation,

    Many mamy thanks!! :)

    Thursday, June 30, 2011 7:19 AM
  • Good to hear that my solution helped you :)

     


    --Rune
    Thursday, June 30, 2011 8:20 AM
  • Sorry Rune, this morning I was so obfuscated and your solution sound me so right.

    The point is I would need also to perform LINQ to SQL queries using a Where that filter by the product entity.

    With your solution it is only possible to do it this using LINQ to Entitis when all the data are loaded from the database. :(

     

     

     


    Thursday, June 30, 2011 7:41 PM
  • Hi,

    Well, It isn't any good solution to that unfortunately :(

    The only solution I see then is that you don't use the same class in both generated models but you generate one class for each entity. And if you need to use the product entity in both ProductModel and SalesModel contexts you convert them between eachother with helper functions.

     


    --Rune
    Thursday, June 30, 2011 8:17 PM
  • Hi Rune

    The point is I'm working on two apps, a desktop app and a WP7 app. They share a lot of domain objects, nevertheless SQLCEdb for WP7 doesn't allow mapping between domain entity classes and database objects, they have to be the same isn't it? So as I can't have the same database object mapped for two different entity domain classes this solution doesn't work for me.

    Do you know if is ADO.NET team planning to do any movement to provide a solution for this scenario?


    Friday, July 1, 2011 6:27 AM
  • Hi,

    I'm not quite sure what you are saying now?

    What I meant with my suggestion above is this:

    You have your Product entity in both models (with two entity classes SalesModel.Product and ProductModel.Product). You fetch a Product record from the database using your ProductModel, this creates a ProductModel.Product object that you can use in your ProductModel.

    If you at some point want to use this entity against your SalesModel, you should do one of two things.

    1. Fetch the same entity in your SalesModel based on Id's
    2. Create a function that converts your ProductModel.Product object to a SalesModel.Product object, and work with this.

    And you can work with the ProductModel.Product entity in your ProductModel and the SalesModel.Product in your SalesModel. The problem is that you have to keep these in sync yourself.

    There may be other solutions to the problem, but since I dont' have the exact code, it's difficult to tell. If you have a reproducible example it would help to find other solutions to your problem.

    I don't think this actually is a bug, so I don't think the ADO.NET team will fix this. But if you think it is, I recommend you to report your problem using the connect site (connect.microsoft.com). Then they will look at it and judge it.


    --Rune
    Friday, July 1, 2011 7:18 AM
  • Hi,

    I'm not quite sure what you are saying now?

    What I meant with my suggestion above is this:

    You have your Product entity in both models (with two entity classes SalesModel.Product and ProductModel.Product). You fetch a Product record from the database using your ProductModel, this creates a ProductModel.Product object that you can use in your ProductModel.

    If you at some point want to use this entity against your SalesModel, you should do one of two things.

    1. Fetch the same entity in your SalesModel based on Id's

    Working in an environment with SQL Server and Entity Framework it would work without problems. And even it will be possible to perform LINQ to SQL queries with a Where that filter by the Product properties. It works because SalesModel.Product and ProductModel.Product are mapped to the same table in the database.

    However if you are going to reuse your POCO domain classes in an enviroment based on SQL CE for Windows Phone as local database stored in the isolated storage.. This approach is not feasible. Because as far as I know, I will be very happy if if I'm wrong, how Entity Framework is not available for Windows Phone 7, it is not possible to map SalesModel.Product and ProductModel.Product to the same table in the database. So if I perform a LINQ query referencing map SalesModel.Product the products I will obtain won't be the products I will  have if I reference ProductModel.Product entity. Just because they are saved in dfferent tables in the database.

    2. Create a function that converts your ProductModel.Product object to a SalesModel.Product object, and work with this.

    And you can work with the ProductModel.Product entity in your ProductModel and the SalesModel.Product in your SalesModel. The problem is that you have to keep these in sync yourself.

    It doesn't solve the problem of inability  to perform a LINQ query within my SalesModel that references the same Product data used in the ProductModel, when my scenario is a Windows Phone 7 working with local data stored on SQL CE 

    There may be other solutions to the problem, but since I dont' have the exact code, it's difficult to tell. If you have a reproducible example it would help to find other solutions to your problem.

    Sorry, to be honest my code is more complex than I explained to you. I made a simplification to explain easily my question. As it is I can't send it to you.

    I don't think this actually is a bug, so I don't think the ADO.NET team will fix this. But if you think it is, I recommend you to report your problem using the connect site (connect.microsoft.com). Then they will look at it and judge it.


    --Rune
    I agree it is not a bug. 
    Friday, July 1, 2011 8:28 AM