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


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


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

分享到:
评论

相关推荐

    NHibernate 实体类和配置文件生成模板

    CodeSmith 是一个模板驱动的代码生成工具,它允许用户通过自定义模板来生成各种代码,包括但不限于数据库访问层、业务逻辑层和实体类。通过使用此模板,开发者可以节省大量的手动编码时间,专注于业务逻辑的实现,...

    根据NHibernate实体生成简单控件

    在这个主题中,“根据NHibernate实体生成简单控件”指的是利用NHibernate定义的实体类来创建用户界面中的控件,如文本框、下拉列表等,以便于数据的展示和输入。这种方式可以极大地提高开发效率,避免手动为每个实体...

    NHibernate2.0 实体类和配置文件生成模板

    总结来说,"NHibernate2.0 实体类和配置文件生成模板"是CodeSmith工具的一个应用实例,它简化了基于NHibernate的.NET项目中实体类和配置文件的创建过程,提升了开发效率。理解并熟练使用这些模板,有助于提升开发者...

    Nhibernate从映射文件生成实体类和sql建表脚本的程序

    2. 一致性保证:映射文件确保了数据库表结构和实体类的一致性,减少错误。 3. 可维护性:当数据库结构发生变化时,只需更新映射文件,然后重新生成代码即可。 在实际应用中,开发者需要了解如何配置和使用`Hbm2...

    nhibernate映射类代码生成器

    然而,手动编写每个实体类的映射文件(.hbm.xml)或使用特性注解(.NET 4.0及以后版本)会消耗大量时间。这就是“nhibernate映射类代码生成器”发挥作用的地方。 这个代码生成器的主要目标是自动化创建与数据库表...

    Nhibernate代码生成模板v1_1.rar

    "NHibernate代码生成模板v1_1"着重于修复了v1.0版本的一个主要问题,即在处理复合主键时,实体类在运行时会引发Nhibernate错误。在数据库设计中,复合主键是指由两个或更多列共同组成的唯一标识符。在ORM框架中,...

    C#自动生成实体类

    在IT行业中,实体类是软件开发中的重要组成部分,特别是在基于对象的编程语言如C#中。实体类通常代表数据库中的表,它们封装了数据并提供了操作这些数据的方法。手动创建和维护这些实体类可能会非常耗时,尤其是在...

    自动生成实体类....

    例如,Entity Framework的`Scaffold-DbContext`命令行工具可以自动从数据库创建上下文类和实体类。只需运行以下命令,替换合适的连接字符串和数据库提供者: ```bash dotnet ef dbcontext scaffold "Server=...

    数据库表的实体类生成工具

    通过使用这类生成工具,开发人员可以从数据库中读取表结构信息,一键生成对应的实体类,这些类可以直接被ORM框架如Entity Framework或NHibernate使用,实现数据访问层的快速构建。 工具的主要功能包括: 1. 单表...

    NHibernate2.0中文文档

    3. **实体类映射**:理解如何使用Hibernate的注解或XML映射文件将C#类映射到数据库表。 4. **会话管理**:掌握Session接口的使用,它是与数据库交互的主要接口,负责保存、加载和更新对象。 5. **事务处理**:学习...

    Nhibernate代码生成器

    **Nhibernate代码生成器** 是一个工具,它的主要功能是自动生成Nhibernate实体类和映射文件,从而极大地简化了开发过程。在使用Nhibernate进行对象关系映射(ORM)时,手动创建每个实体类和对应的映射文件是一项繁琐...

    实体类生成工具(很实用的工具)

    在ASP.NET和C#环境中,实体类生成器通常会集成在开发环境中,如Visual Studio,通过ORM(对象关系映射)框架如Entity Framework或NHibernate来工作。这些工具能够根据数据库中的表结构自动生成对应的C#类,类中的...

    Nhibernate使用教程中文文档

    1. **映射文件**: 使用XML(如`hibernate-mapping`)或Fluent NHibernate进行实体类与数据库表之间的映射。 2. **标识符**: 设置主键,可以使用自动增长、自定义ID生成器等策略。 3. **属性映射**: 包括字段类型、...

    nhibernate 由类文件,映射文件自动生成表的 源代码

    在标题和描述中提到的“nhibernate 由类文件,映射文件自动生成表的 源代码”,指的是使用NHibernate的SchemaExport工具或编程方式,根据定义的类和映射文件自动创建数据库表的机制。以下是对这个主题的详细解释: ...

    实体类代码生成器

    在C#中,为了实现更高效的数据访问,实体类通常会配合ORM(对象关系映射)框架,如Entity Framework或NHibernate使用。这些框架允许开发者以面向对象的方式操作数据库,而无需编写大量的SQL语句。实体类生成器在生成...

    NHibernate中文帮助手册API

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

    C# 实体类代码 生成器

    C#实体类代码生成器是一种工具,用于自动化创建C#编程中的数据模型类,也称为实体类。在软件开发中,尤其是涉及到数据库交互时,实体类是必不可少的一部分,它们代表了数据库表中的记录,提供了与数据库对象进行交互...

    NHibernate 中文文档教程

    9. **事件和拦截器**: NHibernate提供了一套事件系统和拦截器,允许在特定操作(如对象加载、保存、更新、删除等)前后插入自定义代码。 10. **版本控制**: NHibernate支持乐观锁和悲观锁,以防止并发访问时的数据...

    CodeSmith中的Nhibernate模板

    `NHibernate_VirtualEntity.cst`模板可能是一个扩展或增强版的实体类模板,其中的"Virtual"通常意味着属性使用了虚方法(virtual),这在Nhibernate的懒加载(Lazy Loading)机制中很重要。当实体的某个属性标记为...

    生成Nhibernate的类库和映射文件的codesmith模板

    例如,实体类的属性名称、类型和映射文件中的字段映射是动态的,而类名、文件名等可能是固定的。 - 编写模板语言代码,如使用Emit或Expression语法,来定义模板的生成规则。 - 测试模板,通过提供不同的输入(如...

Global site tag (gtag.js) - Google Analytics