您能告诉我为什么Entity Framework 6需要使用“ IsModified”代码行进行带有附件的更新,否则我的代码将为“ Silent Fail”,而不是Entity Framework 4?换句话说,在Entity Framework 4中,我进行了附有更新的工作。但是在EF6中,如果我做类似的事情,数据库将不会更新,也不会抛出异常(静默失败)。如果我在代码中放入“ IsModified”行,则可以正常工作,但这是不可接受的,因为开发人员可能会忽略“ IsModified”代码,并且更新将失败,并且没人知道。
在数据库中设置的以下条件下,此问题将在EF6中发生/不会发生:1.如果将active设置为默认值1并且AllowNulls = false,则更新失败2.如果未将active设置为默认值并且AllowNulls = false,则更新失败3.如果未将active设置为默认值并且AllowNulls = true,则更新有效。4.如果active设置为默认值1并且AllowNulls = true,则更新效果正常
这类似于:EntityFramework不保存null和false值,但不精确。我将引导您解决问题:
1)如果您拥有Visual Studio 2010,则可以继续进行,否则,您可以相信我EF4可以按照说明进行工作。
在Visual Studio 2010中,使用.NET Framework 4创建新项目ASP.NET MVC 2 Web应用程序,并将其命名为EF4Works。不要创建单元测试。
2)确保添加默认值并且不允许为空,这一点很重要
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(true)
4)在此表中添加edmx。
5)在Home Index Controller中(如有必要,添加此控制器)添加并运行此代码(类似),并检查db IT WORKS!(updates db)(在调用视图之前插入断点):
public ActionResult Index()
{
BreazEntities entities = new BreazEntities();
Document document = new Document { Id = 1 };
entities.Documents.Attach(document);
document.Active = false;
entities.SaveChanges();
return View();
}
6)将活动标志放回1
7)在Visual Studio 2013中添加新的解决方案和项目。Web,.NET Framework 4.5.1名为EF6Fails的ASP.NET WebApplication,下一个向导页面MVC,将身份验证更改为无身份验证。在程序包管理器控制台中:卸载程序包EntityFramework -project ef6fails -force,然后安装程序包EntityFramework -version 6.1.3 -project ef6fails
8)将ef6fails中的edmx添加到Document表中。
9)在控制器中运行以下代码,并在调用视图之前放置一个断点:
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();
您要指出的是EF 4.1ObjectContext
和EF 6(实际上是4.1和更高版本)之间在代码生成方面的区别DbContext
。
在ObjectContext
API中,一个数据库字段(如Active
)将生成不少于此的代码:
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Boolean Active
{
get
{
return _Active;
}
set
{
OnActiveChanging(value);
ReportPropertyChanging("Active");
_Active = StructuralObject.SetValidValue(value);
ReportPropertyChanged("Active");
OnActiveChanged();
}
}
private global::System.Boolean _Active;
partial void OnActiveChanging(global::System.Boolean value);
partial void OnActiveChanged();
这意味着,EF的更改跟踪器将立即被通知每个属性更改。
该DbContext
API不仅改变了对开发人员更友好的API,而且改变了更简单的类模型,并转向了真正的持久性无知。我相信,一开始仍然会生成此自我跟踪代码,但最终,它会被放弃,而数据库字段将由一个简单的生成的自动属性来表示:
public bool Active { get; set; }
(毫无疑问,这样做也是为了在代码优先和数据库优先方法的基础上建立一个统一的代码库)。
不可避免地,这会使变更跟踪程序承担更多责任。它必须检测更改,而不是仅注册更改。因此,更改跟踪器方法“随时”DetectChanges
执行。
回到您的代码。
在“旧” ObjectContext
API中...
document.Active = false;
...将立即通知变更跟踪器该属性已设置。即使已经是错误的,UPDATE
也会发出SaveChanges
。
在DbContext
API中,更改跟踪器将永远不会将其检测为更改,因为Active
已经具有booleans的默认值false
。没什么变化。
简而言之,它曾经是“您设置的是您更新的内容”,后来变成了“您更改的是您更新的内容”。
您可能想回到原来的状态。
那你呢
尝试稍微改变视角。假设您先进行代码工作,是否会像在第一个代码片段中那样编写属性代码?你真的吗?首先,这是紧密耦合,没有单一责任。在断开连接的情况下(即重新连接反序列化的实体),可能会导致许多不必要的更新。
但是,即使您将编写(或生成)类似的代码,EF也不会监听更改。您必须自己在上下文中为物化实体预订一些变更传播代码。它不再是内置的,除非您返回到ObjectContext
API(您不希望这样做)。
我会说:忍受它。您输了一些,但赢了很多(更多的SOLID代码)。习惯于控制数据库中的更新内容和未更新的内容。您可能希望Active
在实体的构造函数中将true设置为默认值,因此更改跟踪器会注意到对的更改false
。
但是我不认为开发人员会忘记它是一个有效的论点。开发人员应该具有灵活性。世界一直在变化,不能与时俱进。如果他们记得包括EF特定的语句Attach
(管理实体状态),为什么不管理属性状态的语句呢?
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句