开发者

Fluent NHibernate and filtering one-to-many relationship on query requiring multiple joins?

开发者 https://www.devze.com 2023-02-13 12:15 出处:网络
I recently got started with NHibernate and am having some trouble implementing the domain model outlined further down.

I recently got started with NHibernate and am having some trouble implementing the domain model outlined further down.

What I'm looking for is a way to filter the relationship between an Item and it's ItemData collection on specific DataStores. DataStores are either global, in which case they are always returned, or specific to a user identity (based on application instance).

In SQL this can be accomplished using a simple query:

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

Database structure:

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

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

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

Domain model:

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

The basic theory is to fetch one ItemData row per DataStore and join each column on the weight field of the respective DataStore (first non-null value ordered by weight).

Insight as to if and how this could be accomplished in NHibernate would be much appreciated.


Heres what I've found myself in case anyone else is looking for this information.

1.Create a custom filter:

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

2.Modify your Fluent NHibernate property mapping (with .ApplyFilter<>()):

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

3.In your repository enable the filter and set it's property for the current session:

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

Another way to do this would be to fetch all ItemData for each Item and add another non-mapped property that does this filtering.


You can do this using HQL using a simple query too.. Your HQL query syntax is as follows:

 Session.CreateQuery(hqlQuery).List();

your hqlQuery will be something like this:

 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>();

Hope this works..

0

精彩评论

暂无评论...
验证码 换一张
取 消