Критерий API с предложением в отношении многих ко многим
В NHibernate 3 введено предложение With для Criteria API. Я пытаюсь использовать его, чтобы ограничить объединение отношений "многие ко многим", и NHibernate применяет дополнительное ограничение объединения к таблице ссылок, а не к правильной таблице.
У меня есть отношения многие ко многим между Player и Address, и я хочу вернуть Player и его почтовый адрес, ограничив Address.IsMailingAddress. Ограничение IsMailingAddress в предложении where не возвращает записи, которые не имеют почтового адреса (или вообще не имеют адреса), поэтому мне нужно ограничить его в соединении. Приведенный ниже код упрощен, и я не могу использовать HQL.
Запрос:
var target = session.CreateCriteria<Player>()
.SetProjection(Projections.Property("PlayerId"))
.CreateAlias("Addresses", "ad", JoinType.LeftOuterJoin, Restrictions.Eq("ad.IsMailingAddress", true))
.Add(Restrictions.Eq("LastName", "Anonymous"))
.List();
генерирует SQL:
SELECT this_.PlayerId as y0_
FROM dbo.VPlayerExisting this_
left outer join dbo.LinkPlayAddr addresses3_
on this_.PlayerId = addresses3_.PlayerId
and (ad1_.MailingAddressFlag = 1 /* @p0 */)
left outer join dbo.VAddress ad1_
on addresses3_.AddressId = ad1_.AddressId
and (ad1_.MailingAddressFlag = 'Anonymous' /* @p1 */)
WHERE this_.Name_Last = @p2
MailingAddressFlag (столбец, сопоставленный с IsMailingAddress) ограничен в таблице ссылок "многие ко многим", где он не существует, и ограничение LastName применяется при объединении с таблицей адресов. Запрос действительно выполняется, но, конечно, сервер базы данных вызывает исключение.
Это ошибка, не поддерживается или я делаю это неправильно?
2 ответа
var target = session.CreateCriteria<Player>()
.CreateAlias("Addresses", "ad", JoinType.InnerJoin)
.Add(Restrictions.Eq("LastName", "Anonymous"))
.Add(Restrictions.Eq("ad.IsMailingAddress",true))
.List();
Просто внутреннее присоединение к почтовому адресу с ограничением на IsMailingAddress?
Должны вернуть игроков (где LastName является "Анонимным") с их MailingAddress, где у них есть адрес, и этот адрес помечен как IsMailingAddress.
Решение ниже. Должен быть только один адрес с установленным параметром IsMailingAddress, поэтому условие или позволяет соединению быть успешным, если есть один или ни один, использующий внутреннее соединение.
var target = session.CreateCriteria<Player>()
.SetProjection(Projections.Property("PlayerId"))
.CreateAlias("Addresses", "ad", JoinType.InnerJoin)
.Add(RestrictionsOr(Restrictions.Eq("ad.IsMailingAddress", true), Restrictions.IsNull("ad.AddressId")))
.Add(Restrictions.Eq("LastName", "Anonymous"))
.List();