Entity framework 4 EF6更新附加需要已修改,否则静默失败vs EF4

Entity framework 4 EF6更新附加需要已修改,否则静默失败vs EF4,entity-framework-4,entity-framework-6,Entity Framework 4,Entity Framework 6,你能告诉我为什么EntityFramework6需要“IsModified”代码行来更新attach,否则我的代码相对于EntityFramework4会“无声失败”吗?换句话说,在EntityFramework4中,我使用AttachItWorks进行更新。但在EF6中,如果我做类似的操作,db将不会更新,也不会抛出异常(静默失败)。如果我在代码中加入“IsModified”行,它就可以工作,但这是不可接受的,因为开发人员可能会忽略“IsModified”代码,更新将失败,并且没有人会知道 在

你能告诉我为什么EntityFramework6需要“IsModified”代码行来更新attach,否则我的代码相对于EntityFramework4会“无声失败”吗?换句话说,在EntityFramework4中,我使用AttachItWorks进行更新。但在EF6中,如果我做类似的操作,db将不会更新,也不会抛出异常(静默失败)。如果我在代码中加入“IsModified”行,它就可以工作,但这是不可接受的,因为开发人员可能会忽略“IsModified”代码,更新将失败,并且没有人会知道

在db中设置的以下条件下,EF6中会出现/不会出现此问题: 1.如果active设置为默认值1且AllowNulls=false,则更新失败 2.如果active未设置为默认值且AllowNulls=false,则更新失败 3.如果active未设置为默认值且AllowNulls=true,则更新有效 4.如果active设置为默认值1且AllowNulls=true,则更新有效

这类似于:但不确切。我将带您解决这个问题:

(一) 如果您有VisualStudio2010,您可以继续使用,否则,您可以相信我EF4的工作原理与前面描述的一样

在VisualStudio2010中,新项目ASP.NETMVC2Web应用程序,使用.NETFramework4,并将其命名为EF4Works。不要创建单元测试

2) 请确保添加默认值,并且不允许为null,这一点很重要

    CREATE TABLE [dbo].[Document](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [DocumentName] [varchar](10) NULL,
    [Active] [bit] NOT NULL CONSTRAINT [DF_Document_Active]  DEFAULT ((1)),
 CONSTRAINT [PK_Document] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
3) 插入行“DocName”1(真)

4) 将edmx添加到此表中

5) 在主索引控制器(必要时添加此控制器)中添加并运行此代码(类似),并检查db是否工作!(更新数据库)(在调用视图之前放置断点):

6) 将活动标志放回1

7) 在Visual Studio 2013中添加新的解决方案和项目。Web、.NET Framework 4.5.1名为EF6的ASP.NET Web应用程序失败,下一个向导页面MVC,将身份验证更改为无身份验证。在软件包管理器控制台中:卸载软件包EntityFramework-项目ef6fails-强制然后安装软件包EntityFramework-版本6.1.3-项目ef6fails

8) 将EF6中的edmx添加到文档表失败

9) 在控制器中运行此代码,并在调用视图之前放置断点:

    public ActionResult Index()
    {
        BreazEntities entities = new BreazEntities();
        Document document = new Document { Id = 1 };
        entities.Documents.Attach(document);
        document.Active = false;
        entities.SaveChanges();

        return View();
    }
    public ActionResult Index()
    {
        BreazEntities6 entities = new BreazEntities6();
        Document document = new Document { Id = 1 };
        entities.Documents.Attach(document);
        document.Active = false;
        entities.SaveChanges();

        return View();
    }
  • 这是行不通的。我将不得不做以下事情,这是不可接受的,因为新开发人员可能会排除以下内容,而不知道代码不起作用。是否有一些东西,我可以全局添加到解决方案中,而不让开发人员添加以下内容?我将自己研究并尝试添加一些内容,直到从SO获得答案:

        BreazEntities6 entities = new BreazEntities6();
        Document document = new Document { Id = 1 };
        entities.Documents.Attach(document);
        /*  The following line needs to be added in EF6, BUT not in EF4 */
        entities.Entry(document).Property(e => e.Active).IsModified = true;
        document.Active = false;
        entities.SaveChanges();
    
        return View();
    

  • 您指出了使用
    ObjectContext
    的EF 4.1和使用
    DbContext
    的EF 6(实际上是4.1和更高版本)在代码生成方面的差异

    ObjectContext
    API中,一个数据库字段(如
    Active
    )生成的代码不少于以下代码:

    //
    ///没有可用的元数据文档。
    /// 
    [EdmScalarPropertyAttribute(EntityKeyProperty=false,IsNullable=false)]
    [DataMemberAttribute()]
    公共全局::System.Boolean处于活动状态
    {
    得到
    {
    返回激活状态;
    }
    设置
    {
    OnActiveChanging(值);
    报告财产变更(“活动”);
    _Active=StructuralObject.SetValidValue(值);
    ReportPropertyChanged(“Active”);
    OnActiveChanged();
    }
    }
    私有全局::System.Boolean\u活动;
    激活更改部分无效(全局::System.Boolean值);
    激活更改()上的部分无效;
    
    这意味着EF的变更跟踪者将立即收到每项财产变更的通知

    DbContext
    API不仅是对开发人员更友好的API的一种改变,而且是对更简单的类模型的一种改变,是对真正持久化的一种转变。我相信在开始时,仍然生成了这个自跟踪代码,但最终,它被放弃了,数据库字段将由一个简单的自动生成属性表示:

    public bool Active{get;set;}
    
    (毫无疑问,这样做也是为了在代码优先和数据库优先方法的基础上有一个统一的代码库)

    这不可避免地将更多的责任推到了变革跟踪者的肩上。它必须检测变化,而不是仅仅注册它们。因此,执行更改跟踪方法
    DetectChanges

    回到你的代码

    在“旧的”
    ObjectContext
    API中

    document.Active=false;
    
    。。。将立即通知更改跟踪程序已设置属性。即使它已经为false,也会在
    SaveChanges
    上发出
    UPDATE

    DbContext
    API中,更改跟踪器永远不会将此检测为更改,因为
    Active
    已经有布尔值的默认值,
    false
    。没有什么变化

    简而言之,它过去是“你设置的就是你更新的”,现在变成了“你改变的就是你更新的”

    好吧,现在怎么办? 你可能想回到你曾经拥有的

    但是你呢

    试着改变一下视角。假设您先编写代码,您会像第一个代码片段那样编写属性代码吗?你真的愿意吗?首先,这是紧密耦合,没有单一责任。在断开连接的情况下(即重新连接反序列化实体),可能会导致许多不必要的更新

    然而,即使您要编写(或生成)类似的代码,EF也不会听取这些更改。您必须自己为上下文中的某些更改传播代码订阅物化实体。它不再是内置的,除非您返回到
    ObjectContext
    API(您不需要)

    我会说:接受它。您失去了一些,但赢得了很多(更可靠的代码)。习惯您可能希望将
    Active
    设置为true,作为实体构造函数中的默认值,以便更改跟踪器注意到
    false
    的更改

    但我不这么认为