使用NHibernate实现一对多,多对一的关联很是简单,可如果要用复合主键实现确实让人有些淡淡的疼。虽然很淡疼但还是要去抹平这个坑,在下不才,愿意尝试。

以示例进入正文,源码下载地址

一、数据表关系图

很明显,他是一个自引用数表,实现无限级树结构的存储。

二、关键步骤

  • 注解如何实现复合主键

根据官方文档说明,联合主键最好是一个独立的类,需要重载Equals和GetHashCode方法,且标记为可序列化。代码如下:

[Serializable]
public class BaseInfo
{
public virtual string Id { get; set; }
public virtual string GroupNumber { get; set; } public override bool Equals(object obj)
{
var baseInfo = obj as BaseInfo;
if (baseInfo == null)
{
return false;
} return baseInfo.Id == this.Id && baseInfo.GroupNumber == this.GroupNumber;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
  • 子类配置好联合主键
[CompositeId(, Name = "BN")]
[KeyProperty(, Name = "Id", Column = "Id", TypeType = typeof(string))]
[KeyProperty(, Name = "GroupNumber", Column = "GroupNumber", TypeType = typeof(string))]
public virtual BaseInfo BN { get; set; }

说明:
1.实现为引用BaseInfo类,而不是继承.

  • 实现一对 和 多对一的映射

这步没有多大难度,主要处理好注解的顺序即可,以及OneToMany时联合主键如何设置的问题.示例代码如下:

[Bag(, Name = "Childs", Cascade = "all", Lazy = CollectionLazy.False, Inverse = true)]
[Key()]
[Column(, Name = "ParentId")]
[Column(, Name = "GroupNumber")]
[OneToMany(, ClassType = typeof(Foo))]
public virtual IList<Foo> Childs { get; set; } [ManyToOne(, Name = "Parent", ClassType = typeof(Foo))]
[Column(, Name = "ParentId")]
[Column(, Name = "GroupNumber")]
public virtual Foo Parent { get; set; }

三、出错了,有Bug

  • childs没有数据

重载的GetHashCode方法有问题,返回值应该是联合主键HashCode,优化后的实现如下:

public override int GetHashCode()
{
return (this.Id + "|" + this.GroupNumber).GetHashCode(); //判断缓存是否存在,已此作为Key
}
  • 插入数据时报错,提示SqlParameterCollection的索引无效[索引溢出错误]

原因,最初在设计Parent的时候,与联合主键共用了一个字段GroupNumber,导致在NHibernate做映射转换的时候会多计算出一个需要填充的值,但SqlParameterCollection中又少一个位置。优化代码如下:

//外键与联合主键不要共用字段
[ManyToOne(, Name = "Parent", ClassType = typeof(Foo))]
[Column(, Name = "ParentId")]
[Column(, Name = "ParentGroupNumber")]
public virtual Foo Parent { get; set; }

说明:
1.由于联合外键与联合主键共用了一个字段,导致映射出错

四、终于实现了,总结

  • 类都必须可以序列化,也就是要还serializable标注
  • 继承BaseInfo实现联合主键(不推荐使用)

在Save时,如果用session.merge方法组合缓存与修改对象,返回值的主键会为Null

  • 联合主键与联合外键字段不能重复,也不能共用
  • 注意重载的GetHashCode和Equals方法
  • GetHashCode返回实例的惟一标识
  • Equals判断是否相同实例的具体实现

NHibernate联合主键详细示例的更多相关文章

  1. NHibernate composite-id联合主键配置

    NHibernate的联合主键配置比较复杂,初次配置可能需要花些时间,但只要我们理解了,掌握一定的步骤还是很容易的. 1.设计数据结构 Users:用户表 名称 Users 说明 用户表 序号 字段名 ...

  2. NHibernate 映射基础(第三篇) 简单映射、联合主键

    NHibernate 映射基础(第三篇) 简单映射.联合主键 NHibernate完全靠配置文件获取其所需的一切信息,其中映射文件,是其获取数据库与C#程序关系的所有信息来源. 一.简单映射 下面先来 ...

  3. Hibernate(5)—— 联合主键 、一对一关联关系映射(xml和注解) 和 领域驱动设计

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的知识点总结如下: One to One 映射关系 一对一单向外键(XML/Annotation) 一对一双向外键关联(XML/A ...

  4. SQL联合主键 查重

    2014年最后一天,今天在给数据库导入数据的时候,遇到一个问题,就是联合主键去重. 事情是这样的,现有一个表M,我想找个表中导入了许多数据,并需要将字段A(int)和B(int)联合设置为主键. 但是 ...

  5. Hibernate注解映射联合主键的三种主要方式

    今天在做项目的时候,一个中间表没有主键,所有在创建实体的时候也未加组件,结果报以下错误: org.springframework.beans.factory.BeanCreationException ...

  6. 联合主键用Hibernate注解映射的三种方式

    第一.将联合主键的字段单独放在一个类中,该类需要实现java.io.Serializable接口并重写equals和hascode,再将该类注解为@Embeddable,最后在主类中(该类不包含联合主 ...

  7. EntityFramework中Mapper怎么定义联合主键?

    HasKey(m => new { m.StoreId, m.CarTypeId, m.CarLevel}) 用“new {}”联合主键以“,”分隔形式定义

  8. SQL Server中的联合主键、聚集索引、非聚集索引、mysql 联合索引

    我们都知道在一个表中当需要2列以上才能确定记录的唯一性的时候,就需要用到联合主键,当建立联合主键以后,在查询数据的时候性能就会有很大的提升,不过并不是对联合主键的任何列单独查询的时候性能都会提升,但我 ...

  9. sql,联合主键,按id分组求版本号最大值的集合

    表结构如下: /* SQLyog v10.2 MySQL - 5.5.39 ************************************************************** ...

随机推荐

  1. jQuery EasyUI API - Layout - Layout[原创汉化官方API]

    最近在学习jQuery EasyUI,发现中文的文档好少,部分文档不错但它是鸟语的,为了大家也为了自己学习吧,汉化做一下笔记. 有没有说清楚的,或者翻译不正确的地方还请大家谅解指出.. 由于工作时间原 ...

  2. 2.2 LINQ中使用from子句指定数据源

    数据源是LINQ查询中必不可少的元素,数据源是实现泛型接口IEnumerable<T>或IQueryable<T>的类对象. 可以将IEnumerable<T>简单 ...

  3. 一个web开发框架

    一个web开发框架 怎么才能成为一名架构师?需要具备哪些条件? 作为一名码农我迫切希望自己成为一个比较合格的web架构师,昨晚心血来潮小弟花了4个小时的时间整了个简易的web开发框架,由于第一次搭建框 ...

  4. python进程池剖析(一)

    python中两个常用来处理进程的模块分别是subprocess和multiprocessing,其中subprocess通常用于执行外部程序,比如一些第三方应用程序,而不是Python程序.如果需要 ...

  5. C#编程实践–产假方案优化版

    前言 既然作为一个踏踏实实学习技术的人,就要有一颗谦卑.虚心和追求卓越的心,我不能一次就写出很完美的代码,但我相信,踏踏实实一步一步的优化,代码就可以变得趋近完美,至少在某一个特定场景下相对完美,这和 ...

  6. DropDownListFor的用法

    Asp.Net MVC中DropDownListFor的用法   在Asp.Net MVC中可以用DropDownListFor的方式来让用户选择已定列表中的一个数值.用法不复杂,这里简单做一个记录. ...

  7. JS数量输入控件

    JS数量输入控件 很早看到kissy首页 有数量输入控件,就随便看了下功能 感觉也不怎么难 所以也就试着自己也做了一个, 当然基本的功能和他们的一样,只是用了自己的编码思想来解决这么一个问题.特此给大 ...

  8. 2 MySQL安装

    目录: 1. mysql安装简介2. 下载AppServ3. 安装AppServ4. 使用phpmyadmin连接MySQL5. 使用MySQL Command Line Client 连接MySQL ...

  9. Hadoop将本地文件复制到Hadoop文件系统

    代码: package com.hadoop; import java.io.BufferedInputStream; import java.io.FileInputStream; import j ...

  10. TFS二次开发、C#知识点、SQL知识

    TFS二次开发.C#知识点.SQL知识总结目录   TFS二次开发系列 TFS二次开发系列:一.TFS体系结构和概念 TFS二次开发系列:二.TFS的安装 TFS二次开发系列:三.TFS二次开发的第一 ...