过滤器未应用于多对一参考

发布于 2024-09-18 10:34:21 字数 4338 浏览 2 评论 0原文

我有一个有点奇怪的场景,我有一个表引用一个包含特定于用户的行的视图。该视图具有唯一的行 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

我很想重构栏视图以使其不存在,但除非绝对有必要,否则时间限制不允许这样做。或者是否有关于如何进行特定于上下文的对象引用的指导?

我在 JBoss 方面也找到了一些参考资料。遇到了潜在相关的设计问题。在 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));

帮助?!

I have a bit of an odd scenario where I have a table that references a view that contains rows which are user-specific. The view has a unique row ID, but it is never used to reference the item. Instead a unique value is derived from a combination of a client ID, user ID, and an object key.

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

I have a filter applied to the class that should kick in the WHERE clause based on the current user and client context. Now in practice I see those filters apply when I try to retrieve a Bar directly. However, when I retreive an object named Foo which references a Bar object, the filters are skipped in a secondary SELECT call.

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

Based on the above you would expect that Foo would perform a JOIN to hydrate the Bar object, but it appears to skip it and insist on retrieving a Foo object. I suspect the secondary SELECT call is happening because the NH library is trying to retrieve the object based on a unique value of the Key (in the log

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

I can see right here it loaded the Bar, but it didn't hydrate it for some reason??

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]

Here is where it makes an attempt to re-load the Bar, but doesn't include the filters causing it to return multiple rows / blow up....

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

I'd love to refactor the Bar view out of existence but the time constraints won't allow for it unless it is absolutely necessary. Any thoughts on how to get filters to apply? Or is there guidance on how to do context-specific object references?

I found some reference on the JBoss side that Hibernate also might have suffered from a potentially related design issue. Looking into the code the NHibernate source the problem seems to center around 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>()));

If I change it to this everything works fine, but I'm not sure what the impact of the change is and the comment doesn't really indicate why filters should be excluded.

SqlStringBuilder whereCondition = WhereString(Alias, uniqueKey, batchSize)
    .Add(persister.FilterFragment(Alias, enabledFilters));

Help?!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

动次打次papapa 2024-09-25 10:34:21

通过在地图类中应用过滤来解决(从外观上看是 NH 2.1.2 中的新功能):

Where("Client_Id = :clientFilter.clientId AND User_Id = :userFilter.userId");

Solved by applying filtering in the map class (new in NH 2.1.2 by the looks of it):

Where("Client_Id = :clientFilter.clientId AND User_Id = :userFilter.userId");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文