简体   繁体   中英

How to execute the following SQL-Query using LINQ or HQL

How can I execute the following query using Castle ActiveRecords and LINQ or HQL?

SELECT a.id, s.classes, COUNT(p.id), MAX(p.date) AS last, MIN(p.date) AS first
FROM account a
LEFT JOIN school s ON s.account_id = a.id
LEFT JOIN user u ON u.account_id = a.id
LEFT JOIN points p ON p.user_id = u.id
WHERE payment = "S"
GROUP BY a.id

The tables are related in the following way:ER图

I also have ActiveRecord classes for all tables with the correct relations defined (if I do the query in steps it works, but it is slow as there are a lot of rows) and I tried the following which didn't worked:

var result = from account in AccountRecord.Queryable
             join s in SchoolRecord.Queryable on account equals s.Account into schools
             from school in schools.DefaultIfEmpty(null)
             join user in UserRecord.Queryable on account equals user.Account
             join p in PointsRecord.Queryable on user equals p.User into points
             where account.PaymentType == "S"
             select new { Account = account, School = school, Count = points.Count() };

which threw the following The method or operation is not implemented -Exception at:

NHibernate.Linq.Visitors.QueryModelVisitor.VisitGroupJoinClause(GroupJoinClause groupJoinClause, QueryModel queryModel, Int32 index)

Found the solution using HQL - I'm still open for a LINQ solution:

HqlBasedQuery query = new HqlBasedQuery(typeof(AccountRecord),
    "SELECT a, s, COUNT(p), MIN(p.DateUTC), MAX(p.DateUTC) " +
    "FROM AccountRecord a " +
    "LEFT JOIN a.Schools s " +
    "LEFT JOIN a.Users u " +
    "LEFT JOIN u.Points p " +
    "WHERE a.PaymentType=:payment GROUP BY a.Id");
query.SetParameter("payment", "S");
var result = from object[] row in (ArrayList)ActiveRecordMediator.ExecuteQuery(query)
                select new
                {
                    Account = row[0] as AccountRecord,
                    School = row[1] as SchoolRecord,
                    Count = row[2],
                    First = (new DateTime(1970, 1, 1, 0, 0, 0, 0)).AddSeconds(Convert.ToDouble(row[3])),
                    Last = (new DateTime(1970, 1, 1, 0, 0, 0, 0)).AddSeconds(Convert.ToDouble(row[4]))
                };

I think your Linq query would be something like:

var result = from a in AccountRecord.Queryable
             join s in SchoolRecord.Queryable on a.id equals s.account_id
             join u in UserRecord.Queryable   on a.id equals u.account_id
             join p in PointsRecord.Queryable on u.id equals p.user_id
             where a.payment == "S"
             group by a.id
             select new
             {
               Account = a,
               School = s,
               Count = p.Count()
             };

Though I'm not sure how well NHibernate will handle the group by and Count() combination. You might want to see what the generated SQL ends up being, if it doesn't throw an error.

If that doesn't work, you might want to select the records back, and group/count them in the application instead, more like:

var data = from a in AccountRecord.Queryable
           join s in SchoolRecord.Queryable on a.id equals s.account_id
           join u in UserRecord.Queryable   on a.id equals u.account_id
           join p in PointsRecord.Queryable on u.id equals p.user_id
           where a.payment == "S"
           select new
           {
             Account = a,
             School = s,
             Count = c
           };
var grouped = data.ToList.GroupBy(x => x.Account.Id);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM