Skip to content

Commit f2ea7b5

Browse files
committed
Enhance nullability check for "==" and "!=" operators for LINQ provider
1 parent c79ea1f commit f2ea7b5

16 files changed

+1028
-24
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System.Collections.Generic;
2+
3+
namespace NHibernate.DomainModel.Northwind.Entities
4+
{
5+
public class AnotherEntityRequired
6+
{
7+
public virtual int Id { get; set; }
8+
9+
public virtual string Output { get; set; }
10+
11+
public virtual string Input { get; set; }
12+
13+
public virtual Address Address { get; set; }
14+
15+
public virtual AnotherEntityNullability InputNullability { get; set; }
16+
17+
public virtual string NullableOutput { get; set; }
18+
19+
public virtual AnotherEntityRequired NullableAnotherEntityRequired { get; set; }
20+
21+
public virtual int? NullableAnotherEntityRequiredId { get; set; }
22+
23+
public virtual ISet<AnotherEntity> RelatedItems { get; set; } = new HashSet<AnotherEntity>();
24+
25+
public virtual bool? NullableBool { get; set; }
26+
}
27+
28+
public enum AnotherEntityNullability
29+
{
30+
False = 0,
31+
True = 1
32+
}
33+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="NHibernate.DomainModel.Northwind.Entities" assembly="NHibernate.DomainModel">
3+
<class name="AnotherEntityRequired" table="AnotherEntity" mutable="false" schema-action="none">
4+
<id name="Id">
5+
<generator class="native" />
6+
</id>
7+
<property name="Output" not-null="true" />
8+
<property name="Input" not-null="true" />
9+
<property name="NullableOutput" formula="Output" lazy="true" />
10+
<property name="InputNullability" formula="case when Input is not null then 0 else 1 end" lazy="true" />
11+
<property name="NullableAnotherEntityRequiredId" formula="Id" lazy="true" />
12+
<property name="NullableBool" formula="null" lazy="true" />
13+
<component name="Address" insert="false" update="false" lazy="true">
14+
<property name="Street" formula="Input" access="field.camelcase-underscore" />
15+
<property name="City" formula="Output" access="field.camelcase-underscore" />
16+
</component>
17+
<many-to-one name="NullableAnotherEntityRequired" formula="Id" />
18+
<set name="RelatedItems" lazy="true" inverse="true">
19+
<key column="Id"/>
20+
<one-to-many class="AnotherEntity"/>
21+
</set>
22+
</class>
23+
</hibernate-mapping>

src/NHibernate.Test/Async/Linq/NullComparisonTests.cs

Lines changed: 307 additions & 0 deletions
Large diffs are not rendered by default.

src/NHibernate.Test/Linq/LinqTestCase.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ protected override string[] Mappings
2929
"Northwind.Mappings.Supplier.hbm.xml",
3030
"Northwind.Mappings.Territory.hbm.xml",
3131
"Northwind.Mappings.AnotherEntity.hbm.xml",
32+
"Northwind.Mappings.AnotherEntityRequired.hbm.xml",
3233
"Northwind.Mappings.Role.hbm.xml",
3334
"Northwind.Mappings.User.hbm.xml",
3435
"Northwind.Mappings.TimeSheet.hbm.xml",
@@ -69,4 +70,4 @@ public static void AssertByIds<TEntity, TId>(IEnumerable<TEntity> entities, TId[
6970
Assert.That(entities.Select(x => entityIdGetter(x)), Is.EquivalentTo(expectedIds));
7071
}
7172
}
72-
}
73+
}

src/NHibernate.Test/Linq/NullComparisonTests.cs

Lines changed: 306 additions & 0 deletions
Large diffs are not rendered by default.

src/NHibernate/Linq/Expressions/NhAggregatedExpression.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ protected NhAggregatedExpression(Expression expression, System.Type type)
1616
Type = type;
1717
}
1818

19+
public virtual bool AllowsNullableReturnType => true;
20+
1921
public sealed override System.Type Type { get; }
2022

2123
public Expression Expression { get; }

src/NHibernate/Linq/Expressions/NhCountExpression.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ protected NhCountExpression(Expression expression, System.Type type)
1010
{
1111
}
1212

13+
public override bool AllowsNullableReturnType => false;
14+
1315
protected override Expression Accept(NhExpressionVisitor visitor)
1416
{
1517
return visitor.VisitNhCount(this);

src/NHibernate/Linq/Functions/BaseHqlGeneratorForMethod.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,17 @@
77

88
namespace NHibernate.Linq.Functions
99
{
10-
public abstract class BaseHqlGeneratorForMethod : IHqlGeneratorForMethod
11-
{
12-
public IEnumerable<MethodInfo> SupportedMethods { get; protected set; }
10+
public abstract class BaseHqlGeneratorForMethod : IHqlGeneratorForMethod, IHqlGeneratorForMethodExtended
11+
{
12+
public IEnumerable<MethodInfo> SupportedMethods { get; protected set; }
1313

14-
public abstract HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor);
15-
}
16-
}
14+
public abstract HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor);
15+
16+
public virtual bool AllowsNullableReturnType(MethodInfo method) => true;
17+
18+
bool IHqlGeneratorForMethodExtended.AllowsNullableReturnType(MethodInfo method)
19+
{
20+
return AllowsNullableReturnType(method);
21+
}
22+
}
23+
}

src/NHibernate/Linq/Functions/CompareGenerator.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ internal static bool IsCompareMethod(MethodInfo methodInfo)
5151
methodInfo.DeclaringType.FullName == "System.Data.Services.Providers.DataServiceProviderMethods";
5252
}
5353

54+
public override bool AllowsNullableReturnType(MethodInfo method) => false;
5455

5556
public CompareGenerator()
5657
{
@@ -102,4 +103,4 @@ public IHqlGeneratorForMethod GetMethodGenerator(MethodInfo method)
102103

103104
#endregion
104105
}
105-
}
106+
}

src/NHibernate/Linq/Functions/DictionaryGenerator.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject,
2525

2626
public class DictionaryContainsKeyGenerator : BaseHqlGeneratorForMethod
2727
{
28+
public override bool AllowsNullableReturnType(MethodInfo method) => false;
29+
2830
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
2931
{
3032
return treeBuilder.In(visitor.Visit(arguments[0]).AsExpression(), treeBuilder.Indices(visitor.Visit(targetObject).AsExpression()));
@@ -98,4 +100,4 @@ protected override string MethodName
98100
get { return "get_Item"; }
99101
}
100102
}
101-
}
103+
}

0 commit comments

Comments
 (0)