`
yyw84
  • 浏览: 78787 次
社区版块
存档分类
最新评论
阅读更多


        在正常的对象操作中,当两个对象都是通过 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() 的解释: 

4.3. 实现equals()hashCode()如果你需要混合使用持久化类(比如,在一个Set中),你必须重载equals() 和 hashCode()方法。

这仅适用于那些在两个不同的Session中装载的对象,Hibernate在单个Session中仅保证JVM 辨别( a == b ,equals()的默认实现)!

就算两个对象a和b实际是同一行数据库内容(它们拥有同样的主键值作为辨识符),我们也不能保证在特定的Session 之外它们是同一个Java实例。

最显而易见的实现equals()/hashCode()方法的办法就是比较两个对象的标识值。如果这个值是同堂的,他们必定是直线同一条数据库行,所以它们是相等的(如果都被加入到Set,在Set中只应该出现一个元素)。不幸的是,我们不能使用这种办法。Hibernate只会对已经持久化的对象赋予标识值,新创建的实例将不会有任何标识符值!我们推荐使用商业关键字相等原则来实现equals()和hashCode()。

商业关键字相等意味着equals()方法只比较那些组成商业关键字的属性,它对应着真实世界中的实例(自然的候选关键字)


下面是实现方法(该方法出自 http://cs.nerdbank.net/blogs/jmpinline/archive/2006/01/24/126.aspx ):

/**//// <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)
{
    ClassNameHere other 
= obj as ClassNameHere;
    
if (other == nullreturn false;
    
if (Id == 0 && other.Id == 0)
        
return (object)this == other;
    
else
        
return Id == other.Id;
}


public override int GetHashCode()
{
    
if (Id == 0return base.GetHashCode();
    
string stringRepresentation = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "#" + Id.ToString(); return stringRepresentation.GetHashCode();
}

伴随着 .NET 2.0 的发布,加入了泛型代码中 default 关键字,我们可以把 snippet  做得更加通用而不仅限于 Int 数据类型,

<?xml version="1.0" encoding="utf-8" ?>
<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 模板中了,添加的内容如下:

Equals and GetHashCode#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)
{
    
<%= ClassName(SourceTable) %> other = obj as <%= ClassName(SourceTable) %>;

    
if (other == null)
        
return false;

    
if (<%= IdName(SourceTable) %> == default(<%= IdMemberType(SourceTable) %>&& other.<%= IdName(SourceTable) %> == default(<%= IdMemberType(SourceTable) %>))
        
return (object)this == other;
    
else
        
return <%= IdName(SourceTable) %> == other.<%= IdName(SourceTable) %>;
}


public override int GetHashCode()
{
    
if (<%= IdName(SourceTable) %> == default(<%= IdMemberType(SourceTable) %>))
        
return base.GetHashCode();

    
string stringRepresentation = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "#" + <%= IdName(SourceTable) %>.ToString();
    
return stringRepresentation.GetHashCode();
}


#endregion
 


事情都已经做到这个份上也该收场了,虽然只是一些小技巧,也希望能给大家带来方便,提高生产效率。。。 :)

分享到:
评论

相关推荐

    C#数据库表转实体类

    例如,添加属性验证规则、自定义导航属性(关联其他表的实体)、重写Equals和GetHashCode方法以支持对象比较等。 5. **Repository模式**:为了进一步解耦数据访问层和业务逻辑层,我们可以采用Repository模式。...

    NHibernate中文帮助手册API

    实现 Equals() 和 GetHashCode() 方法  4.4. 持久化生命周期(Lifecycle)中的回调(Callbacks)  4.5. 合法性验证(IValidatable)回调  5. 对象/关系数据库映射基础(Basic O/R Mapping)  5.1. 映射定义...

    nhibernate2.1.2帮助

    - **对象比较**:重写Equals()和GetHashCode()方法以支持对象的比较和散列计算。 ##### 4.4 动态模型 - **动态类型**:使用动态类型来简化对象的创建和操作。 ##### 4.5 Tuplizers - **对象转换**:Tuplizer用于将...

    nhibernate reference

    - **4.3 实现 Equals() 和 GetHashCode()**:说明了为什么实体类应该重写这两个方法,并给出了正确的实现方式。 - **4.4 生命周期回调**:列举了 NHibernate 支持的几种生命周期事件回调,如 onPreInsert、...

    nhibernate_reference.pdf

    3. **实现 Equals() 和 GetHashCode() 方法**:为了确保实体类能正确地进行相等性比较和散列。 4. **生命周期回调**:探讨了如何利用 NHibernate 提供的事件回调机制。 5. **IValidatable 回调**:介绍了一种验证...

    nhibernate

    **4.3 实现Equals()和GetHashCode()方法** 为了确保NHibernate能够正确识别相同的对象实例,需要正确地重写这两个方法。这部分内容详细介绍了如何实现以及为什么这么做很重要。 **4.4 动态模型** 动态模型允许在...

    NHibernate中文帮组文档(2008.11月更新)

    4.3. 实现 Equals() 和 GetHashCode() 方法 4.4. 持久化生命周期(Lifecycle)中的回调(Callbacks) 4.5. 合法性验证(IValidatable)回调 5. 对象/关系数据库映射基础(Basic O/R Mapping) 5.1. 映射定义(Mapping...

    NHibernate Documentation

    实现Equals()和GetHashCode() 为了确保实体的正确比较和哈希计算,需要重写这两个方法。 #### 4.4. 生命周期回调 生命周期回调允许在实体生命周期的不同阶段执行特定的操作,如初始化、加载等。 #### 4.5. ...

    VB/C#.Net实体代码生成工具

    在实际开发中,当数据库结构发生变化时,通过此工具可以快速更新相关的实体类,避免手动修改大量代码,节省了大量的时间和精力。 使用【VB/C#.Net实体代码生成工具】,开发者可以指定连接到的数据库,选择需要生成...

    NHibernate参考文档 2.0.0 chm

    4.3. 实现 Equals() 和 GetHashCode() 方法 4.4. 持久化生命周期(Lifecycle)中的回调(Callbacks) 4.5. 合法性验证(IValidatable)回调 5. 对象/关系数据库映射基础(Basic O/R Mapping) 5.1. 映射定义(Mapping...

    CodeSmith(Templates)

    开发者可以通过这个模板自定义实体类的属性(对应数据库字段),并实现如ToString、Equals、GetHashCode等方法。 3. **AutoEntity.cst**:这个名字暗示这可能是一个自动化的实体生成模板,可能包含了更复杂的逻辑,...

Global site tag (gtag.js) - Google Analytics