Skip to content

Commit

Permalink
Merge tag '4.1.1.GA'
Browse files Browse the repository at this point in the history
# Conflicts:
#	build-common/common.xml
  • Loading branch information
hazzik committed Feb 2, 2017
2 parents 36100cc + b64b6b7 commit 252d3f3
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 28 deletions.
15 changes: 15 additions & 0 deletions releasenotes.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
Build 4.1.1.GA
=============================

##### Notes #####
The [NH-3904] has been reverted in favor of [NH-2401]: users now required to explicitly specify
custom user type via MappedAs method if they want to use IUserType/ICompositeUserType type
parameters in Linq queries, or implement generators the way they take the types into account.

** Sub-task
* [NH-3940] - Revert NH-3904

** Bug
* [NH-3929] - ExpressionParameterVisitor selects wrong CustomType for ConstantExpression (Linq)
* [NH-3941] - MappedAs() does not work

Build 4.1.0.GA
=============================

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;
using System.Data;
using NHibernate.SqlTypes;
using NHibernate.UserTypes;

namespace NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators
{
public class DoubleStringUserType : IUserType
{
public SqlType[] SqlTypes
{
get { return new[] { SqlTypeFactory.GetString(20) }; }
}

public System.Type ReturnedType
{
get { return typeof(string); }
}

public bool IsMutable
{
get { return false; }
}

public int GetHashCode(object x)
{
if (x == null)
{
return 0;
}
return x.GetHashCode();
}

public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
object obj = NHibernateUtil.String.NullSafeGet(rs, names[0]);
if (obj == null)
{
return null;
}
return Convert.ToDouble((string)obj);
}

public void NullSafeSet(IDbCommand cmd, object value, int index)
{
if (value == null)
{
((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
}
else
{
var doubleValue = (double)value;
((IDataParameter)cmd.Parameters[index]).Value = doubleValue.ToString();
}
}

public object DeepCopy(object value)
{
return value;
}

public object Replace(object original, object target, object owner)
{
return original;
}

public object Assemble(object cached, object owner)
{
return cached;
}

public object Disassemble(object value)
{
return value;
}

bool IUserType.Equals(object x, object y)
{
return object.Equals(x, y);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public class EntityWithUserTypeProperty
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IExample Example { get; set; }
public virtual double DoubleStoredAsString { get; set; }
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using NHibernate.Linq;
using NUnit.Framework;


namespace NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators
{

Expand Down Expand Up @@ -71,7 +70,6 @@ protected override void OnTearDown()
}
}


[Test]
public void EqualityWorksForUserType()
{
Expand All @@ -80,14 +78,14 @@ public void EqualityWorksForUserType()
{
var newItem = new BarExample { Value = "Larry" };
var entities = session.Query<EntityWithUserTypeProperty>()
.Where(x=>x.Example == newItem)
.Where(x => x.Example == newItem)
.ToList();

Assert.AreEqual(1, entities.Count);
}
}

[Test]
[Test, Ignore("Not implemented yet")]
public void LinqMethodWorksForUserType()
{
using (var session = OpenSession())
Expand All @@ -102,6 +100,50 @@ public void LinqMethodWorksForUserType()
}
}

[Test]
public void EqualityWorksForExplicitUserType()
{
using (var session = OpenSession())
using (session.BeginTransaction())
{
var newItem = new BarExample { Value = "Larry" };
var entities = session.Query<EntityWithUserTypeProperty>()
.Where(x => x.Example == newItem.MappedAs(NHibernateUtil.Custom(typeof(ExampleUserType))))
.ToList();

Assert.AreEqual(1, entities.Count);
}
}

[Test]
public void LinqMethodWorksForExplicitUserType()
{
using (var session = OpenSession())
using (session.BeginTransaction())
{
var newItem = new BarExample { Value = "Larry" };
var entities = session.Query<EntityWithUserTypeProperty>()
.Where(x => x.Example.IsEquivalentTo(newItem.MappedAs(NHibernateUtil.Custom(typeof(ExampleUserType)))))
.ToList();

Assert.AreEqual(2, entities.Count);
}
}

[Test]
public void LinqMethodWorksForStandardStringProperty()
{
using (var session = OpenSession())
using (session.BeginTransaction())
{
var entities = session.Query<EntityWithUserTypeProperty>()
.Where(x => x.Name == "Bob")
.ToList();

Assert.AreEqual(1, entities.Count);
}
}

[Test]
public void CanQueryWithHql()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
</id>
<property name="Name" />
<property name="Example" type="NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators.ExampleUserType, NHibernate.Test" />
<property name="DoubleStoredAsString" type="NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators.DoubleStringUserType, NHibernate.Test" />
</class>
</hibernate-mapping>
</hibernate-mapping>
1 change: 1 addition & 0 deletions src/NHibernate.Test/NHibernate.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,7 @@
<Compile Include="Linq\ByMethod\DistinctTests.cs" />
<Compile Include="Component\Basic\ComponentWithUniqueConstraintTests.cs" />
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\BarExample.cs" />
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\DoubleStringUserType.cs" />
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\EntityWithUserTypeProperty.cs" />
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\EntityWithUserTypePropertyIsEquivalentGenerator.cs" />
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\EntityWithUserTypePropertyGeneratorsRegistry.cs" />
Expand Down
5 changes: 2 additions & 3 deletions src/NHibernate/Linq/NhLinqExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,13 @@ public class NhLinqExpression : IQueryExpression
public NhLinqExpression(Expression expression, ISessionFactoryImplementor sessionFactory)
{
_expression = NhPartialEvaluatingExpressionTreeVisitor.EvaluateIndependentSubtrees(expression);

// We want logging to be as close as possible to the original expression sent from the
// application. But if we log before partial evaluation, the log won't include e.g.
// subquery expressions if those are defined by the application in a variable referenced
// from the main query.
LinqLogging.LogExpression("Expression (partially evaluated)", _expression);

_constantToParameterMap = ExpressionParameterVisitor.Visit(_expression, sessionFactory);
_constantToParameterMap = ExpressionParameterVisitor.Visit(ref _expression, sessionFactory);

ParameterValuesByName = _constantToParameterMap.Values.ToDictionary(p => p.Name,
p => System.Tuple.Create(p.Value, p.Type));
Expand Down Expand Up @@ -77,4 +76,4 @@ internal void CopyExpressionTranslation(NhLinqExpression other)
ParameterDescriptors = other.ParameterDescriptors;
}
}
}
}
30 changes: 10 additions & 20 deletions src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@ public class ExpressionParameterVisitor : ExpressionTreeVisitor
ReflectionHelper.GetMethodDefinition(() => Enumerable.Take<object>(null, 0)),
};

