Skip to content

NH-3800 and NH-3681 #433

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions src/NHibernate.Test/Linq/ByMethod/GroupByTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -507,14 +507,22 @@ public void ProjectingWithSubQueriesFilteredByTheAggregateKey()
Assert.That(result[15].FirstOrder, Is.EqualTo(10255));
}

[Test(Description = "NH-3681"), KnownBug("NH-3681 not yet fixed", "NHibernate.HibernateException")]
[Test(Description = "NH-3681")]
public void SelectManyGroupByAggregateProjection()
{
var result = (from o in db.Orders
from ol in o.OrderLines
group ol by ol.Product.ProductId
into grp
select new {ProductId = grp.Key, Sum = grp.Sum(x => x.UnitPrice)}
from ol in o.OrderLines
group ol by ol.Product.ProductId
into grp
select new
{
ProductId = grp.Key,
Sum = grp.Sum(x => x.UnitPrice),
Count = grp.Count(),
Avg = grp.Average(x => x.UnitPrice),
Min = grp.Min(x => x.UnitPrice),
Max = grp.Max(x => x.UnitPrice),
}
).ToList();

Assert.That(result.Count, Is.EqualTo(77));
Expand Down
48 changes: 48 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/NH3800/Domain.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NHibernate.Test.NHSpecificTest.NH3800
{
public class Project
{
public Project()
{
Components = new List<Component>();
}

public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Component> Components { get; set; }
}

public class Component
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual Project Project { get; set; }
}

public class TimeRecord
{
public TimeRecord()
{
Components = new List<Component>();
Tags = new List<Tag>();
}

public virtual Guid Id { get; set; }
public virtual double TimeInHours { get; set; }
public virtual Project Project { get; set; }
public virtual IList<Component> Components { get; set; }
public virtual IList<Tag> Tags { get; set; }

}

public class Tag
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
}
}
193 changes: 193 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/NH3800/Fixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading;
using NHibernate.Linq;
using NHibernate.Test.ExceptionsTest;
using NHibernate.Test.MappingByCode;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.NH3800
{
[TestFixture]
public class Fixture : BugTestCase
{
protected override void OnSetUp()
{
var tagA = new Tag() { Name = "A" };
var tagB = new Tag() { Name = "B" };

var project1 = new Project { Name = "ProjectOne" };
var compP1_x = new Component() { Name = "PONEx", Project = project1 };
var compP1_y = new Component() { Name = "PONEy", Project = project1 };

var project2 = new Project { Name = "ProjectTwo" };
var compP2_x = new Component() { Name = "PTWOx", Project = project2 };
var compP2_y = new Component() { Name = "PTWOy", Project = project2 };

using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
session.Save(tagA);
session.Save(tagB);
session.Save(project1);
session.Save(compP1_x);
session.Save(compP1_y);
session.Save(project2);
session.Save(compP2_x);
session.Save(compP2_y);

session.Save(new TimeRecord { TimeInHours = 1, Project = null, Components = { }, Tags = { tagA } });
session.Save(new TimeRecord { TimeInHours = 2, Project = null, Components = { }, Tags = { tagB } });

session.Save(new TimeRecord { TimeInHours = 3, Project = project1, Tags = { tagA, tagB } });
session.Save(new TimeRecord { TimeInHours = 4, Project = project1, Components = { compP1_x }, Tags = { tagB } });
session.Save(new TimeRecord { TimeInHours = 5, Project = project1, Components = { compP1_y }, Tags = { tagA } });
session.Save(new TimeRecord { TimeInHours = 6, Project = project1, Components = { compP1_x, compP1_y }, Tags = { } });

session.Save(new TimeRecord { TimeInHours = 7, Project = project2, Components = { }, Tags = { tagA, tagB } });
session.Save(new TimeRecord { TimeInHours = 8, Project = project2, Components = { compP2_x }, Tags = { tagB } });
session.Save(new TimeRecord { TimeInHours = 9, Project = project2, Components = { compP2_y }, Tags = { tagA } });
session.Save(new TimeRecord { TimeInHours = 10, Project = project2, Components = { compP2_x, compP2_y }, Tags = { } });

transaction.Commit();
}
}

protected override void OnTearDown()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
session.Delete("from TimeRecord");
session.Delete("from Component");
session.Delete("from Project");
session.Delete("from Tag");

transaction.Commit();
}
}

