简体   繁体   中英

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. Eg 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM