Свободный NHibernate и фильтрация отношения один-ко-многим в запросе, требующем нескольких объединений - PullRequest
3 голосов
/ 27 февраля 2011

Я недавно начал работать с NHibernate, и у меня возникли проблемы с реализацией модели предметной области, описанной ниже.

То, что я ищу, - это способ фильтрации отношений между Предметом и его коллекцией ItemData в конкретных хранилищах данных. Хранилища данных являются либо глобальными, в этом случае они всегда возвращаются, либо специфичны для идентификатора пользователя (на основе экземпляра приложения).

В SQL это можно сделать с помощью простого запроса:

SELECT * FROM Items i
INNER JOIN ItemData id ON (i.ItemId=id.ItemId)
LEFT OUTER JOIN Users u ON (id.UserId=u.UserId)
LEFT OUTER JOIN DataStore ds ON (id.DataStoreId=ds.DataStoreId)
WHERE ds.IsGlobal = 1 OR ds.UserId = @userId

Структура базы данных:

DataStore:
- DataStoreId (PK)
- Name
- Weight
- UserId
- IsGlobal

Item:
- ItemId (PK)
- ... (non-nullable fields)

ItemData:
- ItemDataId (PK)
- ItemId
- DataStoreId
- ... (nullable fields)

Модель домена:

public class ItemMap : ClassMap<Item>
{
    public ItemMap()
    {
        Id(x => x.Id, "ItemId");
        HasMany(x => x.Data)
            .KeyColumn("ItemId")
            .ApplyFilter<ItemDataFilter>(..?)
            .Cascade.AllDeleteOrphan();
    }
}

Основная теория заключается в извлечении одной строки ItemData для каждого хранилища данных и присоединении каждого столбца в поле веса соответствующего хранилища данных (первое ненулевое значение, упорядоченное по весу).

Высоко ценится понимание того, как и как это можно сделать в NHibernate.

Ответы [ 2 ]

5 голосов
/ 28 февраля 2011

Вот что я нашел на тот случай, если кто-то еще ищет эту информацию.

1.Создать пользовательский фильтр:

public class ItemDataFilter : FilterDefinition
{
    public ItemDataFilter()
    {
        WithName("ItemDataFilter").WithCondition("Data.DataStoreId == :DataStoreId").AddParameter("DataStoreId", NHibernate.NHibernateUtil.Int32);
    }
}

2.Измените свое отображение свойств Fluent NHibernate (с помощью .ApplyFilter <> ()):

HasMany(x => x.Data)
    .KeyColumn("ItemId")
    .ApplyFilter<ItemDataFilter>()
    .Cascade.AllDeleteOrphan();

3.В вашем репозитории включите фильтр и установите его свойство для текущего сеанса:

public IList<Item> GetItemsByDataStore(int DataStoreId)
    {
    using (var session = NHibernateHelper.OpenSession())
    {
        session.EnableFilter("ItemDataFilter").SetParameter("DataStoreId", DataStoreId);
        return session.CreateCriteria(typeof(Item)).List<Item>();
    }
}

Еще один способ сделать это - извлечь все ItemData для каждого Item и добавить еще одно неотображенное свойство, которое выполняет эту фильтрацию.

1 голос
/ 27 февраля 2011

Вы можете сделать это, используя HQL, используя также простой запрос. Ваш синтаксис HQL-запроса выглядит следующим образом:

 Session.CreateQuery(hqlQuery).List();

Ваш hqlQuery будет выглядеть примерно так:

 var hqlQuery= string.Format("select i from Items as i inner join i.ItemData left join Users u left join DataStire ds where u.UserId=i.UserId and ds.DataStoreId=i.DataStoreId and (ds.IsGlobal=1 or ds.UserId='{0}')",userId);

 Session.CreateQuery(hqlQuery).List<Item>();

Надеюсь, что это работает ..

...