Список родителей 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"));
Другие вопросы по тегам