EF中Add()和Attach()两种添加数据方法的区别

最近在开发一个项目,在实现某个模块数据的插入操作时(底层数据库的交互采用的是EF),发现无论如何数据都不能插入成功,把数据拷贝出来放到数据库中执行Sql语句时却能正确插入,下面给出代码片段

 public int InsertWithFundInfo(F_WithFunding_Info withinfo)
        {
            int res = 0;
            using (var context = new RenRenChaoContext())
            {
                context.F_WithFunding_Info.Attach(withinfo);
                return res = context.SaveChanges();
            }
        }
核心也就是两段代码,就是不知道问题出在了哪里。后来想起EF插入数据还有一个Add方法,于是抱着侥幸的心理试了试,结果竟然成功了。
 public int InsertWithFundInfo(F_WithFunding_Info withinfo)
        {
            int res = 0;
            using (var context = new RenRenChaoContext())
            {
                context.F_WithFunding_Info.Add(withinfo);
                //context.F_WithFunding_Info.Attach(withinfo); return res = context.SaveChanges();
}
在网上搜了一番,发现虽然两者都可以用来插入数据,不过还是有一些细微的差别。

在讲解差别之前,我们先来看下命名空间下的描述实体所处状态的枚举类型EntityState:

    // 摘要:
    //实体对象的状态。
    [Flags]
    public enum EntityState
    {
        // 摘要:
        //     对象存在,但未由对象服务跟踪。在创建实体之后、但将其添加到对象上下文之前,该实体处于此状态。通过调用 System.Data.Objects.ObjectContext.Detach(System.Object)
        //     方法从上下文中移除实体后,或者使用 System.Data.Objects.MergeOption.NoTrackingSystem.Data.Objects.MergeOption
        //     加载实体后,该实体也会处于此状态。
        Detached = 1,
        //
        // 摘要:
        //     自对象加载到上下文中后,或自上次调用 System.Data.Objects.ObjectContext.SaveChanges() 方法后,此对象尚未经过修改。
        Unchanged = 2,
        //
        // 摘要:
        //     对象已添加到对象上下文,但尚未调用 System.Data.Objects.ObjectContext.SaveChanges() 方法。对象是通过调用
        //     System.Data.Objects.ObjectContext.AddObject(System.String,System.Object)
        //     方法添加到对象上下文中的。
        Added = 4,
        //
        // 摘要:
        //     使用 System.Data.Objects.ObjectContext.DeleteObject(System.Object) 方法从对象上下文中删除了对象。
        Deleted = 8,
        //
        // 摘要:
        //     对象已更改,但尚未调用 System.Data.Objects.ObjectContext.SaveChanges() 方法。
        Modified = 16,
    }<p></p>
这五种状态分别是:Detached-游离;UnChanged-没有变化;Added-添加;Deleted-删除;Modified-编辑。Detached状态下的Entity不会被上下文(context)所捕获(track)。当SavaChanged()方法执行期间,他会查看当前Entity的EntityState的值,决定是去新增(Added)、修改(Modified)、删除(Deleted)、什么也不做(UnChanged)。

1.Attach()

Attach在 微软的中文翻译中是附加,不同于Add方法的添加,她是将一个处于Detached的Entity附加到上下文,而附加到上下文后的这一Entity的State为UnChanged。传递到Attach方法的对象必须具有有效的EntityKey值。如果该对象不具有有效的EntityKey值,请使用AttachTo方法指定实体集的名称。

2、Add()

MSDN的解释:Add方法将对象将一个对象添加到集合中,添加到EntityCollection并创建两个对象之间的关系。当源对象附加到ObjectContext实例时,方法也将对象添加到ObjectContext当调用SaveChanges时,此操作转换为插入到数据源中的操作。

自我理解:ObjectContext类的Add()方法的作用就是将一个Entity的State修改为Added,这样在SavaChanged()方法就会将实体新增到数据库当中

这样,在上面的程序中通过调用Attach()方法只能把对象添加到了对象上下文中(此时对象的状态已经是Unchanged的),执行SaveChange()方法并不能真正添加到数据库中去。要想真正执行还需要添加一个修改实体状态的代码。

context.ObjectStateManager.ChangeObjectState(withinfo,EntityState.Added);  
调用Add()方法时其实已经隐藏了修改实体的状态为Added的这个操作,执行SaveChange()方法就可以进行新增的操作。

在 Linq to EF 增删改查这篇文章中添加数据介绍了两种方法的具体使用有兴趣的可以参考一下。


参考文献:https://msdn.microsoft.com/zh-cn/library/system.data.objects.objectcontext.attach(v=vs.110).aspx

                https://msdn.microsoft.com/zh-cn/library/system.data.objects.objectcontext.addobject(v=vs.110).aspx

                https://msdn.microsoft.com/zh-cn/library/bb351713(v=vs.110).aspx

                http://www.cnblogs.com/Jnw-qianxi/archive/2013/08/15/3260989.html