开发者

Nhibernate filter not consistently applying to child collections

I have an entity with child objects that are soft deleted. When I call a simple get on the parent, I want it to retrieve on child objects not soft deleted. All my entities have a base class where the id, audit, soft delete fields are kept.

In order to achieve this I created 2 event listeners and 1 filter, one Event listener will cascade the soft delete if necessary, and another to apply the filter on preload.

public class NonDeletedFilter : FilterDefinition
{
    public static string FilterName = "NonDeletedFilter";
    public NonDeletedFilter()
    {
        WithName(FilterName).WithCondition("IsDeleted = 0");
    }
}

public class ParentMap : IAutoMappingOverride<Parent>
{
    public void Override(FluentNHibernate.Automapping.AutoMapping<Parent> mapping)
    {
        mapping.HasMany(x => x.Children).Fetch.Join()
                .Inverse()
                .Cascade.AllDeleteOrphan()
                .ApplyFilter(NonDeletedFilter.FilterName);
    }
}

public class PreLoadEventListener : DefaultPreLoadEventListener
{
    public override void OnPreLoad(NHibernate.Event.PreLoadEvent preloadEvent)
    {
        preloadEvent.Session.EnableFilter(NonDeletedFilter.FilterName);
        base.OnPreLoad(preloadEvent);
    }
}

Here is the issue, and it's the worst kind: sometimes it works. In my test cases, it creates the sql perfectly. It selects the parent, has a left outer join for the child and makes certain the children isdeleted = false. In my application it does not, it simply does the join without checking. It works on a seperate parent/child relationship with the same mapping override applied.

The configuration is built from the same mappings, has the same filters and event listeners. The only difference I can see is my test uses an inmemory sqlite db where the database is created based on the mappings and then initialization sql is executed to prepopulate the database. But it's populated from actual data and I can't find any differences.

At this point I suppose my question is where should I look?

Here are my thoughts. Are the tables not right? They look fine. Is the mapping missing something? They look the same. Is the filter not being applied? Well it is for another. Is the filter working? It is for another.

Perhaps I've looked 开发者_高级运维at the code so much I can't see the issue. Can anyone shed some light on where to concentrate my efforts?


After a few mind boggling hours the issue finally revealed itself. I have a base repository call to apply fetch statements to properties. For the class that was broken, the repository was fetching the same property, thereby overriding the filter that was setup in the map class. And yes, I had been looking at it too long to notice the difference. Another set eyes was working through it, and noticed the working one taking a different path through the repository. So, +1 for pair programming.

And for anyone who is wondering why the preload event listener is not working, make certain that when you create custom criteria, you don't override the fetching strategy.

I should have known better since this was used elsewhere to bypass the filter and explicitly return all objects regardless of soft delete.

Here is an example of what was done in the repository.

public override Parent Get(id)
{
    Session.CreateCriteria<Parent>()
           .Fetch<Parent>(x => x.Children)
}

public static ICriteria Fetch<T>(this ICriteria criteria, params Expression<Func<T, object>>[] fetch)
{
    foreach (Expression<Func<T, object>> expression in fetch)
        criteria.SetFetchMode(expression, FetchMode.Join);

    return criteria;
}

Included is an extension method to clean up the code when creating custom criteria.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