内容简介:有一定的背景要通过这一个 – 请忍受我!我们使用EF的n层WPF应用程序 – 我们通过dbContext将数据从数据库加载到POCO类中. dbContext被破坏,用户可以编辑数据.我们使用Julie Lerman在“编程实体框架:DBContext”一书中建议的“国画”,以便当我们将根实体添加到新的dbContext进行保存时,我们可以设置每个子实体是添加,修改还是保持不变. .
有一定的背景要通过这一个 – 请忍受我!
我们使用EF的n层WPF应用程序 – 我们通过dbContext将数据从数据库加载到POCO类中. dbContext被破坏,用户可以编辑数据.
我们使用Julie Lerman在“编程实体框架:DBContext”一书中建议的“国画”,以便当我们将根实体添加到新的dbContext进行保存时,我们可以设置每个子实体是添加,修改还是保持不变. .
当我们第一次做到这一点(2012年11月!)发生的问题是,如果我们添加到dbContext的根实体具有相同子实体的多个实例(即,与用户链接的“任务”记录, “状态历史”也链接到相同的用户),进程将失败,因为即使子实体相同(从同一数据库行),它们被赋予不同的哈希码,因此EF将它们识别为不同的对象.
我们修复了这一点(2012年12月!),通过在实体上覆盖GetHashCode,如果实体来自数据库,则返回数据库ID,如果实体尚未保存,则返回唯一的负数.现在,当我们将根实体添加到dbContext时,它很聪明,足以实现同一个子实体被多次添加,并且它正确处理.自2012年12月以来,这一直都很好,直到我们上周升级到EF6
EF6的新功能之一就是它现在使用自己的Equals和GetHashCode方法执行变更跟踪任务,忽略任何自定义覆盖.请参阅: http://msdn.microsoft.com/en-us/magazine/dn532202.aspx (搜索“较少干扰您的编码风格”).如果您期望EF管理变更跟踪,但是在一个不连接的n层应用程序中,我们不希望这样做,这实际上这会打破我们一年以来一直工作正常的代码,这是非常好的.
希望这是有道理的.
现在 – 问题 – 有没有人知道任何方式,我们可以告诉EF6使用我们的GetHashCode和Equals方法,就像在EF5中一样,或者有人有更好的方法来处理将根实体添加到具有重复的子实体的dbContext在这里,EF6会很高兴吗?
感谢任何帮助.对不起,长篇文章
更新
在EF代码中戳了一下,它看起来像是通过获取实体的哈希码来设置的InternalEntityEntry(dbEntityEntry)的哈希码,但现在在EF6中使用RuntimeHelpers.GetHashCode(_entity)来检索,这意味着我们重写的哈希码对实体被忽略.所以我想让EF6使用我们的哈希码是不成问题的,所以也许我需要集中在如何添加一个实体到上下文可能有重复的子实体,而不会扰乱EF.有什么建议么?
更新2
最令人讨厌的事情是,功能的这种变化被报告为一件好事,而不是像我看到的那样,是一个突破性的变化!当然,如果你有断开连接的实体,并且你已经加载了.AsNoTracking()来执行性能(因为我们知道我们会断开连接,所以为什么要跟踪它们),那么dbContext就没有理由来覆盖我们的getHashcode方法!
更新3
感谢所有的意见和建议 – 非常感谢!
经过一些实验,它似乎与.AsNoTracking()有关.如果您使用.AsNoTracking()重载子实体加载数据,则内存中具有不同的对象(具有不同的哈希码),因此有一个问题状态绘制并稍后保存.我们通过覆盖哈希码更早地解决了这个问题,所以当实体被添加回保存上下文中时,重复的实体被识别为相同的对象,并且只添加一次,但是我们再也不能用EF6做这个了.所以现在我需要进一步调查我们为什么使用.AsNoTracking()在第一位.
另一个想法是,也许EF6的变更跟踪器应该只使用自己的哈希码生成方法来进行跟踪,如果实体已经加载了.AsNoTracking()可能应该使用来自底层实体的哈希码?
更新4
所以现在我们已经确定我们不能继续使用我们在EF6中的方法(覆盖的hashCodes和.AsNoTracking),我们应该如何管理不连接的实体的更新?我用blogposts / comments / authors创建了这个简单的例子:
在这个示例中,我想打开blogpost 1,更改内容和作者,然后再次保存.我已经尝试了3种方法与EF6,我无法得到它的工作:
BlogPost blogpost;
using (TestEntities te = new TestEntities())
{
te.Configuration.ProxyCreationEnabled = false;
te.Configuration.LazyLoadingEnabled = false;
//retrieve blog post 1, with all comments and authors
//(so we can display the entire record on the UI while we are disconnected)
blogpost = te.BlogPosts
.Include(i => i.Comments.Select(j => j.Author))
.SingleOrDefault(i => i.ID == 1);
}
//change the content
blogpost.Content = "New content " + DateTime.Now.ToString("HH:mm:ss");
//also want to change the author from Fred (2) to John (1)
//attempt 1 - try changing ID? - doesn't work (change is ignored)
//blogpost.AuthorID = 1;
//attempt 2 - try loading the author from the database? - doesn't work (Multiplicity constraint violated error on Author)
//using (TestEntities te = new TestEntities())
//{
// te.Configuration.ProxyCreationEnabled = false;
// te.Configuration.LazyLoadingEnabled = false;
// blogpost.AuthorID = 1;
// blogpost.Author = te.Authors.SingleOrDefault(i => i.ID == 1);
//}
//attempt 3 - try selecting the author already linked to the blogpost comment? - doesn't work (key values conflict during state painting)
//blogpost.Author = blogpost.Comments.First(i => i.AuthorID == 1).Author;
//blogpost.AuthorID = 1;
//attempt to save
using (TestEntities te = new TestEntities())
{
te.Configuration.ProxyCreationEnabled = false;
te.Configuration.LazyLoadingEnabled = false;
te.Set<BlogPost>().Add(blogpost); // <-- (2) multiplicity error thrown here
//paint the state ("unchanged" for everything except the blogpost which should be "modified")
foreach (var entry in te.ChangeTracker.Entries())
{
if (entry.Entity is BlogPost)
entry.State = EntityState.Modified;
else
entry.State = EntityState.Unchanged; // <-- (3) key conflict error thrown here
}
//finished state painting, save changes
te.SaveChanges();
}
如果您在EF5中使用此代码,请使用我们现有的方法将.AsNoTracking()添加到原始查询中.
blogpost = te.BlogPosts
.AsNoTracking()
.Include(i => i.Comments.Select(j => j.Author))
.SingleOrDefault(i => i.ID == 1);
并覆盖实体上的GetHashCode和Equals(例如,在BlogPost实体中)..
public override int GetHashCode()
{
return this.ID;
}
public override bool Equals(object obj)
{
BlogPost tmp = obj as BlogPost;
if (tmp == null) return false;
return this.GetHashCode() == tmp.GetHashCode();
}
代码中的所有三种方法现在都可以正常工作.
请问可以告诉我如何在EF6中实现这一点?谢谢
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- c# – 实体框架以错误的顺序插入子对象
- c# – 实体框架LINQ不包含不区分大小写
- tsql – 实体框架4:所选存储过程不返回任何列
- c# – 使用实体框架代码中的SQL视图第一版本5
- EF架构~FluentValidation实体检验与实体分离了
- 表单 – 如何使用实体列表(CRUD)从模板中删除实体?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
测试驱动的JavaScript开发
Christian Johansen / 赵勇、程德、凌杰、高博 / 机械工业出版社 / 2012-2-9 / 69.00元
本书是一本完整的、基于最佳实践的JavaScript敏捷测试指南,同时又有着测试驱动开发方法(TDD)所带来的质量保证。领先一步的JavaScript敏捷开发者Christian Johansen的讨论涵盖了将最先进的自动化测试用于JavaScript开发环境的方方面面,带领读者走查整个开发的生命周期,从项目启动到应用程序部署。本书的主要内容包括:掌握自动化测试和TDD;构建有效的自动化测试工作流......一起来看看 《测试驱动的JavaScript开发》 这本书的介绍吧!