[Test]
public void ExpectedHql()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
var baseQuery = session.Query<TimeRecord>();

Assert.That(baseQuery.Sum(x => x.TimeInHours), Is.EqualTo(55));

var query = session.CreateQuery(@"
select c.Id, count(t), sum(cast(t.TimeInHours as big_decimal))
from TimeRecord t
left join t.Components as c
group by c.Id");

var results = query.List<object[]>();
Assert.That(results.Select(x => x[1]), Is.EquivalentTo(new[] { 4, 2, 2, 2, 2 }));
Assert.That(results.Select(x => x[2]), Is.EquivalentTo(new[] { 13, 10, 11, 18, 19 }));

Assert.That(results.Sum(x => (decimal?)x[2]), Is.EqualTo(71));

transaction.Rollback();
}
}

[Test]
public void PureLinq()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
var baseQuery = session.Query<TimeRecord>();
var query = from t in baseQuery
from c in t.Components.Select(x => (object)x.Id).DefaultIfEmpty()
let r = new object[] { c, t }
group r by r[0]
into g
select new[] { g.Key, g.Select(x => x[1]).Count(), g.Select(x => x[1]).Sum(x => (decimal?)((TimeRecord)x).TimeInHours) };

var results = query.ToList();
Assert.That(results.Select(x => x[1]), Is.EquivalentTo(new[] { 4, 2, 2, 2, 2 }));
Assert.That(results.Select(x => x[2]), Is.EquivalentTo(new[] { 13, 10, 11, 18, 19 }));

Assert.That(results.Sum(x => (decimal?)x[2]), Is.EqualTo(71));

transaction.Rollback();
}
}

[Test]
public void MethodGroup()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
var baseQuery = session.Query<TimeRecord>();
var query = baseQuery
.SelectMany(t => t.Components.Select(c => c.Id).DefaultIfEmpty().Select(c => new object[] { c, t }))
.GroupBy(g => g[0], g => (TimeRecord)g[1])
.Select(g => new[] { g.Key, g.Count(), g.Sum(x => (decimal?)x.TimeInHours) });

var results = query.ToList();
Assert.That(results.Select(x => x[1]), Is.EquivalentTo(new[] { 4, 2, 2, 2, 2 }));
Assert.That(results.Select(x => x[2]), Is.EquivalentTo(new[] { 13, 10, 11, 18, 19 }));

Assert.That(results.Sum(x => (decimal?)x[2]), Is.EqualTo(71));

transaction.Rollback();
}
}

[Test]
public void ComplexExample()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
var baseQuery = session.Query<TimeRecord>();

Assert.That(baseQuery.Sum(x => x.TimeInHours), Is.EqualTo(55));

var query = baseQuery.Select(t => new object[] { t })
.SelectMany(t => ((TimeRecord)t[0]).Components.Select(c => (object)c.Id).DefaultIfEmpty().Select(c => new[] { t[0], c }))
.SelectMany(t => ((TimeRecord)t[0]).Tags.Select(x => (object)x.Id).DefaultIfEmpty().Select(x => new[] { t[0], t[1], x }))
.GroupBy(j => new[] { ((TimeRecord)j[0]).Project.Id, j[1], j[2] }, j => (TimeRecord)j[0])
.Select(g => new object[] { g.Key, g.Count(), g.Sum(t => (decimal?)t.TimeInHours) });

var results = query.ToList();
Assert.That(results.Select(x => x[1]), Is.EquivalentTo(new[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }));
Assert.That(results.Select(x => x[2]), Is.EquivalentTo(new[] { 1, 2, 3, 3, 4, 5, 6, 6, 7, 7, 8, 9, 10, 10 }));

Assert.That(results.Sum(x => (decimal?)x[2]), Is.EqualTo(81));

transaction.Rollback();
}
}

[Test]
public void OuterJoinGroupingWithSubQueryInProjection()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
var baseQuery = session.Query<TimeRecord>();
var query = baseQuery
.SelectMany(t => t.Components.Select(c => c.Name).DefaultIfEmpty().Select(c => new object[] { c, t }))
.GroupBy(g => g[0], g => (TimeRecord)g[1])
.Select(g => new[] { g.Key, g.Count(), session.Query<Component>().Count(c => c.Name == (string)g.Key) });

