如何翻译';其中not在';转换为NHibernate查询,其中子查询表不是实体

本文关键字:查询 实体 查询表 NHibernate 翻译 何翻译 其中 转换 not | 更新日期: 2023-09-27 18:26:49

我有两个实体:UserNotice,它们通过DismissedNoticeToUser表链接在一起(UserIdNoticeId分别是列)。

以下是我为User类绘制的FluentHibernate映射:

mapping.HasManyToMany<Notice>(u => u.DismissedNotices)
    .Table("DismissedNoticeToUser")
    .ParentKeyColumn("UserId")
    .ChildKeyColumn("NoticeId")
    .Inverse();

每次使用"驳回"通知时,都会向DismissedNoticeToUser类中添加一对User.IdNotice.Id。这在代码中很容易:

var notice = this.session.Load<Notice>(noticeId);
var user = this.session.Load<User>(this.userSession.Id);
user.DismissedNotices.Add(notice);

如果我想列出所有被用户驳回的而不是的通知,我会在原始SQL:中写这样的东西

select * from [Notice]
    where Id not in 
    (select NoticeId from [DismissedNoticeToUser] where UserId=@userId)

然而,我真的不知道如何使用NHibernate来做同样的事情。我已经尝试了以下操作,但它在用户的通知中作为单独的查询执行左联接。

this.session.Query<Notice>().Where(n => !user.DismissedNotices.Contains(n));

我可以放下并使用NHibernate来编写原始SQL,但我觉得我可能遗漏了一些东西。我不在乎我使用哪一个NHibernate查询API。

如何翻译';其中not在';转换为NHibernate查询,其中子查询表不是实体

如果不能将Users映射到Notice,也可以根据Query编写Query。我还没有尝试将Load与Query合作,对Query使用Load可能会导致NH生成单独的查询。

试试这个:

this.session.Query<Notice>().Where( n => 
    this.session.Query<User>().Any(u => u.UserId == "007"
            && !u.DismissedNotices.Contains(n) );

我认为下面的帖子描述了如何查询这些多对多关系:

FluentHibernate对多对多关系对象的查询

可能还有很多其他类似的帖子也有这种效果。

编辑

以下是一个更接近您要求的示例:

var subquery = QueryOver.Of<Notice>()
                .JoinQueryOver<User>(x => x.DismissedNotices)
                .Where(x => x.Id == userId)
                .Select(x => x.Id);
IList<Notice> groupsFound =
         session.QueryOver<Notice>()
                .WithSubquery.WhereProperty(x => x.Id).NotIn(subquery)
                .List<Notice>();

如果您想生成与上面完全相同的查询,我不确定您能否做到这一点,除非您将表DismissedNoticeToUser映射为一个实体。如果你要这样做,那么你可能会做这样的事情:

var subquery = QueryOver.Of<DismissedNoticeToUser>()
                        .Where(x => x.UserId == userId)
                        .Select(x => x.NoticeId);
IList<Notice> noticesFound = session.QueryOver<Notice>()
                               .WithSubquery.WhereProperty(x => x.Id).NotIn(subquery)
                               .List<Notice>();

您差不多到了,将Contains更改为Any:

string userId = "007";
this.session.Query<Notice>().Where( n => 
    !n.Users.Any(x => x.UserId == userId) );

嗨,我为您的示例Notice和DismissedNoticeToUser实体制作了它。

var userIdParam = 111;
var results = session.GetSession().CreateCriteria(typeof(Notice));
var notInSubQuery = DetachedCriteria.For<DismissedNoticeToUser>()
                        .Add(Expression.Eq("userId", userIdParam))
                        .SetProjection(NHibernate.Criterion.Projections.Id());
results.Add(Subqueries.PropertyNotIn("id",notInSubQuery));
var result = results.List<Notice>();

注意,"userId"answers"id"是来自实体的主键列的名称,而不是来自数据库的。我并没有完全测试你的情况,公交车上类似的东西对我来说效果很好。