Skip to content

Commit c119218

Browse files
committed
Handle implicit convert expression in LINQ update with anonymous type.
1 parent 2b0e1f1 commit c119218

File tree

4 files changed

+84
-6
lines changed

4 files changed

+84
-6
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Namespace Issues.GH3716
2+
Public Class Entity
3+
Public Overridable Property Id As Guid
4+
5+
Public Overridable Property Date1 As Date?
6+
End Class
7+
End Namespace
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
Imports NHibernate.Linq
2+
Imports NUnit.Framework
3+
4+
Namespace Issues.GH3716
5+
<TestFixture>
6+
Public Class Fixture
7+
Inherits IssueTestCase
8+
9+
Protected Overrides Sub OnSetUp()
10+
11+
Using session As ISession = OpenSession()
12+
13+
Using transaction As ITransaction = session.BeginTransaction()
14+
15+
Dim e1 = New Entity
16+
e1.Date1 = New Date(2017, 12, 3)
17+
session.Save(e1)
18+
19+
Dim e2 = New Entity
20+
e2.Date1 = New Date(2017, 12, 1)
21+
session.Save(e2)
22+
23+
Dim e3 = New Entity
24+
session.Save(e3)
25+
26+
session.Flush()
27+
transaction.Commit()
28+
29+
End Using
30+
31+
End Using
32+
End Sub
33+
34+
Protected Overrides Sub OnTearDown()
35+
36+
Using session As ISession = OpenSession()
37+
38+
Using transaction As ITransaction = session.BeginTransaction()
39+
40+
session.Delete("from System.Object")
41+
42+
session.Flush()
43+
transaction.Commit()
44+
45+
End Using
46+
47+
End Using
48+
End Sub
49+
50+
<Test>
51+
Public Sub ShouldBeAbleToUpdateWithAnonymousType()
52+
53+
Using session As ISession = OpenSession()
54+
session.Query(Of Entity).Update(Function(x) New With {.Date1 = Date.Today})
55+
End Using
56+
End Sub
57+
End Class
58+
End Namespace
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test.VisualBasic" namespace="NHibernate.Test.VisualBasic.Issues.GH3716">
3+
4+
<class name="Entity">
5+
<id name="Id">
6+
<generator class="guid.comb"/>
7+
</id>
8+
<property name="Date1" />
9+
</class>
10+
11+
</hibernate-mapping>

src/NHibernate/Linq/DmlExpressionRewriter.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ void AddSettersFromBindings(IEnumerable<MemberBinding> bindings, string path)
2525
switch (node.BindingType)
2626
{
2727
case MemberBindingType.Assignment:
28-
AddSettersFromAssignment((MemberAssignment)node, subPath);
28+
AddSettersFromAssignment((MemberAssignment) node, subPath);
2929
break;
3030
case MemberBindingType.MemberBinding:
31-
AddSettersFromBindings(((MemberMemberBinding)node).Bindings, subPath);
31+
AddSettersFromBindings(((MemberMemberBinding) node).Bindings, subPath);
3232
break;
3333
default:
3434
throw new InvalidOperationException($"{node.BindingType} is not supported");
@@ -53,10 +53,10 @@ void AddSettersFromAnonymousConstructor(NewExpression newExpression, string path
5353
switch (argument.NodeType)
5454
{
5555
case ExpressionType.New:
56-
AddSettersFromAnonymousConstructor((NewExpression)argument, subPath);
56+
AddSettersFromAnonymousConstructor((NewExpression) argument, subPath);
5757
break;
5858
case ExpressionType.MemberInit:
59-
AddSettersFromBindings(((MemberInitExpression)argument).Bindings, subPath);
59+
AddSettersFromBindings(((MemberInitExpression) argument).Bindings, subPath);
6060
break;
6161
default:
6262
_assignments.Add(subPath.Substring(1), Expression.Lambda(argument, _parameters));
@@ -121,9 +121,11 @@ public static Expression PrepareExpressionFromAnonymous<TSource>(Expression sour
121121
if (expression == null)
122122
throw new ArgumentNullException(nameof(expression));
123123

124-
// Anonymous initializations are not implemented as member initialization but as plain constructor call.
124+
// Anonymous initializations are not implemented as member initialization but as plain constructor call, potentially wrapped in a Convert expression
125125
var newExpression = expression.Body as NewExpression ??
126-
throw new ArgumentException("The expression must be an anonymous initialization, e.g. x => new { Name = x.Name, Age = x.Age + 5 }");
126+
(expression.Body is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.Convert && unaryExpression.Operand is NewExpression newExpressionOperand
127+
? newExpressionOperand
128+
: throw new ArgumentException("The expression must be an anonymous initialization, e.g. x => new { Name = x.Name, Age = x.Age + 5 }"));
127129

128130
var instance = new DmlExpressionRewriter(expression.Parameters);
129131
instance.AddSettersFromAnonymousConstructor(newExpression, "");

0 commit comments

Comments
 (0)