NHibernate,映射一个集合,其中键可以是两个不同的列

时间:2012-01-02 12:47:22

标签: c# .net nhibernate c#-4.0 nhibernate-3

有一个实体 A

此外,还有一个实体 B ,它与 A 有两个关联。

包含 B 的集合。

如果关联的 A 之一是已加载的的父级,则此集合必须加载任何 B A

问题是 上的集合映射必须根据检查两个 A 关联中的一个是否过滤来过滤子项父母一个。

我怎样才能做到这一点?

注意:订单无关紧要,因此您可以使用建议一些映射。

注意2:请建议如何使用XML映射实现这一点,我不会在代码中实现。

更新:真实场景:

这是关于友谊实施的全部内容。我想在实体UserProfile中映射友谊的集合。友谊有两个表示关系的关联:OneUser,OtherUser。如果我想要让所有朋友都能找到我,我需要检查这两个属性,因为如果其中一个属性是我自己,那么我的朋友就是我的朋友。

2 个答案:

答案 0 :(得分:1)

这不是一个真正的答案,但我需要能够格式化并且没有字符限制。

我有同样的问题,但由于解决方案不是很容易,我决定通过修改我的结构来解决它。

我看到的一些看起来很有希望的东西是SQLQueries,它将对象作为通过Queryover加入的别名返回。

或者 - 在“hasMany”映射中添加.Where子句。我读到的关于这个选项的一切都说它非常有限。虽然做你所要求的逻辑似乎很简单 - Select Distinct ... From ... Where (OneUser = UserId or OtherUser = UserId)

修改

在这里查看JoinQueryOver:http://nhibernate.info/blog/2009/12/17/queryover-in-nh-3-0.html

此处的Native SQL查询:http://knol.google.com/k/nhibernate-chapter-14-native-sql#

虽然这不是映射级解决方案,但您可以在选择用户时在where子句中指定条件,以便正确填充其好友。如果您无法通过Fluent QueryOver实现所需的过滤,我认为您可以使用Native SQL查询创建别名,并使用JoinQueryOver / JoinAlias来相应地填充Friends集合。

如果这是您已经知道的所有信息,我道歉。无论哪种方式 - 我有兴趣看到这个问题的解决方案。

**编辑2:** 我玩了一下它,这就像我能得到它一样接近:

Public Class UserMapping
    Inherits ClassMap(Of User)
    Public Sub New()
        Id(Function(x) x.Id).Column("UserID")
        Map(Function(x) x.Name).Length(50).Not.Nullable().Column("UserName")
        HasMany(Function(x) x.Friends).Inverse.KeyColumn("UserID").Where("Users.UserID in (select Friendships.FriendOne from Friendships where Friendships.FriendTwo = UserID) or UserID in (select Friendships.FriendTwo from Friendships where Friendships.FriendOne = UserID)")
        Table("Users")
    End Sub
End Class

查询不能正常工作,因为它继续在where子句中添加一个额外的约束,UserID需要等于外部userId,这违背了子查询的目的。

我见过另一个帖子,其中提供了另外两个解决方案。

  1. 创建两个子集合。一个映射当前用户是主要朋友的朋友,另一个映射当前用户是次要朋友。然后,您可以创建一个属性,在NH查询它之外将它们合并在一起。

  2. 在数据库中创建冗余条目,以便每个用户都有一个条目,其中它是与其他人共享的所有关系的PrimaryUser。

  3. 基于这两个选项 - 我可能会选择选项#1。

答案 1 :(得分:1)

如果您愿意将解决方案略微移出数据域,则您的用户可能与他们指定为朋友的其他用户建立了一对多的关系。如果您不希望它泄露,可以是protectedprivate

然后,您实施一个公共属性,将实际的友谊定义为需要双向关系。也许是这样的:

public List<User> Friends {
    this.assignedFriends.Where(f => f.assignFriends.Contains(this)).ToList();
}

如果您这样做,您将需要确保使用二级缓存形式,否则对此属性的请求将破坏您的数据库。


如果您需要返回专用Friendship对象的集合,则取决于您如何持久保存这些条目以及如何映射该类。

一个选项是将Friendship定义为只有三列,一个主键和两个外键返回User表。每当有人试图添加朋友时,您需要一点逻辑:首先需要检查一半的关系是否已经存在..

var f = session.Query<Friend>()
    .Where(x => x.User1 == YourCurrentUser)
    .Cacheable()
    .FirstOrDefault();

然后如果它存在,则分配关系的另一半

f.User2 = TheOtherUser;

否则创建一个新对象:

f = new Friendship();
f.User1 = YourCurrentUser;

并在任何一个分支之后:

session.SaveOrUpdate(f);

然后User的朋友变成

public property List<Friendship> {
    session.Query<Friendship>()
        .Where(f => 
            f.User1 != null && f.User2 != null
            && (f.User1 == this || f.User2 == this)
        ).Cacheable()
        .ToList();
}

请注意,我不在我的VS安装附近。请原谅错别字,或者我是否犯了明显的错误(早上2:30,我原来是这样)