Список родителей NHibernate с количеством детей
Я использую NHibernate 4 с MySQL. у меня есть 2 стола. Мои таблицы кошачьи и ответ.
public class cat
{
[Key]
public virtual int id { get; set; }
public virtual string catName { get; set; }
public virtual IList<answer> answers { get; set; }
}
public class answer
{
[Key]
public virtual int id { get; set; }
public virtual int catId { get; set; }
public virtual string detail { get; set; }
public virtual bool stat { get; set; }
[ForeignKey("catId")]
public virtual cat cats { get; set; }
}
Я хочу выбрать все записи о кошках (со списком ответов) и подсчитать их ответы.
мой SQL-запрос, как это;
select count(t2.id) as count, cats.*from cat cats left join answer t2 ON(cats.id=t2.catId and t2.stat=0) GROUP BY(cats.id);
Результат, как это;
id - catName - count
1 - Книга - 5
2 - ПК - 0
3 - английский - 22
4 - Искусство - 56
Я попробовал также этот запрос NH;
public class myClass {
public virtual int count { get; set; }
public virtual cat cats { get; set; }
}
var u = db.CreateCriteria(typeof(cat), "cats")
.CreateAlias("answer", "t2", NHibernate.SqlCommand.JoinType.LeftOuterJoin, Restrictions.Eq("t2.stat", false))
.SetProjection(Projections.ProjectionList()
.Add(Projections.Count("t2.id"), "count")
.Add(Projections.Group<cat>(g => g.id)));
var list = u.SetFetchMode("answer", FetchMode.Eager)
.SetResultTransformer(Transformers.AliasToBean<myClass>())
.List<myClass>();
Этот ответ на запрос NHibernate также учитывает количество ответов. но кошки всегда возвращают ноль. Как я могу сделать мой запрос для этого результата?
Редактировать 1 я могу сделать это так
public class myClass {
public virtual int count { get; set; }
public virtual catId count { get; set; }
public virtual cat cats { get; set; }
}
cat cats = null;
answer answers = null;
var u = db.QueryOver<cat>(() => cats)
.JoinQueryOver(x => x.answers, () => answers, NHibernate.SqlCommand.JoinType.LeftOuterJoin, Restrictions.Eq("answers.stat", false))
.SelectList(cv => cv
.SelectCount(() => answers.id)
.SelectGroup(c => c.id))
.List<object[]>()
.Select(ax => new myClass
{
count = (int)ax[0],
catId = (int)ax[1],
cats = (cat)db.QueryOver<cat>().Where(w=>w.id==(int)ax[1]).Fetch(fe => fe.answers).Eager.SingleOrDefault()
})
.ToList();
2 ответа
Я могу сделать этот запрос вот так;
public class myClass {
public virtual int count { get; set; }
public virtual İnt catId { get; set; }
public virtual cat cats { get; set; }
}
cat cats = null;
answer answers = null;
var u = db.QueryOver<cat>(() => cats)
.JoinQueryOver(x => x.answers, () => answers, NHibernate.SqlCommand.JoinType.LeftOuterJoin, Restrictions.Eq("answers.stat", false))
.SelectList(cv => cv
.SelectCount(() => answers.id)
.SelectGroup(c => c.id))
.List<object[]>()
.Select(ax => new myClass
{
count = (int)ax[0],
catId = (int)ax[1],
cats = (cat)db.QueryOver<cat>().Where(w=>w.id==(int)ax[1]).Fetch(fe=>fe.answers).Eager.SingleOrDefault()
})
.ToList();
В вашем результате cats
всегда нулевой, потому что ResultTransformer
пытается сопоставить свойства по их именам.
Пожалуйста, проверьте ваш лог-файл NHibernate. Вы, вероятно, увидите, что ваш запрос возвращает столбцы count
а также id
, но myClass
имеет свойства count
а также cats
,
Редактировать:
Новое предложение:
Предыдущее предложение не сработало, потому что собственность id
имеет тип Int32
и не может быть назначен myClass.cat
(который имеет тип cat
).
Если вам не нужна ссылка на cat
-объект в myClass
тогда вы можете изменить это на это:
public class myClass {
public virtual int count { get; set; }
public virtual int catId { get; set; }
}
и иметь такую проекцию:
.Add(Projections.Group<cat>(g => g.id), "catId"));
Если вам нужно свойство типа cat
в вашем классе результатов я не думаю, что это можно сделать с помощью простой проекции, но я могу ошибаться.
Изменить 2:
Так как вам требуется объект типа cat
в вашем результате я предлагаю вам собрать его вручную после запроса, например:
Новый класс результатов:
public class myClassResult {
public virtual int count { get; set; }
public virtual cat cats { get; set; }
}
Добавьте это после логики запроса:
IList<myClassResult> result = new List<myClassResult>();
foreach (var idWithCount in list)
{
result.Add(new myClassResult()
{
cats = catsOnlyList.FirstOrDefault(x => x.id == idWithCount.catId),
count = idWithCount.count
});
}
catsOnlyList
относится к простому списку кошек, который нужно получить заранее. Я знаю, что это не красиво, но я не думаю, что вы можете группировать по cat
сам в запросе.
Старое предложение (не работает из-за несовместимых типов):
Вместо
.Add(Projections.Group<cat>(g => g.id)));
использование
.Add(Projections.Group<cat>(g => g.id), "cats"));