NHibernate QueryOver组没有选择按列分组

时间:2015-06-18 10:37:33

标签: c# nhibernate queryover

进行如下查询:

public class ByteDataType {
    public int x=20;
    byte a=x;                 //This is an error 
    public final int z=30;
    byte c=z;                 // This is not an Error !! Why???
}

生成的sql正在选择var subquery = SessionFactory.GetCurrentSession() .QueryOver<SomeEntity>() .Where(_ => _.SomeOtherEntity.Id == someId) .SelectList(list => list .SelectGroup(x => x.SomeGroupByProperty) .SelectMax(x => x.MaxPerGroupProperty)) .List<dynamic>(); SomeGroupByProperty的最大值。是否可以将其分组到MaxPerGroupProperty,但只选择SomeGroupByProperty的最大值?这是为了在子查询中使用子查询结果。

3 个答案:

答案 0 :(得分:5)

这是NHibernate jira(标准查询)中的一个未解决的问题:https://nhibernate.jira.com/browse/NH-1426

你可以这样做但是

var subquery =
    QueryOver.Of<SomeEntity>()
        .Where(_ => _.SomeOtherEntity.Id == someId)
        .Select(
            Projections.ProjectionList()
                .Add(Projections.SqlGroupProjection("max(MaxPerGroupProperty) as maxAlias", "SomeGroupByProperty",
                    new string[] { "maxAlias" }, new IType[] { NHibernate.NHibernateUtil.Int32 })));

var parentQuery = session.QueryOver<SomeEntity2>()
    .WithSubquery.WhereProperty(x => x.MaxPerGroupPropertyReference).In(subquery).List();

不如使用实体属性那么漂亮,但确实有用。

答案 1 :(得分:0)

我知道,我正在展示替代方案,而不是给出答案。但是如果我们需要在另一个查询中使用这样的子查询,我们可以:

  • 使用外部查询
  • 中的某些设置过滤内部查询
  • 使用'YYYYMMDD{SPACE}hh:mm:ss[{SPACE}TMZ]'(可以返回任意数量的列)

因此,我们需要首先定义Exists (外部查询)并进行一些过滤: 有如下查询:

Alias

之后,在外部 (root) 查询中,我们可以像这样使用它:

SomeOtherEntity otherEntity = null; // alias of the outer query 
var subquery = QueryOver
    .QueryOver.Of()<SomeEntity>()
    .Where(_ => _.SomeOtherEntity.Id == someId)
    .Where(_ => _.SomeOtherEntity.Id == otherEntity.Id) // here we consume outer alias
    .SelectList(list => list
        .SelectGroup(x => x.SomeGroupByProperty)
        .SelectMax(x => x.MaxPerGroupProperty)
    );

这是一个超简化的解决方案,带有WHERE子句。我们很可能需要在HAVING子句中应用该过滤器。以下是如何:

的详细示例

Query on HasMany reference

因此,子查询看起来像这样:

var query = session
    .QueryOver(() => otherEntity)
    .WithSubquery
    .WhereExists(subquery);

完整的example here

答案 2 :(得分:0)

您可以使用自己的投影来执行此操作,这与NHibernate ProjectionList类似,ToSqlStringGetTypesGetTypedValues方法的实现略有不同。

public static class CustomProjections
{
    public static ProjectionWithGroupByWithoutSelectProjection GroupByWithoutSelect(IProjection projection, params Expression<Func<object>>[] groupByExpressions)
    {
        var projectionRet = new ProjectionWithGroupByWithoutSelectProjection();
        projectionRet.Add(projection);
        foreach (var groupByExpression in groupByExpressions)
        {
            projectionRet.Add(Projections.Group(groupByExpression));
        }

        return projectionRet;
    }
}

public class ProjectionWithGroupByWithoutSelectProjection : IProjection
{
    // because ProjectionList constructor is protected internal
    private class ProjectionListCustom : ProjectionList
    {
    }

    private readonly ProjectionList _projectionList = new ProjectionListCustom();

    protected internal ProjectionWithGroupByWithoutSelectProjection()
    {
    }

    public ProjectionWithGroupByWithoutSelectProjection Add(IProjection proj)
    {
        _projectionList.Add(proj);
        return this;
    }

    public ProjectionWithGroupByWithoutSelectProjection Add(IProjection projection, string alias)
    {
        _projectionList.Add(projection, alias);
        return this;
    }

    public ProjectionWithGroupByWithoutSelectProjection Add<T>(IProjection projection, Expression<Func<T>> alias)
    {
        _projectionList.Add(projection, alias);
        return this;
    }

    public IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery)
    {
        return _projectionList[0].GetTypes(criteria, criteriaQuery);
    }

    public SqlString ToSqlString(ICriteria criteria, int loc, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
    {
        return _projectionList[0].ToSqlString(criteria, loc, criteriaQuery, enabledFilters);
    }

    public SqlString ToGroupSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
    {
        return _projectionList.ToGroupSqlString(criteria, criteriaQuery, enabledFilters);
    }

    public string[] GetColumnAliases(int position, ICriteria criteria, ICriteriaQuery criteriaQuery)
    {
        return _projectionList.GetColumnAliases(position, criteria, criteriaQuery);
    }

    public string[] GetColumnAliases(string alias, int position, ICriteria criteria, ICriteriaQuery criteriaQuery)
    {
        return _projectionList.GetColumnAliases(alias, position, criteria, criteriaQuery);
    }

    public IType[] GetTypes(string alias, ICriteria criteria, ICriteriaQuery criteriaQuery)
    {
        return _projectionList[0].GetTypes(alias, criteria, criteriaQuery);
    }

    public string[] Aliases => _projectionList.Aliases;

    public override string ToString()
    {
        return _projectionList.ToString();
    }

    public bool IsGrouped => _projectionList.IsGrouped;

    public bool IsAggregate => _projectionList.IsAggregate;

    public TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
    {
        return _projectionList[0].GetTypedValues(criteria, criteriaQuery);
    }
}