Skip to content

Commit 5415567

Browse files
Antonis MygiakisfredericDelaporte
Antonis Mygiakis
authored andcommitted
Fix GroupBy to custom class failing with ArgumentException (nhibernate#1705)
Fixes nhibernate#1704
1 parent ee91396 commit 5415567

File tree

5 files changed

+176
-1
lines changed

5 files changed

+176
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System.Linq;
12+
using NUnit.Framework;
13+
using NHibernate.Linq;
14+
15+
namespace NHibernate.Test.NHSpecificTest.GH1704
16+
{
17+
using System.Threading.Tasks;
18+
[TestFixture]
19+
public class FixtureAsync : BugTestCase
20+
{
21+
protected override void OnSetUp()
22+
{
23+
using (var session = OpenSession())
24+
using (var transaction = session.BeginTransaction())
25+
{
26+
var e1 = new Entity { Country = "Greece", City = "Athens", Budget = 100000m };
27+
session.Save(e1);
28+
29+
var e2 = new Entity { Country = "Greece", City = "Chania", Budget = 50000m };
30+
session.Save(e2);
31+
32+
var e3 = new Entity { Country = "Italy", City = "Rome", Budget = 200000m };
33+
session.Save(e3);
34+
35+
var e4 = new Entity { Country = "Italy", City = "Milan", Budget = 100000m };
36+
session.Save(e4);
37+
38+
var e5 = new Entity { Country = "France", City = "Paris", Budget = 300000m };
39+
session.Save(e5);
40+
41+
transaction.Commit();
42+
}
43+
}
44+
45+
protected override void OnTearDown()
46+
{
47+
using (var session = OpenSession())
48+
using (var transaction = session.BeginTransaction())
49+
{
50+
// The HQL delete does all the job inside the database without loading the entities, but it does
51+
// not handle delete order for avoiding violating constraints if any. Use
52+
// session.Delete("from System.Object");
53+
// instead if in need of having NHbernate ordering the deletes, but this will cause
54+
// loading the entities in the session.
55+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
56+
57+
transaction.Commit();
58+
}
59+
}
60+
61+
[Test(Description = "GH-1704")]
62+
public async Task GroupByCustomClassAsKeyAsync()
63+
{
64+
using (var session = OpenSession())
65+
using (session.BeginTransaction())
66+
{
67+
var result = await (session.Query<Entity>()
68+
.GroupBy(a => new GroupByEntity(a.Country))
69+
.Select(a => new { groupby = a.Key, cnt = a.Count(), sum = a.Sum(o => o.Budget) })
70+
.ToListAsync());
71+
72+
Assert.That(result, Has.Count.EqualTo(3));
73+
}
74+
}
75+
}
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH1704
4+
{
5+
class Entity
6+
{
7+
public virtual Guid Id { get; set; }
8+
public virtual string Country { get; set; }
9+
public virtual string City { get; set; }
10+
public virtual decimal Budget { get; set; }
11+
}
12+
13+
class GroupByEntity
14+
{
15+
public GroupByEntity(string country)
16+
{
17+
Country = country;
18+
}
19+
public virtual string Country { get; set; }
20+
public virtual string City { get; set; }
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System.Linq;
2+
using NUnit.Framework;
3+
4+
namespace NHibernate.Test.NHSpecificTest.GH1704
5+
{
6+
[TestFixture]
7+
public class Fixture : BugTestCase
8+
{
9+
protected override void OnSetUp()
10+
{
11+
using (var session = OpenSession())
12+
using (var transaction = session.BeginTransaction())
13+
{
14+
var e1 = new Entity { Country = "Greece", City = "Athens", Budget = 100000m };
15+
session.Save(e1);
16+
17+
var e2 = new Entity { Country = "Greece", City = "Chania", Budget = 50000m };
18+
session.Save(e2);
19+
20+
var e3 = new Entity { Country = "Italy", City = "Rome", Budget = 200000m };
21+
session.Save(e3);
22+
23+
var e4 = new Entity { Country = "Italy", City = "Milan", Budget = 100000m };
24+
session.Save(e4);
25+
26+
var e5 = new Entity { Country = "France", City = "Paris", Budget = 300000m };
27+
session.Save(e5);
28+
29+
transaction.Commit();
30+
}
31+
}
32+
33+
protected override void OnTearDown()
34+
{
35+
using (var session = OpenSession())
36+
using (var transaction = session.BeginTransaction())
37+
{
38+
// The HQL delete does all the job inside the database without loading the entities, but it does
39+
// not handle delete order for avoiding violating constraints if any. Use
40+
// session.Delete("from System.Object");
41+
// instead if in need of having NHbernate ordering the deletes, but this will cause
42+
// loading the entities in the session.
43+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
44+
45+
transaction.Commit();
46+
}
47+
}
48+
49+
[Test(Description = "GH-1704")]
50+
public void GroupByCustomClassAsKey()
51+
{
52+
using (var session = OpenSession())
53+
using (session.BeginTransaction())
54+
{
55+
var result = session.Query<Entity>()
56+
.GroupBy(a => new GroupByEntity(a.Country))
57+
.Select(a => new { groupby = a.Key, cnt = a.Count(), sum = a.Sum(o => o.Budget) })
58+
.ToList();
59+
60+
Assert.That(result, Has.Count.EqualTo(3));
61+
}
62+
}
63+
}
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping
3+
xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test" namespace="NHibernate.Test.NHSpecificTest.GH1704">
4+
<class name="Entity">
5+
<id name="Id" generator="guid.comb"/>
6+
<property name="Country"/>
7+
<property name="City"/>
8+
<property name="Budget"/>
9+
</class>
10+
</hibernate-mapping>

src/NHibernate/Linq/GroupBy/GroupKeyNominator.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ protected override Expression VisitNew(NewExpression expression)
5555
{
5656
_transformed = true;
5757
// Transform each initializer recursively (to allow for nested initializers)
58+
if (expression.Members == null)
59+
return Expression.New(expression.Constructor, expression.Arguments.Select(VisitInternal));
60+
5861
return Expression.New(expression.Constructor, expression.Arguments.Select(VisitInternal), expression.Members);
5962
}
6063

@@ -85,4 +88,4 @@ protected override Expression VisitBinary(BinaryExpression expression)
8588
return base.VisitBinary(expression);
8689
}
8790
}
88-
}
91+
}

0 commit comments

Comments
 (0)