由母体实体NHIBERNATE组无n 1查询



我有两个具有亲子关系的表。我想计算子表的记录,将其分组由父实体分组并收集结果。因此,我想看看每个父母在子表中引用了多少次。

所以如果我的父桌是猫:

| Id | Name     |
|  1 | Bob      |
|  2 | Garfield |

,孩子的桌子是Catskills:

| Id | Cat_Id | Skill        |
|  1 |      1 | Land on feet |
|  2 |      2 | Eat lasagne  |
|  3 |      2 | Escape diets |

我想收到这个:

| Id | Name     | count of skills |
|  1 | Bob      |               1 | 
|  2 | Garfield |               2 |

我已经尝试使用nhibernate linq,查询似乎是正确的,但是我得到了一个"不支持的功能"例外。

我尝试了nhibernate查询,那里有一个n 1问题:

var q = Session.QueryOver<CatSkill>()
    .Fetch(s => s.Cat).Eager
    .Select(Projections.ProjectionList()
        .Add(Projections.Group<CatSkill>(s => s.Cat))
        .Add(Projections.RowCount()))
        .List<object[]>();

上面的查询有效,但会在单独查询中获取所有父记录。

在实验的其他部分中,我最终得到了SQL异常,内容涉及SELECT语句中的参考列如何不属于该组的一部分。

有人对如何实施此查询有想法吗?谢谢!

update

多亏了Radim,更新的代码看起来像:

// a private class, just to make the query work
class CatDto : Cat
{
    public int Count { get; set; }
}
// the actual query code
Cat parent = null;
CatSkill child = null;
CatDto dto = null;
// this is in fact a subselect, which will be injected into parent's SELECT
var subQuery = QueryOver.Of<CatSkill>(() => child)
    .Where(() => child.Cat.ID == parent.ID)
    .Select(Projections.RowCount());
// this is another subquery to filter out cats without skills
var skillFilterSubQuery = QueryOver.Of<CatSkill>(() => child)
    .Where(() => child.Cat.ID == parent.ID /* && more criteria on child table here... */)
    .Select(p => p.Cat);
// the alias here is essential, because it is used in the subselect
var query = session.QueryOver<Cat>(() => parent);
// I only want cats with skills
query = query.WithSubquery.WhereExists(skillFilterSubQuery);
query.SelectList(l => l
    .Select(p => p.ID).WithAlias(() => dto.ID)
    .Select(p => p.Name).WithAlias(() => dto.Name)
    // annoying part: I have to repeat the property mapping for all needed properties of parent...
    // see the parent.Count property
    .Select(Projections.SubQuery(subQuery)).WithAlias(() => dto.Count));
query.TransformUsing(Transformers.AliasToBean<CatDto>());
return query.List<CatDto>();

因此,这消除了n 1问题,但是我必须将父级的每个属性(示例中的CAT)映射到DTO。

如果我能像 .Select(s => s)一样映射它,那将是很好的

一种优雅的方法可能是直接查询父 Cat,并用所需的计数将其扩展为子选择。

Cat parent = null;
CatSkills child = null;
// this is in fact a subselect, which will be injected into parent's SELECT
var subQuery = QueryOver.Of<CatSkills>(() => child)
    .Where(() => child.Cat.ID == parent.ID)
    .Select(Projections.RowCount());
// the alias here is essential, because it is used in the subselect
var query = session.QueryOver<Cat>(() => parent);
query.SelectList(l => l
    .Select(p => p.ID).WithAlias(() => parent.ID)
    .Select(p => p.Name).WithAlias(() => parent.Name)
    // see the parent.Count property
    .Select(Projections.SubQuery(subQuery)).WithAlias(() => parent.Count)
    );
query.TransformUsing(Transformers.AliasToBean<Cat>());

因此,在这种情况下,我们确实期望,父母确实有一个属性

public virtual int Count { get; set ;}

未由Nhiberante映射。如果我们无法扩展C#对象,我们可以创建一些CatDTO(与Cat实体具有相同的属性 - 加上Count

最新更新