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 -
http://lists.jboss.org/pipermail/hibernate-dev/2006-September/000283.html
Help?!
Colin