Skip to content

NH-3693 - AliasToBeanResultTransformer fails under Firebird #330

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 14 commits 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
4 changes: 3 additions & 1 deletion src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ private void AssertObjectsAreEqual(object expected, object actual, string name)

if ((expectedType.IsValueType)
|| (expected is System.Type)
|| (expected is string))
|| (expected is string)
|| (expected is FieldInfo)
|| (expected is PropertyInfo))
{
Assert.AreEqual(expected, actual, fieldPath);
_fieldPath.Pop();
Expand Down
15 changes: 15 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/NH1904/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,19 @@ public class Invoice

protected virtual DateTime issued { get; set; }
}

public class InvoiceWithAddress : Invoice
{
public virtual Address BillingAddress { get; set; }
}

public struct Address
{
public string Line { get; set; }
public string line { get; set; }
public string Line2 { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
}
}
47 changes: 47 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/NH1904/StructFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Collections;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.NH1904
{
[TestFixture]
public class StructFixture : BugTestCase
{
protected override IList Mappings =>
new string[]
{
"NHSpecificTest." + BugNumber + ".StructMappings.hbm.xml"
};

[Test]
public void ExecuteQuery()
{
using (ISession session = OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
var invoice = new InvoiceWithAddress
{
Issued = DateTime.Now,
BillingAddress = new Address { Line = "84 rue du 22 septembre", City = "Courbevoie", ZipCode = "92400", Country = "France" }
};
session.Save(invoice);
transaction.Commit();
}

using (ISession session = OpenSession())
{
var invoices = session.CreateCriteria<Invoice>().List<Invoice>();
}
}

protected override void OnTearDown()
{
base.OnTearDown();
using (ISession session = OpenSession())
{
session.CreateQuery("delete from InvoiceWithAddress").ExecuteUpdate();
session.Flush();
}
}
}
}
22 changes: 22 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/NH1904/StructMappings.hbm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernate.Test"
namespace="NHibernate.Test.NHSpecificTest.NH1904">

<class name="InvoiceWithAddress">
<id name="ID" type="Int32">
<generator class="hilo" />
</id>

<property name="Issued" type="DateTime" />

<component name="BillingAddress">
<property name="Line"/>
<property name="Line2"/>
<property name="City"/>
<property name="ZipCode"/>
<property name="Country"/>
</component>
</class>

</hibernate-mapping>
2 changes: 2 additions & 0 deletions src/NHibernate.Test/NHibernate.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,7 @@
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\FooExample.cs" />
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\IExample.cs" />
<Compile Include="Insertordering\NH3931Entities.cs" />
<Compile Include="NHSpecificTest\NH1904\StructFixture.cs" />
<Compile Include="NHSpecificTest\NH3247\Entity.cs" />
<Compile Include="NHSpecificTest\NH3247\Fixture.cs" />
<Compile Include="NHSpecificTest\NH3386\Entity.cs" />
Expand Down Expand Up @@ -3233,6 +3234,7 @@
<EmbeddedResource Include="NHSpecificTest\NH1291AnonExample\Mappings.hbm.xml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="NHSpecificTest\NH1904\StructMappings.hbm.xml" />
<EmbeddedResource Include="Insertordering\FamilyModel\Mappings.hbm.xml" />
<EmbeddedResource Include="Insertordering\AnimalModel\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH3247\Mappings.hbm.xml" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Collections;
using System.Collections.Generic;
using NHibernate.Transform;
Expand Down Expand Up @@ -41,6 +40,43 @@ public struct TestStruct
public string Something { get; set; }
}

public class PublicPropertiesSimpleDTO
{
public object Id { get; set; }
public string Name { get; set; }
}

public class PrivateFieldsSimpleDTO
{
private object id;
private string name;

public object Id { get { return id; } }
public string Name { get { return name; } }
}

public class BasePublicPropsSimpleDTO
{
public object Id { get; set; }
}

public class PublicInheritedPropertiesSimpleDTO : BasePublicPropsSimpleDTO
{
public string Name { get; set; }
}

public class BasePrivateFieldSimpleDTO
{
private object id;
public object Id { get { return id; } }
}

public class PrivateInheritedFieldsSimpleDTO : BasePrivateFieldSimpleDTO
{
private string name;
public string Name { get { return name; } }
}

#region Overrides of TestCase

protected override IList Mappings
Expand Down Expand Up @@ -77,6 +113,99 @@ public void WorkWithOutPublicParameterLessCtor()
}
}

[Test]
public void ToPublicProperties_WithoutAnyProjections()
{
try
{
Setup();

using (ISession s = OpenSession())
{
var transformer = Transformers.AliasToBean<PublicPropertiesSimpleDTO>();
IList<PublicPropertiesSimpleDTO> l = s.CreateSQLQuery("select * from Simple")
.SetResultTransformer(transformer)
.List<PublicPropertiesSimpleDTO>();
Assert.That(l.Count, Is.EqualTo(2));
Assert.That(l, Has.All.Not.Null);
}
}
finally
{
Cleanup();
}
}

[Test]
public void ToPrivateFields_WithoutAnyProjections()
{
try
{
Setup();

using (ISession s = OpenSession())
{
var transformer = Transformers.AliasToBean<PrivateFieldsSimpleDTO>();
IList<PrivateFieldsSimpleDTO> l = s.CreateSQLQuery("select * from Simple")
.SetResultTransformer(transformer)
.List<PrivateFieldsSimpleDTO>();
Assert.That(l.Count, Is.EqualTo(2));
Assert.That(l, Has.All.Not.Null);
}
}
finally
{
Cleanup();
}
}

