我正在使用EF 5编写一个C#ASP.NET MVC 5 Web应用程序。使用EF映射我的数据库表会生成DbContext
类和.edmx
文件。今天,我正在阅读a great article about creating generic DAL classes,但我停止了下面的句子:
请注意,使用Entry方法更改实体的状态 仅影响您传入方法的实际实体。它不会 通过图形级联并设置所有相关对象的状态, 与DbSet.Add方法不同。
这与这些问题中提到的内容相矛盾:
在上述所有问题的答案中,所有用户都提到使用System.Data.EntityState.Added
与使用DbSet.Add
完全相同。但我之前提到的文章指出,使用System.Data.EntityState.Added
不会在图表中级联。
根据我的测试,我得出结论,使用System.Data.EntityState.Added
将在DBset.Add
案例中与图表级联。该文章是错误的,还是我的测试和Q& A?
答案 0 :(得分:5)
这些方法是相同的,你可以通过常规测试来验证,或者,如果你想完全确定 - 通过对EF 6代码的一些探索。
DbSet.Add
方法(http://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework/DbSet.cs)
public virtual TEntity Add(TEntity entity)
{
Check.NotNull<TEntity>(entity, "entity");
this.GetInternalSetWithCheck("Add").Add((object) entity);
return entity;
}
这会调用InternalSet<T>.Add(object)
方法。
DbEntityEntry<T>.State
属性(http://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework/Infrastructure/DbEntityEntry.cs)
public EntityState State
{
get { return _internalEntityEntry.State; }
set { _internalEntityEntry.State = value; }
}
_internalEntityEntry
属于InternalEntityEntry
类型。
InternalEntityEntry.State
属性(http://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework/Internal/EntityEntries/InternalEntityEntry.cs)
public virtual EntityState State
{
get { return IsDetached ? EntityState.Detached : _stateEntry.State; }
set
{
if (!IsDetached)
{
if (_stateEntry.State == EntityState.Modified
&& value == EntityState.Unchanged)
{
// Special case modified to unchanged to be "reject changes" even
// ChangeState will do "accept changes". This keeps the behavior consistent with
// setting modified to false at the property level (once that is supported).
CurrentValues.SetValues(OriginalValues);
}
_stateEntry.ChangeState(value);
}
else
{
switch (value)
{
case EntityState.Added:
_internalContext.Set(_entityType).InternalSet.Add(_entity);
break;
case EntityState.Unchanged:
_internalContext.Set(_entityType).InternalSet.Attach(_entity);
break;
case EntityState.Modified:
case EntityState.Deleted:
_internalContext.Set(_entityType).InternalSet.Attach(_entity);
_stateEntry = _internalContext.GetStateEntry(_entity);
Debug.Assert(_stateEntry != null, "_stateEntry should not be null after Attach.");
_stateEntry.ChangeState(value);
break;
}
}
}
}
您会看到如果实体已分离(您的情况)且状态已添加 - 则会调用相同的InternalSet<T>.Add(object)
。
关于通过测试验证:
using (var ctx = new TestDBEntities()) {
// just some entity, details does not matter
var code = new Code();
// another entity
var error = new Error();
// Code has a collection of Errors
code.Errors.Add(error);
var codeEntry = ctx.Entry(code);
// modify code entry and mark as added
codeEntry.State = EntityState.Added;
// note we did not do anything with Error
var errorEntry = ctx.Entry(error);
// but it is marked as Added too, because when marking Code as Added -
// navigation properties were also explored and attached, just like when
// you do DbSet.Add
Debug.Assert(errorEntry.State == EntityState.Added);
}
答案 1 :(得分:5)
我不知道那篇博客的作者。我确实知道book DbContext的作者(虽然不是亲自)。他们知道EF内外。因此,当他们在第80页写下
致电
DbSet.Add
并将State
设置为Added
,两者完全相同。
我知道自己在做什么。他们完全相同的事情,即:
如果上下文没有跟踪实体,它将开始被上下文跟踪
Added
州。DbSet.Add
。State
和将Added
设置为Added
都是图表操作 - 意味着没有被上下文跟踪并且可以访问的任何其他实体 来自根实体的也将标记为DbSet.Add
。
我也从经验中知道它的工作原理。但是为了消除任何疑问,在EF的源代码中,DbEntityEntry.State
和Added
(设置为ObjectContext
时)到达实际工作的public virtual void AddObject(string entitySetName, object entity)
中的相同点:
{{1}}
这是一个继续欺骗开始使用EF的开发人员的功能,这从StackOverflow上的大量问题可以看出,他们提出了“为什么我的实体会被重复?”的问题。 Julie Lerman写了entire blog解释为什么会发生这种情况。
这种持续的妄想使EF团队决定在EF7中change this behavior。
也许您所引用的博客的作者是那些被迷惑的开发者之一。