在实体框架7中更新外键

时间:2016-04-08 07:54:55

标签: c# sql-server entity-framework foreign-keys entity-framework-core

我正在尝试使用Entity Framework 7更新外键。但是它给出了错误:在对象'X'中找不到属性'Y'。我尝试了很多不同的解决方案,但仍然没有工作。示例代码:

class X
{
  property Y {get; set;} -> property Y is a foreign key and also a complex type
}

在表'X'中,我们有一个'Y_ID'列,它是外键。

注意:我只想更新外键。例如。 最初类'X'指向'NULL'我想更新类'X'指向'Y1'

实体框架7代码:

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);

详细错误:

  

无法找到实体类型“X”上的属性“Y”。确保该属性存在且已包含在模型中。

修改

Fabien在他的评论中提出的方法很好。但问题是我们只知道要在运行时更新哪个属性。如果我使用反射来实现这一点,问题是实体框架将对象视为新对象并尝试创建它(INSERT)然后抛出主键冲突(不允许重复条目)

那么,是否有一种方法可以让我无法更新在EF中充当外键的对象属性? (我在编译时不知道确切的属性。)

1 个答案:

答案 0 :(得分:0)

如果从上下文中获取实体“X”和“Y”,则ChangeTracker会自动跟踪它们。因此,如果您将“X”对象的“Y”属性与从您的上下文中检索到的“Y”实例分配并调用SaveChanges或SaveChangesAsync,则EntityFramework将自动为您执行这些操作。

var x = this.GetX();    
x.Y = "Y1";
await this.mainContext.SaveChangesAsync().ConfigureAwait(false);

按照惯例,对象“X”上的属性“Y”应该是虚拟的,表示它是外键。

编辑1:

如果我理解正确,您希望在运行时动态更新对象的属性,并使用来自web api的值。

第一路:

与您一样,您可以将“X”对象附加到上下文实例,以开始使用EntityState.Unchanged跟踪实体,然后标记需要更新的每个属性:

this.mainContext.Xs.Attach(x);
var entry = this.mainContext.entry(x);
entry.Property(p => p.Y).CurrentValue = "Y1";
await this.mainContext.SaveChangesAsync().ConfigureAwait(false);

附加实体时,您可以指定GraphBehavior,它会告诉EntityFramework是否应该遍历导航属性。

第二路:

使用DbSet.Update()方法:

this.mainContext.Xs.Update(x);
await this.mainContext.SaveChangesAsync().ConfigureAwait(false);

它会自动开始跟踪状态为EntityState.Modified的实体,所有属性都将被标记为已修改。您应该注意何时使用此方法,因为所有属性都将更新,如果其中一些属性未在“X”对象中初始化,则可能会丢失一些数据。为了防止这种情况,您应该始终验证输入。

如果您希望将您的域模型从任何ORM中解除耦合,那么您应该考虑将实体类型和域类型分开。您可以使用Automapper之类的对象映射器将实体映射到域类型,反之亦然。通过这种方式,您可以清楚地分离您在数据访问层和业务逻辑层所做的工作。

相关问题