在正常的对象操作中,当两个对象都是通过 new 或者其它方式创建出来,尽管它们在属性和行为上是一致的,但我们还是得承认他们是属于不同的两个事物,就像现实世界中的单卵双生的双胞胎虽然各方面都很像,但他们到底还是属于不同的个体。但当这种情况发生在 NHibernate(以下简称NH), 实休类中时,我们就不能这么草率地下结论了,通常实体类中每个实例映射着数据库表中的一行记录,我们知道一个良好设计的数据库表字段中一个唯一标识是必不可少的,那就是主键,主键相当于每个公民的身份证号,必须是唯一且无重复的,不管运行多少次 select * from table where id = @id ,只要 @id 值不改变我们就认为查询出来的是同一行记录,同样的道理映射到实体类中也是主键的属性值相等我们就应该承认它们是相等的,一张身份证它可以有多个复印件,但不管怎样它都是属于同一个人的。
由于 System.Object 中是通过 Equals() 方法来确定两个对象是否相等,因为 Equals() 方法中两个对象具有相同的“值”,那么即使它们不是同一实例,这样的 Equals 实现仍返回 true。两个相同的对象它的 GetHashCode() 结果也必须是相等的,在 MSDN 上也明确指出,“重写 Equals 的类型也必须重写 GetHashCode;否则,Hashtable 可能不正常工作。”“重写 GetHashCode 的派生类还必须重写 Equals,以保证被视为相等的两个对象具有相同的哈希代码;否则,Hashtable 可能不会正常工作。”
下面是引用 Hibernate参考文档 第4章 中对 实现equals()和hashCode() 的解释:
下面是实现方法(该方法出自 http://cs.nerdbank.net/blogs/jmpinline/archive/2006/01/24/126.aspx ):
/// Tests whether this and another object are equal in a way that
/// will still pass when proxy objects are being used.
/// </summary>
public override bool Equals(object obj)
{
ClassNameHere other = obj as ClassNameHere;
if (other == null) return false;
if (Id == 0 && other.Id == 0)
return (object)this == other;
else
return Id == other.Id;
}
public override int GetHashCode()
{
if (Id == 0) return base.GetHashCode();
string stringRepresentation = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "#" + Id.ToString(); return stringRepresentation.GetHashCode();
}
伴随着 .NET 2.0 的发布,加入了泛型代码中 default 关键字,我们可以把 snippet 做得更加通用而不仅限于 Int 数据类型,
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>Entity Equals and GetHashCode</Title>
<Shortcut>nheq</Shortcut>
<Author>yyw</Author>
<HelpUrl>
http://www.cnblogs.com/yyw84/archive/2006/09/17/506695.html
http://cs.nerdbank.net/blogs/jmpinline/archive/2006/01/24/126.aspx
</HelpUrl>
<Description></Description>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
<Description>Inserts the Equals and GetHashCode methods that NHibernate requires to run correctly.</Description>
</Header>
<Snippet>
<Declarations>
<Literal Editable="true">
<ID>type</ID>
<ToolTip>The name of the class being injected.</ToolTip>
<Default>ClassName</Default>
</Literal>
<Literal>
<ID>id</ID>
<ToolTip>主键ID</ToolTip>
<Default>Id</Default>
</Literal>
<Literal>
<ID>idtype</ID>
<ToolTip>主键属性类型</ToolTip>
<Default>int</Default>
</Literal>
</Declarations>
<Code Language="CSharp">
<![CDATA[#region Equals and GetHashCode
/// <summary>
/// Tests whether this and another object are equal in a way that
/// will still pass when proxy objects are being used.
/// </summary>
public override bool Equals(object obj)
{
$type$ other = obj as $type$;
if (other == null)
return false;
if ($id$== default($idtype$) && other.$id$ == default($idtype$))
return (object)this == other;
else
return $id$ == other.$id$;
}
public override int GetHashCode()
{
if ($id$ == default($idtype$))
return base.GetHashCode();
string stringRepresentation = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "#" + $id$.ToString();
return stringRepresentation.GetHashCode();
}
#endregion
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
为了做到一劳永逸,接下来要做的事就是把它添加到我的 CodeSmith 模板中了,添加的内容如下:
事情都已经做到这个份上也该收场了,虽然只是一些小技巧,也希望能给大家带来方便,提高生产效率。。。 :)