我有一个我正在修改然后保存的实体。有两个属性,两者都有变化。我已经验证两者都不是空的并且设置为我的意图。但是,当我在数据库中显示它时,我可以看到只有第一个更改(列一些),而另一个保持不变(列 ThingId )。 / p>
public class Holder
{
public string Some { get; set; }
public Thing Thing { get; set; }
}
public class Thing
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Holder> Holders { get; set; }
}
存储按以下方法完成。
model.Holders.Attach(holder);
model.Entry(holder).State = EntityState.Modified;
model.SaveChanges();
它们之间的关系是使用Fluent API以下列方式定义的。
builder.Entity<Holder>()
.HasOptional(_ => _.Thing)
.WithMany(_ => _.Holders)
.Map(_ => _.MapKey("ThingId"));
我错过了什么?创建新持有者时,问题不会出现。仅在尝试更新时。
答案 0 :(得分:1)
当你说
时model.Entry(holder).State = EntityState.Modified;
EF了解持有人实体中的标量已被修改。
所以现在你想让EF知道“Thing”也发生了变化。所以你必须通过说:
明确说出来model.Entry(holder.Thing).State = EntityState.Modified;
如果您不想这样做,则必须将ThingID的属性添加到模型中并同样填充它。
您可以通过https://www.safaribooksonline.com/library/view/programming-entity-framework/9781449331825/ch04s03.html了解EF中的状态。
答案 1 :(得分:1)
使用分离的对象非常棘手 无论如何,一种方法是为外键添加属性并处理它(不只是添加属性)。请参阅其他答案了解详情如果你想使用分离的实体,我认为这是最好的选择。如果你需要使用n-m关系(HasMany WithMany),它就不起作用。
另一个解决方案就是这个(这也适用于n-m关系)
context.Holders.Attach(holder);
context.Entry(holder).State = EntityState.Modified;
var manager = ((IObjectContextAdapter)context).ObjectContext.ObjectStateManager;
manager.ChangeRelationshipState(holder, holder.Thing, "Thing", EntityState.Added);
context.SaveChanges();
此解决方案的问题是EF会生成类似于此
的更新查询update [Holders]
set [Some] = @p0, [ThingId] = @p1
where (([Id] = @p2) and [ThingId] is null)
@p0 = "Holder updated"
@p1 = 100
@p2 = 200
(看看where子句)
如果将更新方法更改为此(更易读),则会出现类似的行为。
var thing = holder.Thing;
holder.Thing = null;
var attachedHolder = context.Holders.Attach(holder);
attachedHolder.Thing = thing;
context.Entry(holder).Property("Some").IsModified = true;
context.SaveChanges();
同样在这种情况下,生成的更新查询是
update [Holders]
set [Some] = @p0, [ThingId] = @p1
where (([Id] = @p2) and [ThingId] is null)
@p0 = "Holder updated"
@p1 = 100
@p2 = 200
所以,在这两种情况下你都需要知道原始的东西(可以分离)。如果您知道,可以通过以下方式更改代码:
var thing = holder.Thing;
holder.Thing = myOldThing; // for example new Thing() {Id = 2} works
var attachedHolder = context.Holders.Attach(holder);
attachedHolder.Thing = thing;
context.Entry(holder).Property("Some").IsModified = true;
context.SaveChanges();
实际上我还没有读过EF源代码的这一部分,但我认为这种行为与可以管理n-m关系的关系处理程序有关(HasMany-WithMany)。在这种情况下,EF还为关系生成“支持”表,主键列是两个表的主键列的总和。更新此类关系需要在支持表的主键上的位置。
答案 2 :(得分:0)
我建议采用三种可能的方法解决问题。
首先是从EF收回部分控件并自行管理连接。基本上,您需要引入带有外键的显式字段,并明确地看到那些被设置的字段。
第二个允许EF管理更新,但要非常明确地告诉它如何操作。原则上,您必须告诉它将实体视为添加,操纵,删除等。
最后,这是我推荐的,因为它是正确的,面向对象的ORM范式方法,是解决EF无法识别实体开始的问题。在你的课程中,我无法看到有关正在实施的比较方法的任何内容(有平等,哈希控制等),如果你谷歌那些,你可能会注意到有很多好东西,EF依赖因为计算机直观地帮助了我们,所以我们通常会有点邋with(并躲开它)。
另外,免责声明。我已经听过很多次(并且我自己说过),在某些情况下,EF不够用,并且必须应用两种初始方法中的一种。回顾过去,它总是被其他地方的代码所证实(被遗忘的 Hash 实现,混淆,非唯一ID或只是迁移中的错误,而不是更新它应该在哪里更新)。我并不是说这是在这里或在任何地方的情况。我只是说我没有其他数据表明,除了其他人之外&#39;推荐。