我有一个奇怪的场景,其中有一个表引用了一个视图,该视图包含特定于用户的行。视图具有唯一的行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子句。现在在实践中,当我尝试直接检索一个条时,我看到了这些过滤器的应用。但是,当我检索一个名为Foo的对象(它引用了一个Bar对象)时,在第二个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库正试图基于键的唯一值(在日志中)检索对象
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
我可以在这里看到,它把吧台装上了水,但不知什么原因它没有水合??
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
我在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));
救命?!