Multiplicity constraint violations with optional-required EF Code First + Fluent relationship? - c#

For some reason I had my made my mind a while back on an EF 6 project that I would try to avoid naming foreign keys. I defined much of the model without testing it incrementally and so I have been running into multiplicity and incomplete Fluent API definition issues:
A relationship from the 'User_InternalAuth' AssociationSet is in the
'Deleted' state. Given multiplicity constraints, a corresponding
'User_InternalAuth_Target' must also in the 'Deleted' state.
In one case, here is the code:
nModelBuilder.Entity<User>()
.HasOptional<InternalAuth>(u => u.InternalAuth)
.WithRequired(a => a.User)
.WillCascadeOnDelete(true);
My understanding is that it is saying:
The entity User
Has an optional property InternalAuth of type InternalAuth
On the other end, InternalAuth has a required property User, so that all InternalAuths have Users but Users may or may not have an `InternalAuth.
If the User gets deleted, so does his InternalAuth if he has one (does this override an optional behavior of treating optionals like nullables?)
However when I try to delete a User I receive an exception about the multiplicity of some association between InternalAuth and User.
Is it true that if EF understands the multiplicity of a relationship there is a way for it to provide it a unique column name for it so there is a canonical naming convention?
If so, do you ever really need to define foreign keys explicitly by annotating the model or through Fluent API?
If not, is it a worthwhile or advisable thing that I should keep trying to avoid it? (I'm thinking along the lines of migrating the data model, database administration, any EF quirks)
Why does attempting to delete the relationship above violate a multiplicity constraint? What else does it need to know?

assuming that
You can configure cascade delete on a relationship by using the WillCascadeOnDelete method. If a foreign key on the dependent entity is not nullable, then Code First sets cascade delete on the relationship. If a foreign key on the dependent entity is nullable, Code First does not set cascade delete on the relationship, and when the principal is deleted the foreign key will be set to null.
My guess is the following : the FK is nullable so the fact to set it to null with the required constraint causes the rise of the exception.
One solution is to put the FK in the PK, that is add, in InternalAuth, the FK to User in the PK. Doing this will mark the entity as deleted when setting a part of his PK to null.

Related

Entity Framework 6.x Code First 0..1 : many mapping without explicit FK property - can it be done?

I think I can illustrate this issue without having to define the classes, as the actual structure beyond the foreign key and navigation properties does not seem to have any bearing.
In my derived EntityTypeConfiguration class, Entity Framework will let me do this if I want a 1-many relationship with no FK property defined:
HasRequired(r => r.Foo)
.WithMany(); //No explicit foreign key property, navigation property only
If I want a 0..1-many relationship, I can do this with an explicit nullable FK property, for instance public int? Foo_Id {get; set;}:
HasOptional(r => r.Foo)
.WithMany()
.HasForeignKey(r=>r.Foo_Id); //Nullable explicit foreign key property and navigation property
but I cannot configure a 0..1-many relationship without an explicitly defined FK property the way I can with a 1-many relationship:
HasOptional(r => r.Foo)
.WithMany(); ////No explicit foreign key property, navigation property only, causes runtime error
The error I receive on the last example is something akin to this:
Multiplicity conflicts with the referential constraint in Role 'Bar_Foo_Target' in relationship 'Bar_Foo'. Because all of the properties in the Dependent Role are non-nullable, multiplicity of the Principal Role must be '1'.
It seems pretty apparent that the error doesn't match the mapping. I know that this can pop up if you try to configure a 0..1-many relationship where the FK property is not made nullable, but that's not the case here, because there is no FK property defined on the class.
Am I missing something? Is this a bug? Why can I configure a 1-many relationship and EF successfully deduces the FK, but on a 0..1-many it craps the bed without an explicitly defined nullable FK property on my class?

Entity Framework DBFirst turns table into association, how to get table access?

I have a DBFirst EntityFramework 6.1 solution that i'm trying to generate off of. When i add a table that only contains two foreign keys the table is turned into two associations and I can not directly access the table anymore. This is neat for navigation in the code but makes it a pain in the ass to delete records from the table.
Is there a way to prevent this behavior and gain direct access to the table as an entity?
For example i am unable to remove an entry in the association because i get this error
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
For example here is how my database sees the structure.
Here is how it appears in entity framework. Notice that the CorporateDataShareVisible table is missing and instead two new associations are created.
The CorporateDataShareVisible table should be able to be deleted and added to at will but any changes i make seem to stop it from working.
Add a primary key to your table that has only foreign keys. EF uses the primary key to keep track internally of the element. Without a primary key it doesnt know which element was modified and how to send that back to your RDBMS.
I prefer surrogate keys i.e auto incrementing integers.
You can also add the primary key by making it a composite key of both the foreign keys

Removing navigation properties from POCO-classes in Entity Framwork

I'm using generated POCO classes and Entity Framework.
In order to make the code less complex I'm trying to remove all navigation properties from the code while still keeping the Foreign Key constraints in the database (navigation properties do more harm than good for us).
If I remove them manually from the POCO-classes I get the following error
The entity type UserEntity is not part of the model for the current context
If I try to remove them from the .edmx-file I get the following error:
Error 3 Error 3015: Problem in mapping fragments starting at lines 479, 562:Foreign key constraint 'fk_StorageContracts_User1' from table StorageContract (OwnerUserID) to table User (ID):: Insufficient mapping: Foreign key must be mapped to some AssociationSet or EntitySets participating in a foreign key association on the conceptual side.
Is there any way to remove navigation properties from POCO-classes without removing the corresponding FK?
I know this is old, but, since there is still no answer, I thought I'd give it a try:
I am still working in EF 4.0, but, following the example to which you referred, you have an xxxModel.tt. If you are willing to tweak that, you can find where it generates the Navigation Properties and change them to be simple auto-properties. I had a similar project where I generated them like this:
public List<NavDataX> NavDataXs
{
get; set;
}
Now, they are still there, but they are null until you explicitly set them. Doing it this way, I did not mess with the EDMX and did not encounter the two errors you mentioned.

remove foreign key property cause an exception

I don't want to use foreign key association to CompanyType (member that will hold the foreign key id) but prefer to use navigation property. So I removed the CompanyTypeId.
I get this exception that relates the relationship between entity Company and CompanyType:
Error 5: The element 'Principal' in
namespace
'http://schemas.microsoft.com/ado/2008/09/edm'
has incomplete content. List of
possible elements expected:
'PropertyRef' in namespace
'http://schemas.microsoft.com/ado/2008/09/edm'.
How can I remove those id's from the POCOs without getting the exception?
This is the difference between Foreign key association and Independent association. Both associations use navigation properties but only Foreign key association uses FK property as well. You can either remove them globally as #Robbie mentioned or you can change the type manually for selected relation.
Select the relation in entity framework designer
In properties remove Referential constraints
Go to Mapping window and map the relation
Here is the screen shot from one of my testing application with one-to-many relation between Order and OrderLine entities:
As you can see there is no OrderId in the OrderLine entity and referential constraints of the relation are empty. Also mapping of the relation is specified.
BUT you can't never remove Id from CompanyType. Ids (PKs) are mandatory. You can only change its accessibility in its properties.
When you imported in your Model from your DB you are asked if you want to:
"Include Foreign key columns in the model"
you need to switch this off.

Based on a declared constraint, the navigation property is required

Im dealing with code first .NET 4 and i'm having trouble with a 1 to 1 relation.
breifing of database:
-POccurrence
-Id
-POccurrenceRiskAssessment
-OccurrenceId
in my class Poccurrence I have a property named RiskAsessment, of the type POccurrenceRiskAssessment. Not all POccurrences have riskassessments, so it needs to be nullable.
I tried
modelBuilder.Entity<POccurrence>().HasOptional(item => item.RiskAssessment).HasConstraint((o, r) => r.OccurrenceId == o.Id);
but that gives me
The navigation property
'RiskAssessment' declared on type
'AM.Pris.Classes.POccurrence' has been
configured as optional. Based on a
declared constraint, the navigation
property is required. Either make some
dependent key property nullable or
configure the navigation as required.
and if i try
modelBuilder.Entity<POccurrence>().HasRequired(item => item.RiskAssessment).HasConstraint((o, r) => r.OccurrenceId == o.Id);
i get
A referential integrity constraint
violation occurred: A primary key
property that is a part of referential
integrity constraint cannot be changed
when the dependent object is Unchanged
unless it is being set to the
association's principal object. The
principal object must be tracked and
not marked for deletion.
and i have no idea what to do. I even tried to delete the real relation in the DB but nothing seems to make any difference. Any idea? I guess its the first try with HasOptional i'm looking for, but how do i make it nullalbe?
Have you considered rolling this up into an Table Per Type inheritance scenario where POccurrenceRiskAssessment : POccurrence? That way you only need query POccurrenceRiskAssessment.

Categories