How to get EF6 to honor Unique Constraint (on FK) in Association/Relationship multiplicity? - entity-framework

2019 Update / TLDR; switch to Entity Framework Core (or whatever else)
While missing some "Features", EF Core properly honors Alternate Keys (aka Unique Constraints) in addition to Primary Keys and thus does a much better job of honoring Relational Algebra. YMMV otherwise; at least it supports many more SQL schemes correctly.
This support added was in the (very outdated) EF Core 1.0 release.. a bit disappointing that the original EF never had this design(ed!) flaw addressed.
This may be related to my other question - which seems to be that either:
Entity Framework is a terrible Relational Algebra mapper1 or;
(which I am hoping for) I am overlooking something with SSDL/CSDL and the EDMX model or EF mappings in general.
I have a Schema First model and the schema looks like this:
ExternalMaps
---
emap_id - PK
Melds
---
meld_id - PK
emap_id - >>UNIQUE INDEX<< over not-null column, FK to ExternalMaps.emap_id
For verification, these are scripted as the following, which should result in a multiplicity of ExternalMaps:1 <-> 0..1:Melds2.
ALTER TABLE [dbo].[Melds] WITH CHECK ADD CONSTRAINT [FK_Melds_ExternalMaps]
FOREIGN KEY([emap_id]) REFERENCES [dbo].[ExternalMaps] ([emap_id])
CREATE UNIQUE NONCLUSTERED INDEX [IX_Melds] ON [dbo].[Melds] ([emap_id] ASC)
However, when I use the EDMX designer to update from the database (SQL Server 2012), from scratch, it incorrectly creates the Association / Foreign Key relation as ExternalMap:1 <-> M:Meld.
When I try to change the multiplicity manually for the Meld (via the "Association Set" properties in the designer) side to either 1 or 0..1, I get:
Running transformation: Multiplicity is not valid in Role 'Meld' in relationship 'FK_Melds_ExternalMaps'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be *.
(As with my other question, this seems to be related to Unique Constraints not being correctly registered/honored as Candidate Keys.)
How can I get EF to honor the 1 <-> 0..1/1 multiplicity, as established by the model?
1 While I hope this is not the case, I am having no end to grief when trying to get EF to map onto a perfectly valid RA model: LINQ to SQL (L2S) does not have this problem. Since my other question was not trivially answered for such a popular ORM, I am losing faith in this tooling.
2 It is by design that the FK is not the other way: "Though shalt not have nullable foreign keys." - It is also not the case that it's a "shared" PK as this answer from 2009 suggests as a fix.
I am using EF 6.1.1, VS 2013 Ultimate, and am not going to use any "OO subtype features" - if that changes anything.
EDIT sigh:
Multiplicity is not valid because the Dependent Role properties are not the key properties? (from 2011) - is this still the case for the EF "Microsoft-endorsed Enterprise-ready" ORM in 2014 2015?
At this rate the next time someone asks why EF wasn't used I'll have a large set of reasons other than "LINQ to SQL works just fine" ..

The problem is that Entity Framework (from EF4 through EF6.1, and who knows how much longer) does not "understand" the notion of Unique Constraints and all that they imply: EF maps Code First, not Relational Algebra *sigh*
This answer for my related question provides a link to a request to add the missing functionality and sums it up:
.. The Entity Framework currently only supports basing referential constraints on primary keys and does not have a notion of a unique constraint.
This can be expanded to pretty much all realms dealing with Unique Constraints and Candidate Keys, including the multiplicity issue brought up in this question.
I would be happy if this severe limitation of EF was discussed openly and made "well known", especially when EF is touted to support Schema First and/or replace L2S. From my viewpoint, EF is centered around mapping (and supporting) only Code First as a first-class citizen. Maybe in another 4 years ..

Related

How to stop EF Core from indexing all foreign keys

