2010-10-21 57 views
0

我正在使用NHibernate将我的Item类保留到SQL数据库。 Item类有一个属性Item.Tags类型ICollection<Tag>我正在使用以下NHibernate configation映射。防止使用多对多NHibernate映射的重复标记名称

<set name="Tags" table="TagLinks" cascade="all" lazy ="false"> 
    <key column="ItemId" /> 
    <many-to-many class="Tag" column="TagID" /> 
</set> 

另外这里是我的标记类的映射,它只是一个int ID和一个字符串名称。

<class name="RCL.Tag" table="Tags" lazy="false" > 
    <id name ="TagID" column="TagID" > 
     <generator class="native"/> 
    </id> 
    <property name="Name" not-null="true"/> 
</class> 

这一切工作正常,但它允许使用相同的名称创建重复的标签。因此,下面的代码将在标签表中创建三个单独的“foo”条目,并且都带有单独的ID。

myItem1.Tags.Add(new Tag("Foo")); 
myItem2.Tags.Add(new Tag("Foo")); 
myItem3.Tags.Add(new Tag("Foo")); 

这显然不是我想要这个工作。我可以添加一个唯一的约束到Tags.Name列,但是上面的代码只会引发异常。

在对象模型方面,我希望能够通过编辑TagString的集合简单地添加和删除Item中的标签。但是,当我的项目被保存到数据库时,它应该确定需要创建哪些新标记以及何时应该映射到标记表中的现有条目。

我也算这个不断变化的值基于一个一对多的关系,其中Item.Tags,简直是一个IList<String>并会映射到同一个标签表中的条目为每个Item每一个人标签。这也会起作用,但我认为我会更喜欢第一个,因为它会使找到具有特定标签的项目更加高效。我对关系数据库也很陌生。所以我甚至不确定这是否应该是一个问题。

+0

我很好奇为什么你真的希望这是一个数据库解决方案? – Iain 2010-11-06 01:35:01

+0

我不确定我是否理解你的评论。数据库解决方案的替代选择是什么? – 2010-11-06 18:36:06

回答

0

拥有两个具有相同名称的标记实体是无用的,因为您必须按名称搜索,否则结果将不符合您的期望。

因此,唯一可能的解决方案是您已经考虑的解决方案:使Tag.Name唯一,或完全移除实体并将标签映射为ICollection。

由于空间是便宜,你会被索引反正该列,后者是一个更简单的方法,如果你想计算器般的标签管理(同义词等)

0

如果你虽然你失去了弹性小想尝试DDD,那么解决方案将是这个样子:

public class Item 
{ 
    public IList<Tag> Tags {get;set;} 
    public void AddTag(String tagName) 
    { 
    var tagAlreadyExists = Tags.Any(a=>String.Compare(a.Name,tagName,StringComparison.OrdinalIgnoreCase)==0; 
    if (tagAlreadyExists) 
     return; // Or throw exception 
    Tags.Add(new Tag(tagName)); 
    } 
} 

基本上聚合根(项目)负责执行该标签必须是唯一的规则。