【问题标题】:Nhibernate filter not consistently applying to child collectionsNhibernate 过滤器不始终适用于子集合
【发布时间】:2011-07-02 21:15:55
【问题描述】:

我有一个带有被软删除的子对象的实体。当我在父对象上调用一个简单的 get 时,我希望它在未软删除的子对象上检索。我所有的实体都有一个基类,其中保留了 id、审计、软删除字段。

为了实现这一点,我创建了 2 个事件监听器和 1 个过滤器,一个事件监听器将在必要时级联软删除,另一个在预加载时应用过滤器。

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

这就是问题所在,这是最糟糕的问题:有时它会起作用。在我的测试用例中,它完美地创建了 sql。它选择父级,为子级设置一个左外连接,并确保子级 isdeleted = false。在我的应用程序中它没有,它只是在不检查的情况下进行连接。它适用于单独的父/子关系,并应用了相同的映射覆盖。

配置基于相同的映射构建,具有相同的过滤器和事件侦听器。我能看到的唯一区别是我的测试使用了一个内存 sqlite db,其中数据库是基于映射创建的,然后执行初始化 sql 以预填充数据库。但它是根据实际数据填充的,我找不到任何差异。

此时我想我的问题是我应该看哪里?

这是我的想法。桌子不对吗?他们看起来很好。映射是否缺少某些内容?它们看起来一样。是否未应用过滤器?好吧,这是另一个。过滤器是否工作?这是为了另一个。

也许我看了太多代码,看不出问题所在。任何人都可以说明我应该在哪里集中精力吗?

【问题讨论】:

  • 一般来说,除非您有真正令人信服的商业理由将软删除的数据与您的实时数据混合在一起,否则只会导致一团糟。 ayende.com/Blog/archive/2009/08/30/avoid-soft-deletes.aspx
  • 我知道这只是时间问题。每当提到软删除时,总是有人必须指出应该避免它。开发人员手中很少有这样的选择。我会说软删除是一项功能,而不是审计或归档的后备解决方案,这是 ayende 提到的重要但经常被忽视的注意事项。因此,如果您了解软删除要求或要求不灵活,请不要害怕此处发布的解决方案。
  • 评论不一定针对您,而是将来偶然发现这一点的人可能能够做出自己的架构决策。

标签: .net nhibernate asp.net-mvc-2 fluent-nhibernate


【解决方案1】:

在令人难以置信的几个小时之后,问题终于暴露出来了。我有一个基本存储库调用来将 fetch 语句应用于属性。对于被破坏的类,存储库正在获取相同的属性,从而覆盖了在地图类中设置的过滤器。是的,我一直在看它太久没有注意到差异。另一双眼睛正在通过它,并注意到正在工作的眼睛在存储库中采用了不同的路径。所以,结对编程+1。

对于任何想知道为什么预加载事件侦听器不起作用的人,请确保在创建自定义条件时不会覆盖获取策略。

我应该更清楚,因为这在其他地方被用来绕过过滤器并显式返回所有对象,而不考虑软删除。

这是在存储库中完成的示例。

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;
}

包括在创建自定义条件时清理代码的扩展方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多