As documented in questions like Entity Framework Indexing ALL foreign key columns, EF Core seems to automatically generate an index for every foreign key. This is a sound default for me (let's not get into an opinion war here...), but there are cases where it is just a waste of space and slowing down inserts and updates. How do I prevent it on a case-by-case basis?
I don't want to wholly turn it off, as it does more good than harm; I don't want to have to manually configure it for all those indices I do want. I just want to prevent it on specific FKs.
Related side question: is the fact that these index are automatically created mentioned anywhere in the EF documentation? I can't find it anywhere, which is probably why I can't find how to disable it?
Someone is bound to question why I would want to do this... so in the interest of saving time, the OPer of the linked question gave a great example in a comment:
We have a People table and an Addresses table, for example. The
People.AddressID FK was Indexed by EF but I only ever start from a
People row and search for the Addresses record; I never find an
Addresses row and then search the People.AddressID column for a
matching record.
EF Core has a configuration option to replace one of its services.
I found replacing IConventionSetBuilder to custom one would be a much cleaner approach.
https://giridharprakash.me/2020/02/12/entity-framework-core-override-conventions/
If it is really necessary to avoid the usage of some foreign keys indices - as far as I know (currently) - in .Net Core, it is necessary to remove code that will set the indices in generated migration code file.
Another approach would be to implement a custom migration generator in combination with an attribute or maybe an extension method that will avoid the index creation. You could find more information in this answer for EF6: EF6 preventing not to create Index on Foreign Key. But I'm not sure if it will work in .Net Core too. The approach seems to be bit different, here is a MS doc article that should help.
But, I strongly advise against doing this! I'm against doing this, because you have to modify generated migration files and not because of not using indices for FKs. Like you mentioned in question's comments, in real world scenarios some cases need such approach.
For other people they are not really sure if they have to avoid the usage of indices on FKs and therefor they have to modify migration files:
Before you go that way, I would suggest to implement the application with indices on FKs and would check the performance and space usage. Therefor I would produce a lot test data.
If it really results in performance and space usage issues on a test or QA stage, it's still possible to remove indices in migration files.
Because we already chat about EnsureCreated vs migrations here for completeness further information about EnsureCreated and migrations (even if you don't need it :-)):
MS doc about EnsureCreated() (It will not update your database if you have some model changes - migrations would do it)
interesting too (even if for EF7) EF7 EnsureCreated vs. Migrate Methods
Entity Framework core 2.0 (the latest version available when the question was asked) doesn't have such a mechanism, but EF Core 2.2 just might - in the form of Owned Entity Types.
Namely, since you said:
" I only ever start from a People row and search for the Addresses record; I never find an Addresses row"
Then you may want to make the Address an Owned Entity Type (and especially the variant with 'Storing owned types in separate tables', to match your choice of storing the address information in a separate Addresses table).
The docs of the feature seem to say a matching:
"Owned entities are essentially a part of the owner and cannot exist without it"
By the way, now that the feature is in EF, this may justify why EF always creates the indexes for HasMany/HasOne. It's likely because the Has* relations are meant to be used towards other entities (as opposed to 'value objects') and these, since they have their own identity, are meant to be queried independently and allow accessing other entities they relate to using navigational properties. For such a use case, it would be simply dangerous use such navigation properties without indexes (a few queries could make the database slow down hugely).
There are few caveats here though:
Turning an entity into an owned one doesn't instruct EF only about the index, but rather it instructs to map the model to database in a way that is a bit different (more on this below) but the end effect is in fact free of that extra index on People.
But chances are, this actually might be the better solution for you: this way you also say that no one should query the Address (by not allowing to create a DbSet<T> of that type), minimizing the chance of someone using it to reach the other entities with these costly indexless queries.
As to what the difference is, you'll note that if you make the Address owned by Person, EF will create a PersonId column in the Address table, which is different to your AddressId in the People table (in a sense, lack of the foreign key is a bit of a cheat: an index for querying Person from Address is there, it's just that it's the primary key index of the People table, which was there anyways). But take note that this design is actually rather good - it not only needs one column less (no AddressId in People), but it also guarantees that there's no way to make orphaned Address record that your code will never be able to access.
If you would still like to keep the AddressId column in the Addresses, then there's still one option:
Just choose a name of AddressId for the foreign key in the Addresses table and just "pretend" you don't know that it happens to have the same values as the PersonId :)
If that option isn't funny (e.g. because you can't change your database schema), then you're somewhat out of luck. But do take note that among the Current shortcomings of EF they still list "Instances of owned entity types cannot be shared by multiple owners", while some shortcomings of the previous versions are already listed as addressed. Might be worth watching that space as, it seems to me, resolving that one will probably involve introducing the ability to have your AddressId in the People, because in such a model, for the owned objects to be shared among many entities the foreign keys would need to be sitting with the owning entities to create an association to the same value for each.
in the OnModelCreating override
AFTER the call to
base.OnModelCreating(modelBuilder);
add:
var indexForRemoval = modelBuilder.Entity<You_Table_Entity>().HasIndex(x => x.Column_Index_Is_On).Metadata;
modelBuilder.Entity<You_Table_Entity>().Metadata.RemoveIndex(indexForRemoval);
'''

A few basic questions about ADO.NET Entity Framework 4

I did work on ADO.NET Entity Framework v2 about two years ago. I have faint memories.
Incidentally, I happen to be working in a very secured (for want of a euphemism) environment where a lot of links are blocked and there's not much one can do. It does get in the way of studying and working, more than a bit.
Therefore, I have to rely on this forum for a few basic questions I have to get started again. This time, I am working on Entity Framework 4. Here are my questions.
All these questions relate to the EDM generated entities, i.e. not the Code First model.
1) Is my understanding correct? I can rename any column name in the EDM designer generated model and nothing breaks.
2) Foreign keys are expressed as navigational properties in the generated entity classes. No special consideration is required to maintain foreign key relationships. I recall in version 1 of EF, you had just ID properties and the navigational IQueryable/IEnumerable/EntityCollection/RelatedEnd properties were introduced in version 2. I just need to know if I need to do anything to retain/maintain foreign key relationships and referential data integrity. I assume I don't need to. A confirmation would be nice.
3) What are all the possible ways to execute a stored procedure? I recall -- one way to use ExecuteSQL or something on the Context.Database object, another to use EntityClient API and the third was to specify stored procedure names in the InsertCommand, SelectCommand, etc. thingies in the mapping window of the EDM designer. Is this correct?
4) How do you use those SelectCommand thingies in the mapping window on an entity? Do you just supply the names of the stored procedures or user defined SQL functions?
5) How do I create an entity out of a subset of a table? Do I just create an entity from the table and then delete the columns I don't need from the designer? What happens if there are required (NOT NULL in SQL) values that are not in the subset I choose?
6) How do I create a table out of a query or join of two or more tables.
1) You can rename columns in the designer and nothing should break (if the name is valid)
2) Navigation properties point to related entities. In EF4 foreign keys were added. Foreign key properties basically expose the database way of handling relations. However, they are helpful since you don't have to load related entities just to change relationship - you can just change the key value to the id of the other entity and save your changes
3) Yes. You can either execute the procedure directly - this is for stored procedures that are not related to CUD (Create/Update/Delete) operations. You can map CUD operations to stored procedure as opposed to having EF execute SQL statements it came up with for your CUD operations.
4) I think this is a bit out of scope - you probably can find a lot of blogs with images how to do it. Any decent book on EF should also have a chapter (or two) on this. Post a question to stackoverflow if you hit a specific problem.
5) Remove properties in the designer and then supply default value to the S-Space definition. I believe you cannot do this with the designer. You need to rightclick on the edmx file and open it with the Xml editor and manually edit it. Also see this: Issue in EF, mapping fragment,no default value and is not nullable
6) You can either create a view in the database or you can create entity set using E-SQL in your edmx file (I think this will be read only though) or you may be able to use Entity Splitting. Each of these is probably a big topic itself so I think you should find more about these and come back if you have more specific questions / problems

Using "Include foreign key column in the model" option in EF wizard

Do you mostly use this option (the default is checked) or do you uncheck it?
I found out that when I have both FK column and navigation property on my entities it results in problems with mapping tools - they might bind one or the other but almost never both.
If we were to follow the guidelines of conceptual models strictly I think those columns should never make it to properties, should they?
Hopefully many of you reply so we can get a better representation of what developers choose more often.
If we were to follow the guidelines of
conceptual models strictly I think
those columns should never make it to
properties, should they?
Right - that's what the EF team did in the first release with .NET 3.5 SP1 - and got a ton of very negative feedback on it.
Yes, "puristically" speaking - you shouldn't be using foreign key columns directly - you should use the proper way of dealing with the referenced entity instead. But in reality, in many cases - you don't want to have to deal with the whole referenced entity, really - just setting the foreign key column will do (e.g. when importing data or many other cases).
So while yes - I agree - it's a bit of a hack at times, I do see it as a big plus that you have the option to use the foreign key column in an entity - after all, at the database level, that's what you'll be dealing with, too.
So in my opinion, and all the recommendations I've heard from colleagues who also use EF in serious work and all the blogger and EF gurus out there (like Julie Lerman who wrote the book on EF) - turn on that option, and you get the best of both worlds!

Can I force multiplicity/assocations with Entity Framework?

I have the following table structure that Entity Framework is correctly returning as a one-to-many:
Patient
{
PatientId PK
}
Death
{
DeathId PK
PatientId FK
}
Unfortunately this DB design is wrong as you can only have one Death per Patient. The design should of been like this instead:
Death
{
PatientId PK
}
However, this is a production system and the DB is not able to be changed. I am writing a new ASP.Net MVC front-end, so I'm rewriting the DAL layer using Entity Framework.
When I call Patient.Death, I get a collection of Death. I only want it to return me a single or null Death (as the Patient may not yet be dead).
So, I went wading into the Model and tried to change the End2 Multiplicity of the assocation to: 0..1 (Zero or One of Death), but when I build the project I get the error:
Multiplicity is not valid in Role
'Death' in relationship
'RefDeath23'. Because the
Dependent Role properties are not the
key properties, the upper bound of the
multiplicity of the Dependent Role
must be *.
Can anyone tell me how, if possible, I can force this to be a zero or one association?
Can you make the EF do what you want? Sure; just lie to the EF about your DB metadata. You can do this by generating your DB against a "correctly" designed DB or by manually editing the SSDL.
However, think twice before you do this.
The EF makes this difficult, I suspect, for a very good reason: Your DB, for worse or better, allows this. By creating a model which doesn't, you would be setting yourself up for a runtime error should you ever encounter this data condition in the wild, because there would be no way to load it into your model. You would be unable to work with such a person at all until you (externally) fixed the bad data in the DB.
Your EF model should match your database. So if the database is wrong, then the EF model should also be "wrong".
What you can do is to implement this restriction in the business layer.

Composite DB keys with Entity Framework 4.0

The re-design for a large database at our company makes extensive use of composite primary keys on the database.
Forgetting performance impacts, will this cause any difficulties when working with this db in Entity Framework 4.0? The database structure is unlikely to change and I'm not looking for "philosophical" debate but what are the practical impacts?
According to Jeremy Miller, "Composite key make any kind of Object/Relational mapping and persistance in general harder." but he doesn't really say why. Is this relavent to how Entity Framework 4.0 handles keys?
No, EF4 supports composite keys just fine.
The problem is a table with a surrogate key and composite keys. You can only set a single key on each model; that key can have multiple fields, but you can only have one from the designer standpoint. Not sure about manually editing xml or code only mapping.
You can set a field as an Identity and not a key if you need a composite and surrogate key on the same table. The Identity ( Id ) field won't be used by the ObjectContext or ObjectStateTracker but will increment and be queryable just fine though.
I have had problems with EF4 and composite keys. It doesn't support columns being used as components in more than one key in a join table.
See my previous question Mapping composite foreign keys in a many-many relationship in Entity Framework for more details. The nuts of it is that when you have a join table (describing a many-many relationship) where both of the relationships use a common key, you'll get an error like
Error 3021: Problem in mapping
fragments...: Each of the following
columns in table PageView is mapped to
multiple conceptual side properties:
PageView.Version is mapped to
(PageView_Association.View.Version,
PageView_Association.Page.Version)
The only way around it was to duplicate the column which defeats the purpose of having it there at all.
Good luck!