Skip to content

Regression caused by NH-3904 #547

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

Closed
wants to merge 1 commit into from
Closed
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
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 @@ -725,6 +725,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