NHibernate: предложение Where, содержащее дочернюю коллекцию как построение подзапроса, неправильные операторы T-SQL - PullRequest
0 голосов
/ 15 сентября 2011

Я использую 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();
    }
}

Теперь я использую шаблон Unit of Work и Service / Repository в своем приложении MVC. Поэтому у меня есть доменный слой моего проекта, который содержит мои основные сущности POCO, а также валидаторы и сервисы. На моем уровне данных у меня есть материалы, связанные с NHibernate, такие как репозитории, к которым мой уровень домена получает доступ из моих сервисов. Здесь и живут мои карты NHibernate.

Чтобы убедиться, что никакая логика, специфичная для NHibernate, не проникает в мой уровень домена (на случай, если в будущем я захочу использовать другой ORM), я выполняю свои операторы LINQ в своих службах на уровне своего домена для объектов IQueryable, возвращаемых из репозитории в моем слое данных. Поэтому, когда я пишу свои запросы, я использую 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 запрашиваются просто отлично. Однако таблица «один ко многим» (местоположения) не запрашивается должным образом. Это то, что я имею в виду ...

Сгенерированный оператор 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, и я не могу избавиться от этой последней части. Я не знаю, почему это добавляет это.

Если я создаю тот же оператор LINQ в LINQPad, он правильно генерирует оператор T-SQL без последней части (и location1_.ID = issueitem0_.ID).

Есть идеи?

Спасибо! Joel

1 Ответ

0 голосов
/ 16 сентября 2011

Добавить любое () при запросе местоположений. Это сбудется, если какое-либо свойство местоположения содержит то, что вы ищете. Вы пытаетесь выбрать пункт 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)) )
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...