views:

429

answers:

2

I'm trying to get a specific set of data while joining 4 different entities together to do so. What I've done is setup a DTO to try to get this working:

public class LatestThread
{
 private readonly string comment;
 private readonly DateTime posted;
 private readonly string userName;
 private readonly int reputation;
 private readonly int threadId;
 private readonly string topic;
 private readonly int userId;
 private readonly string avatar;

 public LatestThread(string comment, DateTime posted, string userName, int reputation, int threadId, string topic, int userId, string avatar)
 {
  this.comment = comment;
  this.avatar = avatar;
  this.userId = userId;
  this.topic = topic;
  this.threadId = threadId;
  this.reputation = reputation;
  this.userName = userName;
  this.posted = posted;
 }

 public string Comment
 {
  get { return comment; }
 }

 public DateTime Posted
 {
  get { return posted; }
 }

 public string UserName
 {
  get { return userName; }
 }

 public int Reputation
 {
  get { return reputation; }
 }

 public int ThreadId
 {
  get { return threadId; }
 }

 public string Topic
 {
  get { return topic; }
 }

 public int UserId
 {
  get { return userId; }
 }

 public string Avatar
 {
  get { return avatar; }
 }
}

Now I thought I could use SimpleQuery like so:

string hql = string.Format("select new LatestThread(m.Comment, m.Posted, u.UserName, u.Reputation, t.Id, t.Topic, u.Id, u.Avatar) from Thread as t inner join Message as m on t.Id = m.ThreadId inner join User as u on u.Id = m.PostedById inner join Activity as a on a.Id = t.ActivityId where a.Lineage like '{0}%' order by t.LastPosted desc", activityLineage);

return repository.SimpleQuery(0, 10, hql);

My repository method looks like:

 public virtual IList<T> SimpleQuery<T>(int firstResult, int maxResults, string hql, params object[] parameters)
 {
  var query = new SimpleQuery<T>(hql, parameters);
  query.SetQueryRange(firstResult, maxResults);
  return query.Execute();
 }

Now it's asking for me to put [ActiveRecord] at the top of my LatestThread class. When I do that it wants a primary key, and that just seems to be the wrong route.

I've also read bits that refer to the Import attribute given to classes that aren't the DTO. In all the examples though it's just two entities being joined, not the 4 I have. Do I need to add Import to all 4? Or is there something to tell AR that it's a readonly DTO class? OR am I doing this all wrong and there's a really easy way to do what I'm trying to do.

TIA!

+1  A: 

You can't query a type that isn't mapped (which is what the [ActiveRecord] attribute does). AFAIK you can't get NHibernate to create a new arbitrary object instance like that via HQL (I stand to be corrected if someone knows otherwise).

Your best bet is to do a projection query and then have a method to map the tuples returned into instances of your type.

My answer here shows how to do a projection query and map it to an anonymous type; what you want to do is not much different. You could then put a method to do this in a type-specific repository or a strongly-typed extension method to the generic repository.

DotNetGuy
Crap, really new to nhib and castle's ar. I'm starting to understand "projection"s but tuples? :P I'll check it out.
rball
+2  A: 

Add the Import attribute to your new Thread class

[Import(typeof(LatestThread), "LatestThread")]
[ActiveRecord("Thread")]
public class Thread : ActiveRecordBase<Thread> { /* blah blah */ }

And then, query magic happens :)

string hql = string.Format("select new LatestThread(m.Comment, m.Posted, u.UserName, u.Reputation, t.Id, t.Topic, u.Id, u.Avatar) from Thread as t inner join Message as m on t.Id = m.ThreadId inner join User as u on u.Id = m.PostedById inner join Activity as a on a.Id = t.ActivityId where a.Lineage like '{0}%' order by t.LastPosted desc", activityLineage);

SimpleQuery<LatestThread> query = new  SimpleQuery<LatestThread>(typeof(Thread), hql );  
LatestThread[] results = query.Execute()

Source : http://www.kenegozi.com/Blog/2006/10/08/projection-using-activerecords-importattribute-and-hqls-select-new-clause.aspx

mathieu
Thanks I'll give this a try!
rball
I did actually see this post before, but wasn't sure where the heck to put the import. It seems that you just need to put it on one of the entities? Then back on my LatestThread I shouldn't need any attributes right? It looks like from your example that I was close, but my exe was wrong at the end
rball
There's no List<T>() method off query...
rball
Adding the Import to the Thread class and then trying to do it with my SimpleQuery still doesn't work. It wants me to put ActiveRecord attribute on my LatestThread again...sigh...
rball
I think this is close...I was just in a rush over lunch. I'll retry tonight.
rball
now it's corrected
mathieu
ahhh, yeah I think I have to have that typeof(Thread). Thanks for posting an update!
rball
It worked...I'll post what I came up with here in a bit
rball
oh and THANKS A S**T LOAD!!!!!! I've been stumped for days!
rball
Nice. I didn't know you could do that in HQL that way - as below, we've been doing it via simple projection.
DotNetGuy