C# 实体框架-GetHashCode中的子对象为null
实体框架6 MVC5 我是EF和MVC的新手,我有一个场景,我有一个覆盖Equals和GetHashCode的类: EF代码:C# 实体框架-GetHashCode中的子对象为null,c#,asp.net-mvc,entity-framework,C#,Asp.net Mvc,Entity Framework,实体框架6 MVC5 我是EF和MVC的新手,我有一个场景,我有一个覆盖Equals和GetHashCode的类: EF代码: public partial class ProdCategory { public long ProdID { get; set; } public int CategoryID { get; set; } public bool PermanentlyDelete { get; set; } public System.DateTim
public partial class ProdCategory
{
public long ProdID { get; set; }
public int CategoryID { get; set; }
public bool PermanentlyDelete { get; set; }
public System.DateTime DateCreated { get; set; }
public virtual Category Category { get; set; }
public virtual Product Product { get; set; }
}
我的代码:
public override bool Equals(object obj)
{
if (obj == null | (!object.ReferenceEquals(this.GetType(), obj.GetType())))
{
return false;
}
ProdCategory p = (ProdCategory)obj;
if (this.Category == p.Category && this.Product == p.Product)
{
return true;
}
return false;
}
public override int GetHashCode()
{
unchecked
{
var result = 0;
result = (result * 397).GetHashCode() ^ this.Product.GetHashCode();
result = (result * 397).GetHashCode() ^ this.Category.GetHashCode();
return result;
}
}
该类成为产品的子对象,当我转到产品列表查看GetHashCode错误时
Heisenberg.dll中发生“System.NullReferenceException”类型的异常,但未在用户代码中处理
我认为这可能是一个延迟加载问题,但是产品对象存在于GetHashCode函数中,所以我假设如果存在,那么类别应该是。。?我试图使用以下命令强制加载prodCategory:
var products = db.Products.Include(p => p.ProdCategories);
但这没什么区别。因此,我认为我需要在ProdCategory中强制加载该类别,但我无法计算出该类别的语法
作为测试,我注释掉了GetHashCode函数-页面加载正常,我可以转到产品的详细信息视图并查看prodCategory详细信息,因此它确实会在某个时候填充。这就是我被抛下的原因!不知道还可以尝试什么
我希望有人能看出我错在哪里
更新:
如果我在GetHashCode中设置了一个断点——当它第一次命中它时,Product被填充,Category为null。如果我不运行分类行并继续,断点将再次命中。这一次将同时填充产品和类别
有人能解释一下发生了什么,bst的行动方针是什么吗?我可以在GetHashCode中检查是否为null,但它确实不应该为null,我只是隐藏了错误。无论如何,您应该根据外键执行
GetHashCode
public override int GetHashCode()
{
unchecked
{
var result = this.ProdID.GetHashCode();
result = (result * 397) ^ this.CategoryID;
return result;
}
}
永远不会设置外部id(假设该项是从数据库“获取”的),这是因为外部id位于行本身(因此不需要联接)。为了解决第一次实例化对象时哈希代码出错的问题,我将这样做
public partial class ProdCategory
{
protected ProdCategory() {} //protected default constructor is required by EF
public ProdCategory(Category category, Product product)
{
this.Category = category;
this.Product = product;
this.ProdID = product.Id;
this.CategoryID = category.Id;
}
public long ProdID { get; protected set; }
public int CategoryID { get; protected set; }
public bool PermanentlyDelete { get; set; }
public System.DateTime DateCreated { get; set; }
public virtual Category Category { get; protected set; }
public virtual Product Product { get; protected set; }
}
ProdCategory
做什么?它看起来只是一个关联,在这种情况下,它不应该存在于域模型中。它包含其他属性,如MarkForDelete。第一个问题是:为什么需要Hashcode?您只能将其用于内存中的对象,而不能用于针对数据库的LINQ查询,而我认为它是在LINQ查询中进行排序和比较的。在该项目中创建重写的equals时,我被告知应该始终更改GetHasCode函数以进行匹配,因为“Equal”对象应该始终具有相同的hashcode?是否有任何代码需要显式或隐式地比较ProdCategory
实例(例如,隐式使用就是拥有Dictionary>
)。好的-也许这是编写GetHashCode函数的更好方法(这更好的原因是什么?),但它仍然无法解释为什么最初不填充Category。它只是隐藏了事实,因为ID是0。在我的模型中,0不是有效值。@Rick未填充类别/产品的原因是您使用的是实际的ProdCategory
,而不是ProdCategory
的EF代理。因此EF无法将延迟加载代码注入虚拟属性getter。总的来说,依赖延迟加载导致的问题比它真正解决的问题还要多。此外,使用可能涉及到数据库往返的GetHashCode
函数也不是很明智(GetHashCode
应该尽可能地提高性能,这就是它的全部要点)。我也不会使用非常可能的可变数据(如外键ID)定义GetHashCode
。。。除非ProdID
和CategoryID
都是主键,否则我只能将其保留在ProdID
上。。。再说一次,这种设计对我来说没有意义(为什么不是每个产品都有自己的id,独立于类别?)哦,我看到这是一个关联表。。。然后可以同时使用ProdID
和CategoryID
。。。但是仅仅拥有这个关联表并没有多大意义。。。它有哪些需要的特性?为什么要“标记以删除关联”?如果是这种情况,您可以在产品
或类别
中执行此操作,只需将关联设置为类别
或产品
为空即可。使用ORM的一个要点是,您可以去掉这些“样板”表格。@Aron哦,是的,他并没有对您的答案发表评论,这正是问题的关键所在(我现在将向上投票)。。。只是质疑OP的设计决策。