我正在尝试映射包含其值的唯一键约束的组件列表。
以下类别的“修剪”样本如下:
public class MyObject
{
public virtual int Id { get; set; }
public virtual IList<Alias> Aliases { get; set; }
}
public class Alias
{
public Alias(string type, string value)
{
Type = type;
Value = value;
}
public virtual string Type { get; protected set; }
public virtual string Value { get; protected set; }
}
来自MyObject的相关NHibernate映射(为了简洁起见,已经修剪了类型):
<list cascade="all-delete-orphan" name="Aliases" table="MyObject_Aliases" mutable="true">
<key>
<column name="MyObject_id" />
</key>
<index>
<column name="`Index`" />
</index>
<composite-element class="Alias">
<property name="Type" type="System.String">
<column name="Type" unique-key="UK_Alias" />
</property>
<property name="Value" type="System.String">
<column name="Value" unique-key="UK_Alias" />
</property>
</composite-element>
</list>
目的是防止两个MyObjects包含相同的别名。
在向MyObject添加新Alias时,这非常有效。但是,如果要从删除别名后的别名中删除别名,则NHibernate会尝试重新排序导致密钥冲突的列表。
NHibernate生成的SQL示例是:
-- statement #1, saving MyObject.Aliases
INSERT INTO MyObject_Aliases
(MyObject_id,
"Index",
Type,
Value)
VALUES (101 /* @p0 */,
0 /* @p1 */,
'A' /* @p2 */,
'ALIAS1' /* @p3 */)
INSERT INTO MyObject_Aliases
(MyObject_id,
"Index",
Type,
Value)
VALUES (101 /* @p0 */,
1 /* @p1 */,
'A' /* @p2 */,
'ALIAS2' /* @p3 */)
-- statement #2, updating MyObject.Aliases after removing the first list item
UPDATE MyObject_Aliases
SET Type = 'A' /* @p0 */,
Value = 'ALIAS2' /* @p1 */
WHERE MyObject_id = 101 /* @p2 */
AND "Index" = 0 /* @p3 */
此示例中的语句#2抛出:
NHibernate.Exceptions.GenericADOException : could not update collection rows: [MyObject.Aliases#101][SQL: UPDATE MyObject_Aliases SET Type = ?, Value = ? WHERE MyObject_id = ? AND "Index" = ?]
----> System.Data.SQLite.SQLiteException : Abort due to constraint violation
columns Type, Value are not unique
根据实际发生的情况,异常本身是完全合理的,但我如何让它实际按预期工作?
答案 0 :(得分:1)
如果您的集合不需要编入索引,则应该使用集合映射。集合是一种集合类型,可确保不存在重复项。列表是可以编制索引的集合类型。