Based on a declared constraint, the navigation property is required - c#

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.

Related

POCO navigation property not updating when foreign key is assigned a value

I have a POCO class (OPERATION) that is used as an Entity Framework entity. This class has a navigation property (OP) and a foreign key into the same related entity (OP_ID).
In a method, I get an OPERATION and on this OPERATION the OP_ID and OP are both null. When I set the OP_ID to a valid value for this foreign key, the OP navigation property remains null. When I explicitly detect changes in the context, the OP navigation property is now assigned with the correct value.
Sample code
public bool UpdateOperation(operationID)
{
IQueryable<OPERATION> operations = from o in base.ctx.OPERATION
select o;
OPERATION operation = operations
.Where(o => o.OPERATION_ID == operationID)
.Include("OP")
.FirstOrDefault();
if (operation != null)
{
operation.OP_ID = opId;
}
// operation.OP is null here
operation.GetContext().ChangeTracker.DetectChanges();
// operation.OP is populated here
}
I have confirmed that the operation is, in fact, a dynamic proxy. For what it's worth, once I detect changes, operation.OP also becomes a dynamic proxy. However, even then, assigning a different value to operation.OP_ID still requires an explicit DetectChanges() call in order to update the value of operation.OP.
Update
In response to the comment from #ErikPhilips, the documentation here seems to imply that this should happen. Specifically:
The following examples show how to use the foreign key properties and navigation properties to associate the related objects. With foreign key associations, you can use either method to change, create, or modify relationships. With independent associations, you cannot use the foreign key property.
By assigning a new value to a foreign key property, as in the following example.
course.DepartmentID = newCourse.DepartmentID;
...
When you change the relationship of the objects attached to the context by using one of the methods described above, Entity Framework needs to keep foreign keys, references, and collections in sync. Entity Framework automatically manages this synchronization (also known as relationship fix-up) for the POCO entities with proxies.
If you are using POCO entities without proxies, you must make sure that the DetectChanges method is called to synchronize the related objects in the context.
Some additional context may be useful, as well. This is a legacy application that used to work directly with an ObjectContext instead of a DbContext, though even then using EF 6. We are now migrating to the DbContext API. This particular code, without any modifications, used to demonstrate the behavior I'm expecting. Specifically, when OP_ID is assigned, I can see in the debugger that the OP property is automatically populated to point to the correct OPERATION.
In the end, I was doing exactly what the documentation described. I was
assigning a new value to a foreign key property.
Yes, Entity Framework does manage this in fix-up. And yes, the documentation does state this.
It turns out, though, that the egg is ultimately on my face. I had checked the classes generated from my T4 template, and seen that all navigation properties were marked virtual. I had not checked thoroughly enough to note that the foreign key properties were not marked virtual, however. It appears that this is the default behavior of the EF-provided T4 template used when working model- or database-first. I've addressed this by changing this line in the CodeStringGenerator.Property() method in the T4 template
Accessibility.ForProperty(edmProperty)
to
AccessibilityAndVirtual(Accessibility.ForProperty(edmProperty))
In the end, as usual, following the documentation (here, the requirements for EF change tracking on POCOs) often results in dependent code behaving as it is documented. Shame on me.

DbSets with Subtypes: The child/dependent side could not be determined for the one-to-one relationship

Similar to this question, I'm trying to get my EF object model squared away, and UNLIKE the linked question, I am in fact setting up the modelBuilder calls inside the actual DbContext, not a Snapshot. It looks something like:
modelBuilder.Entity<MyUser>()
.HasOne(a => a.MyProfile)
.WithOne(a => a.MyUser)
.HasForeignKey<MyProfile>(c => c.Id)
.HasPrincipalKey<MyUser>(x => x.UserIntId);
One difference here is that both MyUser and MyProfile inherit from other types, UserEntity and ProfileEntity, which in turn have associated properties, i.e. UserEntity has UserEntity.Profile of type ProfileEntity and ProfileEntity has ProfileEntity.User of type UserEntity.
So, the exception I get is:
System.InvalidOperationException: The child/dependent side could not be determined for the one-to-one relationship between 'UserEntity.Profile' and 'ProfileEntity.User'. To identify the child/dependent side of the relationship, configure the foreign key property. If these navigations should not be part of the same relationship configure them without specifying the inverse. See http://go.microsoft.com/fwlink/?LinkId=724062 for more details.
I'm not sure how to resolve this exception in this case without totally removing the inheritance (which I would like to avoid in order to save time having to do a refactor of base libraries).

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?

Updating foreign key in Entity Framework 7

I am trying to update a foreign key using Entity Framework 7. But it is giving error: The property 'Y' could not be found in object 'X'. I have tried many different solution but still not working. The sample code:
class X
{
property Y {get; set;} -> property Y is a foreign key and also a complex type
}
In table 'X' we have a column 'Y_ID' which is the foreign key.
Note: I just want to update the foreign key. E.g. Initially class 'X' is pointing to 'NULL', I want to update class 'X' to point to 'Y1'
The Entity Framework 7 code:
var x = this.GetX();
this.mainContext.Xs.Attach(x);
var xEntry = this.mainContext.Entry(x);
xEntry.Property("Y").CurrentValue = "Y1"; // Error at this line
await this.mainContext.SaveChangesAsync().ConfigureAwait(false);
Detailed Error:
The property 'Y' on entity type 'X' could not be found. Ensure that the property exists and has been included in the model.
Edit
The approach Fabien suggested in his comment works fine. But the problem is we only know about which property to update is at runtime. If I use reflection to achieve this, the problem is entity framework treats the object as new and tries to create it (INSERT) and then throws Primary Key violation (No duplicate entries allowed)
So, is there a way where I can't still update an object property which acts like a foreign key in EF? (I don't know exact property at compile time).
If you get the entities "X" and "Y" from your context, then they're automatically tracked by the ChangeTracker. So if you assign "Y" property of the "X" object with an "Y" instance retrieved from your context and call SaveChanges or SaveChangesAsync, EntityFramework will automically do the stuff for you.
var x = this.GetX();
x.Y = "Y1";
await this.mainContext.SaveChangesAsync().ConfigureAwait(false);
By convention, your property "Y" on object "X" should be virtual to indicate that it's an foreign key.
Edit 1 :
If I understand correctly, you want to update properties of your object dynamically at runtime, with values that comme from a web api.
1st way :
Like you did, you can attach your "X" object to your context instance to begin tracking of the entity with EntityState.Unchanged, and then flag each property that need to be updated :
this.mainContext.Xs.Attach(x);
var entry = this.mainContext.entry(x);
entry.Property(p => p.Y).CurrentValue = "Y1";
await this.mainContext.SaveChangesAsync().ConfigureAwait(false);
When attaching an entity, you can specify the GraphBehavior, it tell EntityFramework if navigation properties should traversed or not.
2nd way :
Using the DbSet.Update() method :
this.mainContext.Xs.Update(x);
await this.mainContext.SaveChangesAsync().ConfigureAwait(false);
It's automatically begin tracking of the entity with the state EntityState.Modified, all properties will be marked as modified. You should watch out when using this method, because all properties will be updated, if some of them are not inititialized in your "X" object, you could lost some data. To prevent that case, you should always validate inputs.
If you want to keep your domain models de-coupled form any ORM, then you should think to separate entity types and domain types. You can use an object mapper like Automapper to map entity to domain type and vice versa. In that way you clearly separate what you do at data access layer and business logic layer.

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

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.

Categories