5

I have a frustrating situation owing to this little quirk of EF. Here's a simple demo of the behavior. First the DB schema:

enter image description here

As you see, RestrictedProduct is a special case of product, which I'm intending to make a subclass of Product with some special code.

Now I import to an EF data model:

enter image description here

Oops! EF saw that RestrictedProduct had only 2 fields, both FKs, so it mapped it as a one-to-many relationship between Product and Restriction. So I go back to the database and add a Dummy field to RestrictedProduct, and now my EF model looks much better:

enter image description here

But that Dummy field is silly and pointless. Maybe I could delete it? I blow away the field from the DB table and the entity model, then refresh the model from the DB...

enter image description here

Oh, no! The Product-Restriction association is back, under a new name (RestrictedProduct1)! Plus, it won't compile:

Error 3034: Problem in mapping fragments starting at lines (x, y) :Two entities with possibly different keys are mapped to the same row. Ensure these two mapping fragments map both ends of the AssociationSet to the corresponding columns.

Is there any way to prevent this behavior, short of keeping the Dummy field on the RestrictedProduct table?

Shaul Behr
  • 36,951
  • 69
  • 249
  • 387
  • 1
    Try working the other way, create the class model and see what tables EF Code First makes in the database – Wim Jan 30 '13 at 12:09
  • @Wim - good idea! I did that, and the DB model generated was basically identical to the one I started with. But refreshing from the DB doesn't mess up the EF model! Couldn't see any obvious differences between the underlying XML of the EDMX files, but there's a lot of technical gook there, and I'm sure somewhere in there must be some secret switch. Any idea what it might be? – Shaul Behr Jan 30 '13 at 14:30
  • No can't help you with that. If you do find something let us know. – Wim Jan 30 '13 at 15:01
  • @Shaul sounds like you have quite a domain driven design here. Are you sure DB first is the right approach for you? I don't think the edmx generator is customisable to allow you to switch off the recognition of some associations. –  Feb 01 '13 at 21:01
  • @bmewsing I was under the impression that DB-first and code-first were pretty much interchangeable, inasmuch as you should get pretty much identical results from either approach. Was I mistaken? – Shaul Behr Feb 03 '13 at 07:26
  • @Shaul I think they are in general, I just mean that you seem to have a strong conceptual model so you may be better focusing on the code and let EF sort out the db schema. But you may prefer DB first, I know I like to design my schema myself. I couldn't find a way to customise the generator but it is just an additive generator, ie it won't remove any of the changes you make to the model so you could just delete the undesirable association each time you "update model from database", but I agree it is irritating. –  Feb 03 '13 at 08:32

2 Answers2

2

I just came across the same issue, and as an alternative to putting the dummy field in your RestrictedProduct table to force the creation of an entity you can also make your RestrictedProduct.RestrictionId field nullable and EF will then generate an entity for it. You can then modify it to use inheritance and any subsequent "Update model from database" will not cause undesired nav properties. Not really a nice solution but a work around.

  • As you say, not ideal, because it really is conceptually not nullable, but no worse than the dummy field, so +1 anyway... – Shaul Behr Mar 19 '13 at 07:47
1

Let's walk slowly into your problem.

1st thing you need to decide is if the restricted product is really a special case of product or is it a possible extension to each product.

From your original DB Scheme it seems that any product may have a relation to a single restriction however a single restriction can be shared among many products.. so this is a simple 1 to many situation which means that restricted product is NOT a special case of product! Restriction is an independent entity which has nothing to do with product in a specific way.

Therefore EF is correct in the 1st importation of your scheme: 1. a product can have 0 or 1 restrictions. 2. a restriction is another entity which can be related to many products.

I do not see your problem.

Félix LD
  • 372
  • 1
  • 5
  • 19
G.Y
  • 6,042
  • 2
  • 37
  • 54
  • Thanks for your answer! I understand why you ask that question, but I'm going to deflect it. The case I've given is not my actual schema, but it would take too long to explain the business rules in my system, and it's beside the point. Let's take it as given that `RestrictedProduct` really is a special kind of `Product` that has different business rules, and the class code will override some virtual methods in `Product`. – Shaul Behr Jan 31 '13 at 10:34
  • To add to my previous comment: imagine also that you have other `Product` subclasses which also have different business rules. It doesn't work for me that the ones that only have one additional field (like `RestrictionID`) will get generated as relationships, while those with more than one field will merit their own class. – Shaul Behr Jan 31 '13 at 10:37
  • In what way a RestrictedProduct is a sub-class of a product? what does it bring with it? the problem you expiriencing is related to object oriented design - not to EF, If we go to the classic zoo example: you have "Animal" class and a "Visitor" class and you trying to say that since some animals can be visited they need to be sub-classed.. That is wrong! you can have a property IsBeingVisited on your animal class - that would be the correct approach. you need to distniguish when somthing should be sub-classed and when somthing is just another property, as ground rule ask if it adds somthing. – G.Y Jan 31 '13 at 15:22
  • I've been through that process. I understand the difference between a subclass and a property. Please, just take it as a given that there really is a genuine business need to have a subclass. – Shaul Behr Jan 31 '13 at 16:01
  • alright, in that case you need to set restriction to product as it is your base class of RestrictedProduct and eliminate the relation between RestrictedProduct <-> Restriction... But I don't think it going to be intuative anymore :) – G.Y Feb 01 '13 at 23:30