【问题标题】:NHibernate: Where clause containing child collection as subquery building improper T-SQL statementsNHibernate:包含子集合的 Where 子句作为子查询构建不正确的 T-SQL 语句
【发布时间】:2011-09-15 19:43:37
【问题描述】:

我正在使用 NHibernate 3.x 以及 Fluent NHibernate,并且到目前为止构建数据库查询没有任何问题。

为了在本文中简化我的对象,我在下面包含了我的对象和映射结构的子集:

IssueItem POCO 实体类:

public class IssueItem : DomainEntity, IKeyed<Guid> {
    public virtual Guid ID { get; set; }
    public virtual string Subject { get; set; }
    public virtual string Description { get; set; }
    public virtual IList<IssueLocation> Locations { get; set; }
}

Location POCO 实体类:

public class Location : DomainEntity, IKeyed<Guid> {
    public virtual Guid ID { get; set; }
    public virtual string City { get; set; }
    public virtual string State { get; set; }
    public virtual string Zip { get; set; }
    public virtual string Organization { get; set; }
    public virtual IssueItem Issue { get; set; }
}

IssueItem流畅的NHibernate地图:

public class IssueItemMap : DomainEntityMapping<IssueItem> {
    public IssueItemMap()
    {
        Table("IssueItem");
        LazyLoad();
        Map(x => x.ID).Column("ID");
        Map(x => x.Subject).Column("Subject");
        Map(x => x.Description).Column("Description");
        HasMany(x => x.Locations).KeyColumn("IssueItemID").LazyLoad().ReadOnly().Inverse();
    }
}

Location流畅的NHibernate地图:

public class LocationMap : DomainEntityMapping<Location> {
    public LocationMap()
    {
        Table("Location");
        LazyLoad();
        Map(x => x.ID).Column("ID");
        Map(x => x.City).Column("City");
        Map(x => x.State).Column("State");
        Map(x => x.Zip).Column("Zip");
        Map(x => x.Organization).Column("Organization");
        References(x => x.IssueItem).ForeignKey("IssueItemID").LazyLoad().ReadOnly();
    }
}

现在,我在我的 MVC 应用程序中使用了工作单元和服务/存储库模式。因此,我的项目有一个域层,其中包含我的基本 POCO 实体,以及验证器和服务。在我的数据层中,我有我的 NHibernate 相关的东西,例如我的存储库,我的域层从我的服务访问。这也是我的 NHibernate 地图所在的位置。

为了确保没有特定于 NHibernate 的逻辑渗入我的域层(以防我将来想使用不同的 ORM),我在域层的服务中针对从返回的 IQueryable 对象执行 LINQ 语句我的数据层中的存储库。因此,当我编写查询时,我使用 System.Linq 和 System.Linq.Expressions 而不是 NHibernate.Linq 类。

也就是说,这是我在域层中的一个服务类中遇到问题的 LINQ 查询:

var issues = _issueRepo.All();
if (!string.IsNullOrWhiteSpace(searchWords)) {
    issues = issues.Where(i => i.Subject.Contains(searchWords)
        || i.Description.Contains(searchWords)
        || i.Locations.Where(l => l.Organization.Contains(searchWords)
            || l.City.Contains(searchWords))
            .Select(x => x.IssueItemID).Contains(i.ID)
        );
}

现在,IssueItems 可以正常查询了。但是,未正确查询一对多表(Locations)。这就是我的意思...

生成的 T-SQL 语句是完美的,除了它的最后。示例:

select TOP(100) issueitem0_.ID as ID2_, issueitem0_.Subject as Subject2_, issueitem0_.Description as Description2_ 
from IssueItem issueitem0_ 
where issueitem0_.Subject like ('%test%') or issueitem0_.Description like ('%test%')
or exists (select location1_.IssueItemID from Location location1_ where
issueitem0_.ID=location1_.IssueItemID and (location1_.Organization like ('%test%') 
or location1_.City like ('%test%')) and location1_.ID=issueitem0_.ID)

看到最后一点了吗?它抛出了最后一个“和”语句(和 location1_.ID=issueitem0_.ID),这在整个系统中抛出了一个扳手。我已经调整了我的映射可以想到的每个配置参数,并尝试了许多不同的 LINQ 语句,但我无法摆脱最后一部分。我不知道为什么它会添加它。

如果我在 LINQPad 中构造相同的 LINQ 语句,它会正确生成没有最后一部分(和 location1_.ID=issueitem0_.ID)的 T-SQL 语句。

有什么想法吗?

谢谢! 乔尔

【问题讨论】:

    标签: linq nhibernate c#-4.0 fluent-nhibernate


    【解决方案1】:

    在查询位置时添加 Any()。如果任何位置属性包含您要查找的内容,它将成为现实。您正在尝试在 where 子句中进行选择,然后尝试从那里获取 IssueID。我想你会看到这个查询更清楚。

    var issues = _issueRepo.All();
    if (!string.IsNullOrWhiteSpace(searchWords)) 
    {
        issues = issues.Where(i => i.Subject.Contains(searchWords)
                                || i.Description.Contains(searchWords)
                                || i.Locations.Any(l => l.Organization.Contains(searchWords))
                                || i.Locations.Any(l => l.City.Contains(searchWords)) )
    }
    

    【讨论】:

    • 不幸的是,这不起作用。问题集合的类型为IQueryable&lt;IssueItem&gt;。您放置在上面的Select 返回一个IQueryable&lt;string&gt;。如果您查看我的原始 LINQ 语句生成的问题中的 T-SQL 语句,您会发现我正在尝试检索完整的 IssueItem 记录集,但在 where 子句中包括 Locations 表。
    • 很抱歉。我将删除 select 子句。是你想要的吗?它现在返回问题
    猜你喜欢
    • 1970-01-01
    • 2015-10-30
    • 1970-01-01
    • 2017-10-17
    • 1970-01-01
    • 2014-10-13
    • 2016-08-29
    • 2021-02-21
    • 1970-01-01
    相关资源
    最近更新 更多