Skip to content

Skip transparent cast for unknown ident types in hql conditional expression #2713

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

Merged
merged 2 commits into from
Mar 31, 2021
Merged
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
72 changes: 72 additions & 0 deletions src/NHibernate.Test/Async/NHSpecificTest/GH2707/FixtureByCode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


using System.Linq;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Mapping.ByCode;
using NUnit.Framework;
using NHibernate.Linq;

namespace NHibernate.Test.NHSpecificTest.GH2707
{
using System.Threading.Tasks;
[TestFixture]
public class ConditionalFixtureAsync : TestCaseMappingByCode
{
protected override HbmMapping GetMappings()
{
var mapper = new ModelMapper();

mapper.AddMapping<Entity1Map>();
return mapper.CompileMappingForAllExplicitlyAddedEntities();
}

protected override void OnSetUp()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
var e1 = new Entity1() {Id = "id1", IsChiusa = true};
e1.CustomType = new MyType() {ToPersist = 1};
session.Save(e1);
var e2 = new Entity1() {Id = "id2", IsChiusa = false};
session.Save(e2);
e1.Parent = e1;
transaction.Commit();
}
}

protected override void OnTearDown()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
session.CreateQuery("delete from System.Object").ExecuteUpdate();
transaction.Commit();
}
}

[Test]
public async Task EntityAndCustomTypeInConditionalResultAsync()
{
using (var s = OpenSession())
await ((from x in s.Query<Entity1>()
let parent = x.Parent
//NH-3005 - Contditional on custom type
where (parent.IsChiusa ? x.CustomType : parent.CustomType) == x.CustomType
select new
{
ParentIsChiusa = (((x == null) ? null : x.Parent) == null)
? (bool?) null
: x.Parent.IsChiusa,
}).ToListAsync());
}
}
}
139 changes: 139 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/GH2707/Entity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using System;
using System.Data.Common;
using NHibernate.Engine;
using NHibernate.Mapping.ByCode.Conformist;
using NHibernate.SqlTypes;
using NHibernate.UserTypes;

namespace NHibernate.Test.NHSpecificTest.GH2707
{
public class Entity1
{
public virtual string Id { get; set; }
public virtual bool IsChiusa { get; set; }
public virtual MyType CustomType { get; set; }
public virtual Entity1 Parent { get; set; }
}

class Entity1Map : ClassMapping<Entity1>
{
public Entity1Map()
{
Table("TA");

Id(x => x.Id);
Property(x => x.IsChiusa);
Property(x => x.CustomType, m => m.Type<SimpleCustomType>());
ManyToOne(x => x.Parent, x => x.ForeignKey("none"));
}
}

public class MyType
{
public int ToPersist { get; set; }

public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}

var other = (MyType) obj;
return ToPersist == other.ToPersist;
}

public override int GetHashCode()
{
return ToPersist.GetHashCode();
}
}

public class SimpleCustomType : IUserType
{
private static readonly SqlType[] ReturnSqlTypes = {SqlTypeFactory.Int32};

#region IUserType Members

public new bool Equals(object x, object y)
{
if (ReferenceEquals(x, y))
{
return true;
}

if (ReferenceEquals(null, x) || ReferenceEquals(null, y))
{
return false;
}

return x.Equals(y);
}

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

public SqlType[] SqlTypes
{
get { return ReturnSqlTypes; }
}

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

public void NullSafeSet(DbCommand cmd, object value, int index, ISessionImplementor session)
{
if (value == null)
{
cmd.Parameters[index].Value = DBNull.Value;
}
else
{
cmd.Parameters[index].Value = ((MyType) value).ToPersist;
}
}

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

public object NullSafeGet(DbDataReader rs, string[] names, ISessionImplementor session, object owner)
{
int index0 = rs.GetOrdinal(names[0]);
if (rs.IsDBNull(index0))
{
return null;
}

int value = rs.GetInt32(index0);
return new MyType {ToPersist = value};
}

public bool IsMutable
{
get { return false; }
}

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;
}

#endregion
}
}
60 changes: 60 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/GH2707/FixtureByCode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System.Linq;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Mapping.ByCode;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.GH2707
{
[TestFixture]
public class ConditionalFixture : TestCaseMappingByCode
{
protected override HbmMapping GetMappings()
{
var mapper = new ModelMapper();

mapper.AddMapping<Entity1Map>();
return mapper.CompileMappingForAllExplicitlyAddedEntities();
}

protected override void OnSetUp()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
var e1 = new Entity1() {Id = "id1", IsChiusa = true};
e1.CustomType = new MyType() {ToPersist = 1};
session.Save(e1);
var e2 = new Entity1() {Id = "id2", IsChiusa = false};
session.Save(e2);
e1.Parent = e1;
transaction.Commit();
}
}

protected override void OnTearDown()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
session.CreateQuery("delete from System.Object").ExecuteUpdate();
transaction.Commit();
}
}

[Test]
public void EntityAndCustomTypeInConditionalResult()
{
using (var s = OpenSession())
(from x in s.Query<Entity1>()
let parent = x.Parent
//NH-3005 - Conditional with custom type
where (parent.IsChiusa ? x.CustomType : parent.CustomType) == x.CustomType
select new
{
ParentIsChiusa = (((x == null) ? null : x.Parent) == null)
? (bool?) null
: x.Parent.IsChiusa,
}).ToList();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ protected HqlTreeNode VisitConditionalExpression(ConditionalExpression expressio
// If both operands are parameters, HQL will not be able to determine the resulting type before
// parameters binding. But it has to compute result set columns type before parameters are bound,
// so an artificial cast is introduced to hint HQL at the resulting type.
return expression.Type == typeof(bool) || expression.Type == typeof(bool?)
return expression.Type == typeof(bool) || expression.Type == typeof(bool?) || !HqlIdent.SupportsType(expression.Type)
? @case
: _hqlTreeBuilder.TransparentCast(@case, expression.Type);
}
Expand Down