NHibernate - как получить элемент, на который не ссылается элемент в другой таблице - PullRequest
2 голосов
/ 04 декабря 2009

Допустим, у меня есть ваучер класса:

public class Voucher
{
    public Guid Id {get;set;}
    public DateTime DateAvailable {get;set;}
}

и запись в классе

public class Entry
{
    public Guid Id {get;set;}
    public Voucher Voucher {get;set;}
    // ... other unrelated properties
}

Как я могу создать запрос NHibernate Criteria, который находит первый доступный ваучер, который НЕ назначен в данный момент для записи?

Эквивалентный SQL будет

select 
    v.Id, v.DateAvailable 
from 
    Voucher v
        left join Entries e on e.VoucherId = v.Id
where 
    v.DateAvailable <= getutcdate() and
    e.Id is null

Редактировать: Я все еще не могу понять это. Таблица ваучеров не имеет ссылки на таблицу записей, но мне нужно найти первый ваучер (по порядку дат), который не был присвоен записи. Это кажется такой простой задачей, но все, что я продолжаю читать об использовании критериев левого соединения NHibernate, требует, чтобы у объекта Voucher было свойство, которое ссылается на запись. Конечно, есть способ инвертировать запрос или добавить свойство ссылки в объект Voucher без изменения базы данных, чтобы каждая таблица ссылалась на другую.

Редактировать 2: Несмотря на это, я не думаю, что возможно сделать то, что я пытался сделать без каких-либо модификаций. В конце концов я получил запрос для работы, используя Entry в качестве основного критерия с Voucher в качестве подкритерия, но затем UniqueResult вернул ноль, даже если данные были там. Я предполагаю, что это просто не могло создать ассоциацию.

В случае, если кто-то столкнется с этим, я в конечном итоге создал в каждой таблице внешний ключ, который ссылается на другую, и использовал сопоставление References <>, чтобы связать их. Это не идея, потому что мне приходится вручную устанавливать подсвойство каждого объекта на другое, чтобы сделать ассоциацию двунаправленной, но, по крайней мере, она работает без множества изменений.

Ответы [ 3 ]

1 голос
/ 04 декабря 2009

Следующее должно работать с использованием HQL:

IQuery query = session.CreateQuery(@"
    FROM
        Voucher v LEFT JOIN
        Entry e
    WHERE
        e.ID IS NULL AND
        v.DateAvailable <= :now
");

query.SetParameter("now", DateTime.Now);

// If you want to restrict to only the first result
query.SetMaxResults(1);
Voucher v = query.UniqueResult<Voucher>();

// Otherwise, get a list of results...
// List<Entry> results = query.List<Entry>();
1 голос
/ 04 декабря 2009

Перевод вашего SQL буквально:

var voucher = NHibernateSessionManager.Session.CreateCriteria<Voucher>("v")
                        .Add(Restrictions.Le("v.DateAvailable", DateTime.UtcNow))
                        .CreateCriteria("Entries", "e")
                        .Add(Restrictions.IsNull("e.Id"))
                        .SetMaxResults(1)
                        .UniqueResult<Voucher>();

Теперь, если я правильно понимаю, может быть альтернатива. Если утверждение: «..поискает первый доступный ваучер, который НЕ назначен в данный момент для записи ...», совпадает со статусом «находит первый доступный ваучер, который не имеет записей ...» (поскольку сущность, которая имеет много записей ... в соответствии с вашими классами), то вы можете сделать:

var voucher = NHibernateSessionManager.Session.CreateCriteria<Voucher>()
                .Add(Restrictions.IsEmpty("Entries"))
                .Add(Restrictions.Le("DateAvailable", DateTime.UtcNow))
                .SetMaxResults(1)
                .UniqueResult<Voucher>();

... при условии, что вы сопоставили свойство Entries в сущности Voucher.

Но, может быть, я ошибся ...

0 голосов
/ 04 декабря 2009

Из памяти может не работать:

session.CreateQuery<Entry>().CreateAlias("Voucher","v").Add(Restrictions.And(
    Restrictions.Lt("DateAvailable",DateTime.Now),
    Restrictions.Eq("v.Id",null")
).List<Voucher>();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...