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

发布于 2024-12-24 02:19:38 字数 732 浏览 0 评论 0原文

有一个实体A

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

A 拥有 B 的集合。

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

问题是 A 上的集合映射必须基于检查两个 A 关联之一是否是父关联来过滤子级。

我怎样才能做到这一点?

注意:顺序并不重要,因此您可以建议使用 bag 进行一些映射。

注意 2:请建议如何使用 XML 映射来实现这一点,我赢了不要在代码中执行此操作。

更新:真实场景:

这都是关于友谊实现的。我想在实体用户配置文件中映射友谊的集合。友谊有两个表示关系的关联:OneUser、OtherUser。如果我想为我找到所有朋友,我需要检查这两个属性,因为如果两个属性之一是我自己,那么一个就是我的朋友。

There's an entity A.

In addition, there's an entity B which has two associations with A.

A has a collection of B.

This collection must load any B if one of associated A is the parent of loaded A.

Problem is collection mapping on A must filter children based on checking if one of two A associations is the parent one.

How can I achieve that?

Note: Order doesn't matter, so you can suggest some mapping using bag.

Note 2: Please suggest how to achieve that using an XML mapping, I won't do it in code.

UPDATE: Real-world scenario:

it's all about a friendship implementation. I want to map a collection of Friendship in an entity UserProfile. Friendship has two associations representing the relation: OneUser, OtherUser. If I want to get all friends for me, I need to check both properties, because one is my friend if one of both properties are myself.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

原谅过去的我 2024-12-31 02:19:38

如果您愿意将解决方案稍微移出数据域,您的用户可以与他们指定为朋友的其他用户建立一对多关系。如果您不希望它泄露,可以将其设置为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);

然后用户的朋友就变成

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)

IF you are willing to move the solution slightly out of the data domain, your users could have a one-to-many relationship of other users they have assigned as friends. This could be protected or private if you don't want it to leak out.

Then, you implement a public property that defines an actual Friendship as requiring the relationship in both directions. Maybe something like:

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

You'll want to make sure you are using a form of 2nd level cache if you do this however, otherwise requests to this property will hammer your database.


If instead you need to return a collection of a dedicated Friendship object, it depends on how you are persisting those entries and how you have mapped that class.

One option would be to define Friendship to simply have three columns, a primary key, and two foreign keys back to the User table. You then require a little bit of logic whenever someone tries to add a friend: you first need to check if half of the relationship already exists..

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

then if it exists you assign the other half of the relationship

f.User2 = TheOtherUser;

otherwise create a new object:

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

and after either branch:

session.SaveOrUpdate(f);

then a Users friends becomes

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

Please note, I'm not near my installation of VS. Please excuse typos or if I've made obvious blundering errors (it's 2:30am where I am presenltly)

你的往事 2024-12-31 02:19:38

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

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

我看到的一些看起来很有前途的东西是 SQLQueries,它返回通过 Queryover 连接的对象作为别名。

或者 - 将 .Where 子句添加到“hasMany”映射。我读到的有关此选项的所有内容都表明它非常有限。虽然执行您要求的操作的逻辑似乎非常简单 - Select Distinct ... From ...Where (OneUser = UserId 或 OtherUser = UserId)

编辑:

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

和本机 SQL 查询:http://knol.google.com/k/nhibernate-chapter-14-native-sql#

虽然这不是映射级解决方案,但您可以在其中指定条件当您选择用户时,以便正确填充他们的朋友。如果您无法使用 Fluent QueryOver 实现所需的过滤,我认为您可以从本机 SQL 查询和 JoinQueryOver / JoinAlias 中创建一个 Alias 来相应地填充 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。

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

This isn't really an answer, but I needed to be able to format and not have a character restriction.

I had this same problem, but because the solutions weren't very easy I decided to work around it instead by modifying my structure.

The few things I looked at that seemed promising were SQLQueries that return objects as an alias that was Joined via Queryover.

Or - adding a .Where clause to the "hasMany" mapping. Everything I have read about this option says it's very limited. Though the logic to do what you're asking seems pretty simple - Select Distinct ... From ... Where (OneUser = UserId or OtherUser = UserId)

EDIT:

Take a look at the JoinQueryOver here: http://nhibernate.info/blog/2009/12/17/queryover-in-nh-3-0.html

And Native SQL queries here: http://knol.google.com/k/nhibernate-chapter-14-native-sql#

While this isn't a mapping-level solution, you could specify criteria in the where clause when you select your users so that their Friends are populated properly. If you can't achieve the filtering you need with the Fluent QueryOver, I think you could make an Alias out of a Native SQL query and JoinQueryOver / JoinAlias to populate the Friends collection accordingly.

I apologize if this is all information you already know. Either way - I'm interested to see the solution to this problem.

** Edit 2: **
I played around with it a bit more, and this is as close as I could get it:

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

The query doesn't quite work because it keeps putting an additional constraint in the where clause that the UserID needs to equal the outer userId, which defeats the purpose of the subquery.

I had seen another post where two other solutions where offered.

  1. Create two child collections. One that maps the friends where the current User is the Primary friend, and another where the current user is the Secondary friend. You could then create a property that would merge these together outside of how NH queries it.

  2. Create redundant entries in the database so that each user has an entry where it is the PrimaryUser for all relationships it shares with other people.

Based on these two options - I would probably opt for Option #1.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文