【问题标题】:Can nhibernate check for unique constraints, without it being the primary key可以休眠检查唯一约束,而不是主键
【发布时间】:2012-09-30 13:31:05
【问题描述】:

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

这是一个外观示例。实际上,这些对象要大得多。

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-if-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-column 以便它仅用作外键,而不是别的吗?我必须修改 manyToMany 映射吗?

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

【问题讨论】:

    标签: nhibernate fluent-nhibernate nhibernate-mapping


    【解决方案1】:

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

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

    如果您自己访问数据库,则可以处理约束冲突。然而,NHibernate 不支持这一点,因为它会使批处理复杂化。 IE。当事务被刷新时,批次将被保存,这将是引发错误的地方,而不是你持久化实体的地方。所以 NH 唯一明智的做法就是回滚整个事务并抛出错误。

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

    【讨论】:

    • 我认为(希望)你误解了。该名称是该对象的唯一 ID。名称已经存在是设计使然,具有相同名称的对象代表相同的对象。在这种情况下,我希望 nhibernate 更新对象,然后保存/更新包含 manyToMany 关系的父对象。我正在使用 ORM 正是因为我不想使用通常的选择来处理所有 manyToMany 集合,如果存在则更新,否则插入;在我的整个层次结构中递归循环。
    • 我只想让 nhibernate 使用不同的列(对于 mysql,由于 auto_increment,它必须是主键)来进行数据库连接,仅此而已。
    • 对,但是如果你告诉 NH 那是 id 列,那么就 NH 而言,那是 id,而不是名称。您可以将 name 设置为自然键,但这并没有太大变化。最主要的是 NH 不应该通过数字 id 或名称检查您是否已经存在某些东西。由于您使用的是 auto_increment 列,您会立即看到错误,但如果您使用 say hilo,NH 不会尝试将对象保存到数据库,直到您提交事务,此时它将保存所有更改在单个批次中(当 DBMS 支持时)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-10
    • 1970-01-01
    相关资源
    最近更新 更多