private readonly List<CustomType> _allMappedCustomTypes;

public ExpressionParameterVisitor(ISessionFactoryImplementor sessionFactory)
{
_sessionFactory = sessionFactory;
_allMappedCustomTypes = _sessionFactory.GetAllClassMetadata().Values
.SelectMany(c => c.PropertyTypes)
.OfType<CustomType>().ToList();
}

public static IDictionary<ConstantExpression, NamedParameter> Visit(Expression expression, ISessionFactoryImplementor sessionFactory)
{
return Visit(ref expression, sessionFactory);
}

internal static IDictionary<ConstantExpression, NamedParameter> Visit(ref Expression expression, ISessionFactoryImplementor sessionFactory)
{
var visitor = new ExpressionParameterVisitor(sessionFactory);
visitor.VisitExpression(expression);

expression = visitor.VisitExpression(expression);

return visitor._parameters;
}
Expand All @@ -49,10 +49,10 @@ protected override Expression VisitMethodCallExpression(MethodCallExpression exp
{
if (expression.Method.Name == "MappedAs" && expression.Method.DeclaringType == typeof(LinqExtensionMethods))
{
var parameter = (ConstantExpression) VisitExpression(expression.Arguments[0]);
var type = (ConstantExpression) expression.Arguments[1];
var parameter = (ConstantExpression)VisitExpression(expression.Arguments[0]);
var type = (ConstantExpression)expression.Arguments[1];

_parameters[parameter].Type = (IType) type.Value;
_parameters[parameter].Type = (IType)type.Value;

return parameter;
}
Expand Down Expand Up @@ -94,16 +94,6 @@ protected override Expression VisitConstantExpression(ConstantExpression express
if (expression.Value == null)
type = NHibernateUtil.GuessType(expression.Type);

if (type == null)
{
var customType =
_allMappedCustomTypes.FirstOrDefault(ct => ct.UserType.ReturnedType.IsAssignableFrom(expression.Type));
if (customType != null)
{
type = customType;
}
}

// Constant characters should be sent as strings
if (expression.Type == typeof(char))
{
Expand Down

0 comments on commit 252d3f3

Please sign in to comment.