Selecting an entity with multiple child entities
Using Active Record/NHibernate, I'm trying to select an entity (Site) which has multiple child collections.
There is only one Site with the given siteId, yet the FindAll returns the Site 28 times; it's being duplicated due to the child collections that it's loading. How do I get it to load just the 1 Site and arrays of the child collections? I don't mind if it does 5 selects, one to grab the site and then 1 per child collection.
Here is the code:
var criteria = DetachedCriteria.For<Site>()
.CreateAlias("TimeZone", "tz", NHibernate.SqlCommand.JoinType.InnerJoin)
.CreateAlias("Logos", "l", NHibernate.SqlCommand.JoinType.LeftOuterJoin)
.CreateAlias("SiteColors", "sc", NHibernate.SqlCommand.JoinType.LeftOuterJoin)
.CreateAlias("ManagerUsers", "mu", NHibernate.SqlCommand.JoinType.LeftOuterJoin)
.Add(Restrictions.Eq("Id", siteId));
var sites = FindAll(criteria);
I should me开发者_StackOverflowntion that I also tried an hql approach using fetch, however fetch is not fetching! It returns only the one Site (good) but none of the child collections are eagerly loaded (bad).
public static Site Get(int id)
{
var query = new SimpleQuery<Site>(@"
from Site s
where s.Id = ?
inner join fetch s.TimeZone tc
left join fetch s.Logos l
left join fetch s.SiteColors sc
left join fetch s.ManagerUsers mu
", id);
var results = query.Execute().ToList();
return results.FirstOrDefault();
}
Here is code that seems to work, using the "Future" approach:
public static Site Get(int id)
{
var session = ActiveRecordMediator.GetSessionFactoryHolder().CreateSession(typeof(Site));
var query = session.CreateQuery("from Site s left join fetch s.Logos where s.Id = :id").SetParameter("id", id).Future<Site>();
session.CreateQuery("from Site s left join fetch s.SiteColors where s.Id = :id2").SetParameter("id2", id).Future<Site>();
session.CreateQuery("from Site s left join fetch s.ManagerUsers where s.Id = :id3").SetParameter("id3", id).Future<Site>();
return query.FirstOrDefault();
}
All of my data model classes inherit from a SimpleModel class, which I've added Equals and GetHashCode methods to:
public abstract class SimpleModel
{
protected SimpleModel()
{
DateCreated = DateTimeAccess.Now;
}
[PrimaryKey]
[DocumentId]
public virtual int Id { get; set; }
[Property]
public virtual DateTime DateCreated { get; set; }
public override bool Equals(object obj)
{
if (obj is SimpleModel)
{
return Id.Equals(((SimpleModel)obj).Id);
}
else
{
return false;
}
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
Call SetResultTransformer(DistinctRootEntity)
on your criteria. It will collapse those duplicate Site
instances to a single instance.
For more information, see this thread: http://groups.google.com/group/nhusers/browse_thread/thread/9919812230702ccc
精彩评论