c# – 实体框架6 – 使用我的getHashCode()

栏目: ASP.NET · 发布时间: 5年前

内容简介:有一定的背景要通过这一个 – 请忍受我!我们使用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中实现这一点?谢谢


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

大型分布式网站架构设计与实践

大型分布式网站架构设计与实践

陈康贤 / 电子工业出版社 / 2014-9-1 / 79.00元

《大型分布式网站架构设计与实践》主要介绍了大型分布式网站架构所涉及的一些技术细节,包括SOA架构的实现、互联网安全架构、构建分布式网站所依赖的基础设施、系统稳定性保障和海量数据分析等内容;深入地讲述了大型分布式网站架构设计的核心原理,并通过一些架构设计的典型案例,帮助读者了解大型分布式网站设计的一些常见场景及遇到的问题。 作者结合自己在阿里巴巴及淘宝网的实际工作经历展开论述。《大型分布式网站......一起来看看 《大型分布式网站架构设计与实践》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具