[Test]
public void ToInheritedPublicProperties_WithoutProjections()
{
try
{
Setup();

using (ISession s = OpenSession())
{
var transformer = Transformers.AliasToBean<PublicInheritedPropertiesSimpleDTO>();
IList<PublicInheritedPropertiesSimpleDTO> l = s.CreateSQLQuery("select * from Simple")
.SetResultTransformer(transformer)
.List<PublicInheritedPropertiesSimpleDTO>();
Assert.That(l.Count, Is.EqualTo(2));
Assert.That(l, Has.All.Not.Null);
}
}
finally
{
Cleanup();
}
}

[Test]
public void ToInheritedPrivateFields_WithoutProjections()
{
try
{
Setup();

using (ISession s = OpenSession())
{
var transformer = Transformers.AliasToBean<PrivateInheritedFieldsSimpleDTO>();
IList<PrivateInheritedFieldsSimpleDTO> l = s.CreateSQLQuery("select * from Simple")
.SetResultTransformer(transformer)
.List<PrivateInheritedFieldsSimpleDTO>();
Assert.That(l.Count, Is.EqualTo(2));
Assert.That(l, Has.All.Not.Null);
Assert.That(l, Has.All.Property("Id").Not.Null);
}
}
finally
{
Cleanup();
}
}

[Test]
public void WorkWithPublicParameterLessCtor()
{
Expand Down
1 change: 1 addition & 0 deletions src/NHibernate/NHibernate.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,7 @@
<Compile Include="Transform\ITupleSubsetResultTransformer.cs" />
<Compile Include="Transform\DistinctRootEntityResultTransformer.cs" />
<Compile Include="Transform\IResultTransformer.cs" />
<Compile Include="Transform\QueryAliasToObjectPropertySetter.cs" />
<Compile Include="Transform\RootEntityResultTransformer.cs" />
<Compile Include="TransientObjectException.cs" />
<Compile Include="Type\AbstractType.cs" />
Expand Down
8 changes: 0 additions & 8 deletions src/NHibernate/Properties/BasicPropertyAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,6 @@ internal static BasicSetter GetSetterOrNull(System.Type type, string propertyNam

BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly;

if (type.IsValueType)
{
// the BindingFlags.IgnoreCase is important here because if type is a struct, the GetProperty method does
// not ignore case by default. If type is a class, it _does_ ignore case... we're better off explicitly
// stating that casing should be ignored so we get the same behavior for both structs and classes
bindingFlags = bindingFlags | BindingFlags.IgnoreCase;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, good for me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does fix NH-1904 for the struct case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes but if we're going towards QueryAliasToObjectPropertySetter then I would suggest a separate PR for this then. I only did it here because it "was" used in AliasToBeanResultTransformer.


PropertyInfo property = type.GetProperty(propertyName, bindingFlags);

if (property != null && property.CanWrite)
Expand Down
38 changes: 7 additions & 31 deletions src/NHibernate/Transform/AliasToBeanResultTransformer.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections;
using System.Reflection;
using NHibernate.Properties;

namespace NHibernate.Transform
{
Expand All @@ -27,10 +26,9 @@ namespace NHibernate.Transform
[Serializable]
public class AliasToBeanResultTransformer : AliasedTupleSubsetResultTransformer
{
private readonly QueryAliasToObjectPropertySetter _propertySetter;
private const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
private readonly System.Type resultClass;
private ISetter[] setters;
private readonly IPropertyAccessor propertyAccessor;
private readonly ConstructorInfo constructor;

public AliasToBeanResultTransformer(System.Type resultClass)
Expand All @@ -48,22 +46,17 @@ public AliasToBeanResultTransformer(System.Type resultClass)
if (constructor == null && resultClass.IsClass)
{
throw new ArgumentException("The target class of a AliasToBeanResultTransformer need a parameter-less constructor",
"resultClass");
"resultClass");
}

propertyAccessor =
new ChainedPropertyAccessor(new[]
Copy link
Member

@fredericDelaporte fredericDelaporte Apr 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the only usage of the class ChainedPropertyAccessor. With this change, this class as no more any purpose in NHibernate. This class should be marked with [Obsolete("Has no more usage and will be removed in a future version")].

(Of course, if we keep current changes, not reverting back to 42c5b85.)

{
PropertyAccessorFactory.GetPropertyAccessor(null),
PropertyAccessorFactory.GetPropertyAccessor("field")
});
_propertySetter = QueryAliasToObjectPropertySetter.MakeFor(resultClass);
}


public override bool IsTransformedValueATupleElement(String[] aliases, int tupleLength)
{
return false;
}
}


public override object TransformTuple(object[] tuple, String[] aliases)
Expand All @@ -76,30 +69,13 @@ public override object TransformTuple(object[] tuple, String[] aliases)

try
{
if (setters == null)
{
setters = new ISetter[aliases.Length];
for (int i = 0; i < aliases.Length; i++)
{
string alias = aliases[i];
if (alias != null)
{
setters[i] = propertyAccessor.GetSetter(resultClass, alias);
}
}
}

// if resultClass is not a class but a value type, we need to use Activator.CreateInstance
result = resultClass.IsClass
? constructor.Invoke(null)
: Cfg.Environment.BytecodeProvider.ObjectsFactory.CreateInstance(resultClass, true);
? constructor.Invoke(null)
: Cfg.Environment.BytecodeProvider.ObjectsFactory.CreateInstance(resultClass, true);

for (int i = 0; i < aliases.Length; i++)
{
if (setters[i] != null)
{
setters[i].Set(result, tuple[i]);
}
_propertySetter.SetProperty(aliases[i], tuple[i], result);
}
}
catch (InstantiationException e)
Expand Down
Loading