Коллекция значений NHibernate QueryOver - PullRequest
1 голос
/ 19 сентября 2011

У меня есть проект, использующий NH 3.1, и до сих пор я использовал синтаксис QueryOver для всего.

Один из аспектов этого проекта находится в общеорганизационной базе данных, к которой у меня есть доступ только для чтения, и использует совершенно другую СУБД (Oracle против MSSQL). Поэтому я храню ссылки из своих объектов (Foos) на их объекты (столбцы), используя стандартную таблицу «многие ко многим»

FooBars
FooID int not null PK
BarID int not null PK

И мой объект домена вместо Iset<Bar> вместо этого имеет ISet<int> BarIDs, который вручную сопоставляется с таблицей FooBars. Это препятствует тому, чтобы NH попытался сделать невозможное и полностью присоединился к таблице Bars (я могу использовать BarRepository.Get (), чтобы получить детали Bars позже, если они мне понадобятся, и в этом случае я бы не стал ', потому что мне просто нужны идентификаторы для фильтрации списка возвращаемых объектов).

Учитывая IList<int> SelectedBars, как я могу написать QueryOver<Foo>, где BarIDs содержит любой элемент в SelectedBars?

SQL что-то вроде

...FROM foos INNER JOIN foobars on foo.fooID = foobars.fooID WHERE barID IN ( ... )

Ответы [ 3 ]

2 голосов
/ 20 сентября 2011

Это невозможно с QueryOver. Два года назад у меня был похожий вопрос о фильтрации коллекций значений . (Примечание. QueryOver основан на Criteria API).

Я не уверен на 100%, но, вероятно, он работает с HQL. Это гораздо мощнее.

Вы можете включить оператор SQL в критерии QueryOver.

Я не очень понимаю, почему вы не отображаете это как список сущностей. Существует ленивая загрузка, чтобы избежать ненужной загрузки - хотя иногда есть некоторые компромиссы. Вы можете получить доступ к идентификатору прокси-серверов NH, не обращаясь к базе данных. Сопоставление идентификаторов обычно усложняет жизнь.

1 голос
/ 20 сентября 2011

Попробуйте:

session.QueryOver<Foo>()
       .JoinQueryOver(x => x.FooBars)
       .WhereRestrictionOn(x => x.BarId).IsIn( ... )
0 голосов
/ 03 июня 2014

Итак, через 3 года я вернулся, чтобы сообщить, как я это решил.

public class Foo :Entity {
    public virtual ISet<FooBar> BarIDs { get; protected internal set; }
 } ...

public class FooBar :Entity {
    protected internal FooBar() { }
    protected internal FooBar(Foo f, int BarID) { ... }
    public virtual Foo Foo { get; protected internal set; }
    public virtual int BarID { get; protected internal set; }
}

Это в основном то, что предложил Стефан, и на что намекает в соответствующем посте. Вам просто нужно съесть накладные расходы на написание дополнительной сущности и ссылки на нее. Помните, что я храню BarID вместо полных объектов Bar, потому что я имею дело с жесткой границей между двумя базами данных: столбцы хранятся в совершенно другой базе данных на другой платформе, чем Foos. В противном случае, конечно, вам гораздо лучше просто сказать Фу, что у него ISet<Bar>.

Найти Foos с помощью SelectedBarIDs очень просто, так же, как предложил Тилак:

session.QueryOver<Foo>().JoinQueryOver<FooBar>(f => f.BarIDs).
    WhereRestrictionOn(b => b.BarID).IsIn(...)...

Это интересная проблема, работать через границу базы данных, как это. Я не могу сказать, что мне нравится это делать, но если кто-то собирается потратить время на то, чтобы сохранить список баров и сделать его доступным для моего использования, для меня было бы огромной тратой ресурсов сделать то же самое. , Так что небольшая неэффективность наличия класса-обертки оправдать очень просто.

...