nhibernate可以检查唯一约束,而不是主键

时间:2012-09-30 13:31:06

标签: nhibernate fluent-nhibernate nhibernate-mapping

我有一个简单的类,它有Name成员,用于唯一标识实例。此类在ManyToMany-mapping中引用,该映射将使用Name(因为它是主键)来创建映射表。所涉及的字符串类型使得这非常慢(长度> 128个字符,通常仅在最后几个中不同)。为了加快速度,我想为连接创建一个auto_increment列(我正在使用MySQL),同时仍然可以让nhibernate使用Name来排序对象的唯一性 - 列。

以下是它的外观示例。实际上,物体要大得多。

class MyObject{
  public String Name;
  public String Value;
}
//Mapping
Id(x => x.Name)
  .Length(255)
  .Unique();
Map(x => x.Value);

这是按预期工作的。如果我向表中添加一个新的MyObject,那么nhibernate将首先执行选择,以查看表中是否已存在具有相同Name的记录。

我的ObjectHolder有一套MyObject

class ObjectHolder{
  public UInt64 Id;
  public ICollection<MyObject> MyObjects;
}
//Mapping
Id(x => x.Id)
  .GeneratedBy.Native();
HasManyToMany(x => x.MyObjects)
  .AsSet()
  .Cascade.SaveUpdate();

这将使用ObjectHolder.IdMyObject.Name创建一个映射,这很慢。我希望MyObject具有自动生成的Id列,仅用于映射表,但不能用于nhibernate对主键执行的select-to-see-it-it-exists-checking

我已将映射更改为

class MyObject{
  public UInt64 Id;
  public String Name;
  public String Value;
}
//Mapping
Id(x => x.Id)
  .GeneratedBy.Native();
Map(x => x.Name)
  .Length(255)
  .Unique();
Map(x => x.Value);

这将创建一个auto_increment列并将其用于映射表,但是如果已经存在具有相同Name的记录,它将不再正确检查,这会导致重复的条目异常。

我可以告诉nhibernate检查Name列而不是id,或者注释Id - 列,以便它只用作外键,但没有别的吗?我是否必须修改manyToMany映射?

编辑:如果我必须使用复合ID,似乎更糟。所有id属性都保存两次,一次在对象本身,一次在映射中,这会增加巨大的时间和存储空间开销。

1 个答案:

答案 0 :(得分:1)

你正在以错误的方式看待这个问题,NH不应该检查它是否已经存在。你应该知道它是否已经存在。

检查名称是否唯一应该是验证和业务逻辑的一部分。因此,您应该在尝试保存之前检查名称是否已被采用。

如果您自己访问数据库,则可以处理约束违规。但是,NHibernate不支持这一点,因为它会使批处理变得复杂。即在刷新事务时将保存批处理,这将是引发错误的点,而不是持久保存实体的位置。所以NH可以做的唯一合理的事情是回滚整个事务并抛出错误。

基本上,数据库约束只是最终的故障保护,以防止无效数据,而不是您依赖的东西来检查您的业务规则。