过滤器不适用于多对一参考
Posted
技术标签:
【中文标题】过滤器不适用于多对一参考【英文标题】:Filters not being applied for many-to-one reference 【发布时间】:2010-09-09 19:26:08 【问题描述】:我有一个奇怪的场景,我有一个表,它引用了一个包含用户特定行的视图。视图具有唯一的行 ID,但它从不用于引用项目。相反,唯一值是从客户端 ID、用户 ID 和对象键的组合派生的。
public BarMap()
Table(DatabaseObject.UserBars);
Id(x => x.Id, "Resource_Id");
Map(x => x.ClientId, "Client_Id");
Map(x => x.UserId, "User_Id");
Map(x => x.Key, "Bar_Key")
.Length(10);
Map(x => x.Name, "Bar_Name")
.Length(255);
我有一个过滤器应用于应该根据当前用户和客户端上下文启动 WHERE 子句的类。现在在实践中,当我尝试直接检索 Bar 时,我看到这些过滤器适用。但是,当我检索一个引用 Bar 对象的名为 Foo 的对象时,过滤器会在辅助 SELECT 调用中被跳过。
public class FooMap : ClassMap<Foo>
public FooMap()
Table(DatabaseObject.Foos);
References<Bar>(x => x.Bar, "BarId")
.PropertyRef(x => x.Key)
.Cascade.None()
.Fetch.Join()
.NotFound.Exception();
根据上述情况,您会期望 Foo 会执行 JOIN 来合并 Bar 对象,但它似乎跳过它并坚持检索 Foo 对象。我怀疑正在发生辅助 SELECT 调用,因为 NH 库正在尝试根据 Key 的唯一值检索对象(在日志中
Loader.Loader - SELECT this_.Id as Id12_2_, this_.ClientId as ClientId12_2_, this_.BarId as BarId12_2_, Foo1_.Id as Id13_0_, Foo1_.ClientId as ClientId13_0_, Foo1_.Name as Name13_0_, Bar2_.Resource_Id as Resource1_4_1_, Bar2_.Client_Id as Client7_4_1_, Bar2_.User_Id as User8_4_1_, Bar2_.Bar_Key as Bar9_4_1_, Bar2_.Bar_Name as Bar10_4_1_ FROM Foos this_ inner join FooSchedules Foo1_ on this_.ScheduleId=Foo1_.Id inner join User_Bars Bar2_ on this_.BarId=Bar2_.Bar_Key and (Bar2_.Client_Id = :p0 OR Bar2_.Client_Id IS NULL) and Bar2_.User_Id = :p1 WHERE (Foo1_.ClientId = :p2 OR Foo1_.ClientId IS NULL) and (this_.ClientId = :p3 OR this_.ClientId IS NULL) AND Foo1_.Name = :p4 and Bar2_.Bar_Key = :p5 and Bar2_.Client_Id = :p6 and Bar2_.User_Id = :p7
Loader.Loader - processing result set
Loader.Loader - result set row: 0
我可以在这里看到它加载了 Bar,但由于某种原因它没有给它补水??
Loader.Loader - result row: EntityKey[Core.Domain.FooSchedule#2929992], EntityKey[Core.Domain.Bar#470090], EntityKey[Core.Domain.Foo#3211664]
Loader.Loader - Initializing object from DataReader: [Core.Domain.FooSchedule#2929992]
Loader.Loader - Initializing object from DataReader: [Core.Domain.Foo#3211664]
Loader.Loader - done processing result set (1 rows)
Loader.Loader - total objects hydrated: 2
Engine.TwoPhaseLoad - resolving associations for [Core.Domain.FooSchedule#2929992]
Engine.Loading.LoadContexts - creating collection wrapper:[Core.Domain.FooSchedule.Foos#2929992]
Engine.TwoPhaseLoad - done materializing entity [Core.Domain.FooSchedule#2929992]
Engine.TwoPhaseLoad - resolving associations for [Core.Domain.Foo#3211664]
Engine.Loading.LoadContexts - creating collection wrapper:[Core.Domain.Foo.Items#3211664]
这里是它尝试重新加载栏的地方,但不包括导致它返回多行/爆炸的过滤器....
Loader.Entity.AbstractEntityLoader - Static select for entity Core.Domain.Bar: SELECT Bar0_.Resource_Id as Resource1_4_0_, Bar0_.Client_Id as Client7_4_0_, Bar0_.User_Id as User8_4_0_, Bar0_.Bar_Key as Bar9_4_0_, Bar0_.Bar_Name as Bar10_4_0_ FROM User_Bars Bar0_ WHERE Bar0_.Bar_Key=?
Loader.Loader - loading entity: [Core.Domain.Bar#ABFDBC01]
Engine.QueryParameters - BindParameters(Named:NHibernate.Type.StringType) ABFDBC01 -> [0]
Loader.Loader - SELECT Bar0_.Resource_Id as Resource1_4_0_, Bar0_.Client_Id as Client7_4_0_, Bar0_.User_Id as User8_4_0_, Bar0_.Bar_Key as Bar9_4_0_, Bar0_.Bar_Name as Bar10_4_0_ FROM User_Bars Bar0_ WHERE Bar0_.Bar_Key=:p0
Loader.Loader - processing result set
我很想将 Bar 视图重构为不存在,但时间限制不允许这样做,除非绝对必要。关于如何应用过滤器的任何想法?或者是否有关于如何进行特定于上下文的对象引用的指导?
我在 JBoss 方面发现了一些参考资料,表明 Hibernate 也可能遭受了potentially related design issue 的影响。查看 NHibernate 源代码,问题似乎集中在 EntityJoinWalker:
SqlStringBuilder whereCondition = WhereString(Alias, uniqueKey, batchSize)
//include the discriminator and class-level where, but not filters
.Add(persister.FilterFragment(Alias, new CollectionHelper.EmptyMapClass<string, IFilter>()));
如果我将其更改为此一切正常,但我不确定更改的影响是什么,并且评论并没有真正说明为什么应该排除过滤器。
SqlStringBuilder whereCondition = WhereString(Alias, uniqueKey, batchSize)
.Add(persister.FilterFragment(Alias, enabledFilters));
帮忙?!
【问题讨论】:
最初的想法来自 NHForge.org wiki,在上下文感知对象上使用过滤器。似乎在过滤器不适用的关系的情况下。现在不确定如何处理关联上下文感知对象。 :S 【参考方案1】:通过在地图类中应用过滤来解决(从外观上看是 NH 2.1.2 中的新功能):
Where("Client_Id = :clientFilter.clientId AND User_Id = :userFilter.userId");
【讨论】:
以上是关于过滤器不适用于多对一参考的主要内容,如果未能解决你的问题,请参考以下文章