2

I am trying take this sql query and make it into an nhibernate HQL query. I am using nhibernate 3 and Fluent Nhibernate 1.2

SELECT     dbo.Tasks.CourseId, dbo.CoursePermissions.BackgroundColor, dbo.Tasks.DueDate, dbo.Tasks.TaskName, dbo.Tasks.TaskId
FROM         dbo.Courses INNER JOIN
                      dbo.Tasks ON dbo.Courses.CourseId = dbo.Tasks.CourseId INNER JOIN
                      dbo.CoursePermissions ON dbo.Courses.CourseId = dbo.CoursePermissions.CourseId
WHERE     (dbo.Tasks.CourseId = 1)

I would have liked to use linq but I don't think nhibernate supports linq joins yet so I guess I am stuck with using HQL(unless someone knows a better way).

I guess I can use QueryOver or the other ways nhibernate does queries so whatever works the best. I still don't understand the difference between all the ways as if I could do everything in linq I would.

However I have no clue on how to write my query.

Thanks

Edit

I now have this(changed a bit)

Course cAlias = null; Task tAlias = null; CoursePermission cpAlias = null;

    var result = session.QueryOver<Task>(() => tAlias)
        .JoinAlias(() => tAlias.Course, () => cAlias)
        .JoinAlias(() => cAlias.CoursePermissions, () => cpAlias)
        .Where(Restrictions.In(Projections.Property(() => cAlias.Id), courseIds))
        .And(x => x.DueDate >= startDate)
        .And(x => x.DueDate <= endDate)
        .Select( Projections.Property(() => cAlias.Id),
                Projections.Property(() => cpAlias.BackgroundColor),
                Projections.Property(() => tAlias.DueDate),
                Projections.Property(() => tAlias.TaskName),
                Projections.Property(() => tAlias.TaskId))
        .List<object[]>();

I know want to map it to

public class TaskAppointments { public int Id { get; set; } public string BackgroundColor { get; set; } public DateTime DueDate { get; set; } public int TaskId { get; set; } public string TaskName { get; set; }

}

How do I do this. If this was a linq method I would do

.Select(new TaskAppointments { TaskId = Projections.Property(() => tAlias.TaskId)})

but it says it can't convert it to an int.

Edit2

This is what I came up with

Course cAlias = null; Task tAlias = null; CoursePermission cpAlias = null; TaskAppointments taskAppointments = null;

    List<TaskAppointments> result = session.QueryOver<Task>(() => tAlias)
        .JoinAlias(() => tAlias.Course, () => cAlias)
        .JoinAlias(() => cAlias.CoursePermissions, () => cpAlias)
        .Where(Restrictions.In(Projections.Property(() => cAlias.Id), courseIds))
        .And(x => x.DueDate >= startDate)
        .And(x => x.DueDate <= endDate)
        .SelectList(list => 

                            list.SelectGroup(x => x.TaskId).WithAlias(() => taskAppointments.TaskId)
                            .SelectGroup(() => cpAlias.BackgroundColor).WithAlias(() => taskAppointments.BackgroundColor)
                            .SelectGroup(x => x.DueDate).WithAlias(() => taskAppointments.DueDate)
                            .SelectGroup(x => x.TaskName).WithAlias(() => taskAppointments.TaskName)
                    )
        .TransformUsing(Transformers.AliasToBean<TaskAppointments>())
        .List<TaskAppointments>().ToList();
chobo2
  • 83,322
  • 195
  • 530
  • 832

1 Answers1

3

Without mappings I assume that you have the following relationships: Courses -> Tasks (1:n) and Courses -> CoursePermissions (1:n) I also assumed that you do not want the complete objects but only certain properties, so I used projections.

QueryOver version:

// the aliases are required here, so that we can reference the entities properly
Courses cAlias = null;
Tasks tAlias = null;
CoursePermissions cpAlias = null;

var result = session.QueryOver<Courses>(() => cAlias)
    .JoinAlias(() => cAlias.Tasks, () => tAlias)
    .JoinAlias(() => cAlias.CoursePermissions, () => cpAlias)
    .Where(() => cAlias.CourseId == 1)
    .Select(Projections.Property(() => cAlias.CourseId),
            Projections.Property(()  => cpAlias.BackgroundColor),
            Projections.Property(()  => tAlias.DueDate),
            Projections.Property(()  => tAlias.TaskName),
            Projections.Property(()  => tAlias.TaskId))
    .List<object[]>();

Edit start

If you need to do a WHERE IN clause, you can do this:

List<int> courseIdList = new List<int>() { 1, 2 };

var result = session.QueryOver<Courses>(() => cAlias)
    .JoinAlias(() => cAlias.Tasks, () => tAlias)
    .JoinAlias(() => cAlias.CoursePermissions, () => cpAlias)
    .Where(Restrictions.In(Projections.Property(() => cAlias.CourseId), courseIdList))
    .Select(...)
    .List<object[]>();

