MagicalArmchair
MagicalArmchair

Reputation: 911

Entity Framework, Link tables and mapping multiple tables to a single entity

I have an Entity called "Product", this entity, through table mapping, merges 6 tables that have a 1 to 1..0 relationship with "Products". This all works wonderfully. There is another property I want to add to "Products", which is sBBR_rate, this value is not in a table that has a direct 1 to 1..0 relationship, it is related through a link table as below:

SQL server diagram

When I import the two tables into the EDM, I can't see a way in the "Mapping Details" of "Product" to reference the sBBR_rate. I can reference RatesLink and link that to the "Products" primary key, however, I cannot reference the BBR table.

EDM

The methods I can think of to work "around" this is are as follows:

Is there a better way I can do this that doesn't feel so much like a fudge? Perhaps by directly editing the XML of the Mapping or Conceptual layers of the EDM?

Thanks for your input.

Upvotes: 1

Views: 2355

Answers (3)

MagicalArmchair
MagicalArmchair

Reputation: 911

I ended up creating a view and then linking this view in the EDM, this worked a treat.

Upvotes: 1

Crab Bucket
Crab Bucket

Reputation: 6277

The model we are using is to extend entities by using partial classes which we've found useful so we can get additional properties in the autogenerated classes (we are using a POCO T4 template to autogen but I believe this would work just as well with the default entity object generation).

So we would have

//.. this one is from the T4 template
public partial class Product
{
    //.. all the autogenerated methods
}

and in a separate file that isn't autogened

//.. now in a separate file created by me
public partial class Product
{
   //.. my custom properties and methods to make the entities more usable
   public string BBRRate
   {
     get {return this.RatesLink.BBR.sBBR_rate; } 
   }
}

This means that I can just do

myProduct.BBRRte

I know there are other ways to do this by amending the edmx file but this one we found easy to implement. You just need to watch performance because you are potentially loading extra data. Also we did this with LazyLoading turned on but with more work you wouldn't have to

We also experimented with hooking into the ObjectMaterialized event in the ObjectContext class to preload some of these properties. Using a custom interface i.e. IMaterialisable we could check if the object was of that type then call a method (Materialise) to prepopulate some of the properties. This seems like a good idea but we didn't widely use it - it was easy to load up too much stuff. If you do the load on the properties in the partial classes then it becomes more efficient. Just my experience.

Anyway - as always an interesting question and good luck again with your dev.

EDIT

There is a rule that everything in the store layer must be represented some way in your conceptual layer. Therefore removing the tables from the conceptual layer but bring through some of the properties I don't think will work in it's gross form. Therefore I can think of two further options

  1. Create a View on the database and bring that in as you have already mentioned. TBH this is what I would do.
  2. Use the DefiningQuery element directly in your xml (the store layer) and map the query through to a custom entity of your exact design. Julie Lerman describes this as the ultimate escape hatch for Entity Framework.

Remember though - if you manual amend the XML in point 2 then you lose the ability to automatically update the module through the IDE

Upvotes: 2

Steve Wilkes
Steve Wilkes

Reputation: 7135

Because the multiplicities on the Product -> RatesLink and RatesLink -> BBR relationships are 0 to 1, you should be able to access the sBBR_rate from a Product instance like this:

myProductInstance.RatesLink.BBR.sBBR_rate

I can see on the EDM screenshot that RatesLink has a Product and BBR property, which would indicate this should be available - is it?

On a side note, if it makes sense for the sBBR_rate property to commonly be accessed directly from Product, you might want to follow the law of demeter and create a property on Product which returns it directly.

Upvotes: 2

Related Questions