var results = query.ToList();
Assert.That(results.Select(x => x[1]), Is.EquivalentTo(new[] { 4, 2, 2, 2, 2 }));
Assert.That(results.Select(x => x[2]), Is.EquivalentTo(new[] { 0, 1, 1, 1, 1 }));

transaction.Rollback();
}
}
}
}
58 changes: 58 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/NH3800/Mappings.hbm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="NHibernate.Test.NHSpecificTest.NH3800"
assembly="NHibernate.Test">

<class name="Project">
<id name="Id" column="ProjectId">
<generator class="guid.comb"/>
</id>
<property name="Name" not-null="true"/>
<bag name="Components" inverse="true" lazy="true" fetch="select">
<key>
<column name="ProjectId" not-null="true" />
</key>
<one-to-many class="Component" />
</bag>
</class>

<class name="Component">
<id name="Id" column="ComponentId">
<generator class="guid.comb"/>
</id>
<property name="Name" not-null="true"/>
<many-to-one name="Project" column="ProjectId" class="Project" not-null="true"/>
</class>

<class name="TimeRecord">
<id name="Id" column="TimeRecordId">
<generator class="guid.comb"/>
</id>
<property name="TimeInHours" not-null="true"/>
<many-to-one name="Project" column="ProjectId" class="Project" />
<bag name="Components" inverse="false" lazy="true" fetch="select">
<key>
<column name="TimeRecordId" not-null="true" />
</key>
<many-to-many class="Component">
<column name="ComponentId" not-null="true" />
</many-to-many>
</bag>
<bag name="Tags" inverse="false" lazy="true" fetch="select">
<key>
<column name="TimeRecordId" not-null="true" />
</key>
<many-to-many class="Tag">
<column name="TagId" not-null="true" />
</many-to-many>
</bag>
</class>

<class name="Tag">
<id name="Id" column="TagId">
<generator class="guid.comb"/>
</id>
<property name="Name" not-null="true"/>
</class>

</hibernate-mapping>
5 changes: 5 additions & 0 deletions src/NHibernate.Test/NHibernate.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,8 @@
<Compile Include="NHSpecificTest\NH2860\SampleTest.cs" />
<Compile Include="NHSpecificTest\NH3641\Domain.cs" />
<Compile Include="NHSpecificTest\NH3641\TestFixture.cs" />
<Compile Include="NHSpecificTest\NH3800\Domain.cs" />
<Compile Include="NHSpecificTest\NH3800\Fixture.cs" />
<Compile Include="NHSpecificTest\Properties\CompositePropertyRefTest.cs" />
<Compile Include="NHSpecificTest\Properties\DynamicEntityTest.cs" />
<Compile Include="NHSpecificTest\Properties\Model.cs" />
Expand Down Expand Up @@ -3147,6 +3149,9 @@
</EmbeddedResource>
<EmbeddedResource Include="VersionTest\Db\MsSQL\ProductWithVersionAndLazyProperty.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH3754\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH3800\Mappings.hbm.xml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="LazyComponentTest\Person.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH3372\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH3567\Mappings.hbm.xml" />
Expand Down
23 changes: 22 additions & 1 deletion src/NHibernate/Linq/ExpressionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using System;
using System.Linq;
using System.Linq.Expressions;
using Remotion.Linq.Clauses;
using Remotion.Linq.Clauses.Expressions;
Expand Down Expand Up @@ -32,5 +33,25 @@ public static bool IsGroupingKeyOf(this MemberExpression expression,GroupResultO

return query.QueryModel.ResultOperators.Contains(groupBy);
}

public static bool IsGroupingElementOf(this QuerySourceReferenceExpression expression, GroupResultOperator groupBy)
{
var fromClause = expression.ReferencedQuerySource as MainFromClause;
if (fromClause == null) return false;

var innerQuerySource = fromClause.FromExpression as QuerySourceReferenceExpression;
if (innerQuerySource == null) return false;

if (innerQuerySource.ReferencedQuerySource.ItemName != groupBy.ItemName
|| innerQuerySource.ReferencedQuerySource.ItemType != groupBy.ItemType) return false;

var innerFromClause = innerQuerySource.ReferencedQuerySource as MainFromClause;
if (innerFromClause == null) return false;

var query = innerFromClause.FromExpression as SubQueryExpression;
if (query == null) return false;

return query.QueryModel.ResultOperators.Contains(groupBy);
}
}
}
Loading