Edit end

Edit 2 start

If you want to transform it into a DTO:

// AliasToBeanResultTransformer is in namespace NHibernate.Transform
// we have to use .As("...") for the transformer to find the correct property-names
var result = ...
    .Select(Projections.Property(() => cAlias.CourseId).As("CourseId"),
            Projections.Property(()  => cpAlias.BackgroundColor).As("BackgroundColor"),
            Projections.Property(()  => tAlias.DueDate).As("DueDate"),
            Projections.Property(()  => tAlias.TaskName).As("TaskName"),
            Projections.Property(()  => tAlias.TaskId).As("TaskId"))
    .TransformUsing(new AliasToBeanResultTransformer(typeof(TaskAppointments)))
    .List<TaskAppointments>();

Edit 2 end

HQL version:

string hql = "select c.CourseId, cp.BackgroundColor, t.DueDate, t.TaskName, t.TaskId" 
   + " from Courses as c inner join c.Tasks as t inner join c.CoursePermissions as cp" 
   + " where c.CourseId = 1";

var result2 = session.CreateQuery(hql)
    .List<object[]>();

Be aware that this will result in a cartesian product, so for each Course you will get Tasks.Count + CoursePermissions.Count rows.

Florian Lim
  • 5,332
  • 2
  • 27
  • 28
  • @Florian Lim - What do you mean without mapping? Do I have to map joins? I jsut have stuff like References(x => x.Course).Not.Nullable(); – chobo2 Apr 22 '11 at 20:34
  • @chobo2 I meant there were no mappings in your question, so I assumed the most likely ones based on the SQL query. – Florian Lim Apr 22 '11 at 20:35
  • @Florian Lim - Are we talking about the fluent mapping? I can post that if needed. So are you recommending using QueryOver way? So with this way you don't need to worry about what kind of join? – chobo2 Apr 22 '11 at 20:39
  • oh and what happens if say for the where caluse I need to do a collection. Like in HQL I would use SetParamterList("courseId",courseIdLIst). How would that be handled in queryOver – chobo2 Apr 22 '11 at 20:40
  • 1
    @chobo2 Sorry for the misunderstanding here. All I meant is that I had to assume what the relationships and the names of the properties were, because you did not provide the (fluent) mapping in the question. So instead of a class `Tasks` it may only be `Task`. I personally prefer using QueryOver over HQL when it is possible, because with HQL you do not get Intellisense and the compiler won't help you with spelling errors. But for certain (more complex) scenarios HQL can do what Queryover can't. – Florian Lim Apr 22 '11 at 20:44
  • @ Florian Lim - Ah I understand now. Just too many choices with nhibernate confuses me(as when to use what and how to use it). I am still waiting for a beginner book for nhibernate 3.0 to come out that I can follow. So how can I do a list of Ids in my where caluse? – chobo2 Apr 22 '11 at 20:47
  • @chobo2 I can't help with suggesting a good book but this [link](http://nhforge.org/blogs/nhibernate/archive/2009/12/17/queryover-in-nh-3-0.aspx) here gives a short introduction to QueryOver in NH 3.0. Regarding the list of ids see my edit in the answer. – Florian Lim Apr 22 '11 at 20:54
  • @ Florian Lim - See my edit. I am now trying to change it from an object array to a collection of Task Appointments. – chobo2 Apr 22 '11 at 21:04
  • @Florian Lim - See what I came up with. Mine seems to work but yours might be better. – chobo2 Apr 22 '11 at 21:50
  • @chobo2 I added that to my answer. Please consider putting something like that into an extra question next time. (I am glad to help here but using a `ResultTransformer` does not really have much to do with teh original querstion.) – Florian Lim Apr 22 '11 at 21:51
  • @chobo2 Ah, yes, you can use `.WithAlias()` instead of `.As()`. I have not used it but I would consider it better, because it gets rid of the strings. Not quite sure why you have the SelectGroup in there, though. – Florian Lim Apr 22 '11 at 21:58
  • @Florian Lim- I am not sure either I just tried to copy some examples from the link you gave me. If you know how to improve it let me know. – chobo2 Apr 22 '11 at 22:19
  • @chobo2 `SelectGroup` will do nothing if it is applied to all result fields, so you can just get rid of it. In my answer under Edit 2 I wrote what I think should work in your case. You can replace `.As(...)` with `.WithAlias(() => taskAppointments.TaskId` from your Edit to have a solution without strings. – Florian Lim Apr 22 '11 at 22:29
  • @Florian Lim- Ok I changed it the only thing that I noticed I can't do stuff like x => taskId. I am still a bit unclear on what Projections.Property really is for. – chobo2 Apr 22 '11 at 22:54