2012-09-30 39 views
1

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

下面是它的样子的一个例子。事实上,这些物体要大得多。

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

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

我有了一套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的映射,这是一个缓慢ObjectHolder。我希望MyObject有一个自动生成的Id列,只用于映射表,但不能用于nhibernate对主键进行select-to-see-if-it-exists检查。

我已经改变了映射到

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

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

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

如果您自己正在访问数据库,您可能已经处理了约束冲突。但是,NHibernate不支持这个,因为它会使批处理变得复杂。即当事务刷新时,批处理将被保存,这就是错误发生的地方,而不是你坚持实体的地方。所以NH能做的唯一明智的事情就是回滚整个事务并抛出一个错误。

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

+0

我想(希望)你误会了。该名称是该对象的唯一ID。该名称已经存在是由设计决定的,具有相同名称的对象表示相同的对象。在这种情况下,我希望nhibernate更新对象,然后保存/更新保存manyToMany关系的父项。我正在使用ORM,因为我不想用通常的select来处理所有manyToMany集合,如果存在update,否则插入;递归循环遍历整个层次结构。 – Darcara

+0

我只想让nhibernate使用不同的列(对于mysql必须是由于auto_increment产生的主键)来执行数据库连接,而不是其他任何操作。 – Darcara

+0

对,但如果你告诉NH是id列,那么就NH而言,关心的是id,而不是名称。您可以将名称设置为自然键,但这并没有太大改变。最主要的是NH不应该真的在检查是否已经存在的东西,通过数字ID或名称。由于您使用的是auto_increment列,因此您会立即看到该错误,但如果您使用的是hilo,则NH不会尝试将对象保存到数据库,直到您提交事务,此时它将保存所有更改在一个批次中(当由DBMS支持时)。 –