Nhibernate 过滤器不能一致地应用于子集合
我有一个带有软删除子对象的实体。当我在父对象上调用简单的 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 数据库,其中数据库是根据映射创建的,然后执行初始化 sql 来预填充数据库。但它是根据实际数据填充的,我找不到任何差异。
此时我想我的问题是我应该看哪里?
这是我的想法。是不是表不对啊?他们看起来很好。映射是否缺少某些内容?他们看起来一样。是否没有应用过滤器?好吧,这是为了另一个。过滤器是否工作?这是为了另一个。
也许我已经看了太多代码,所以看不到问题所在。谁能告诉我应该把精力集中在哪里?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
经过几个令人难以置信的小时后,问题终于浮出水面。我有一个基本存储库调用,用于将 fetch 语句应用于属性。对于损坏的类,存储库正在获取相同的属性,从而覆盖映射类中设置的过滤器。是的,我看它太久了,没有注意到其中的区别。另一只眼睛正在研究它,并注意到正在工作的眼睛在存储库中采取了不同的路径。所以,结对编程+1。
对于任何想知道为什么预加载事件侦听器不起作用的人,请确保在创建自定义条件时不会覆盖获取策略。
我应该更清楚,因为这在其他地方用于绕过过滤器并显式返回所有对象,而不管软删除如何。
这是在存储库中完成的操作的示例。
其中包括一个扩展方法,用于在创建自定义条件时清理代码。
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.
Included is an extension method to clean up the code when creating custom criteria.