Skip to content

Commit c611e12

Browse files
committed
Fix custom component property mapping issue
1 parent e958eb0 commit c611e12

File tree

5 files changed

+238
-105
lines changed

5 files changed

+238
-105
lines changed

src/NHibernate.Test/SqlTest/Query/NativeSQLQueries.hbm.xml

Lines changed: 60 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
<?xml version="1.0" encoding="utf-8" ?>
22
<!--
33
4-
This mapping demonstrates the use of Hibernate with
5-
all-handwritten SQL!
4+
This mapping demonstrates the use of Hibernate with
5+
all-handwritten SQL!
66
-->
77

88
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="field.camelcase"
9-
namespace="NHibernate.Test.SqlTest"
10-
assembly="NHibernate.Test">
9+
namespace="NHibernate.Test.SqlTest"
10+
assembly="NHibernate.Test">
1111

1212
<class name="Organization" table="ORGANIZATION">
1313
<id name="id" unsaved-value="0" column="ORGID">
@@ -27,7 +27,6 @@
2727
<generator class="increment"/>
2828
</id>
2929
<property name="name" column="NAME" not-null="true"/>
30-
3130
</class>
3231

3332
<class name="Employment" table="EMPLOYMENT">
@@ -116,7 +115,6 @@
116115
<return-join alias="pers" property="emp.employee"/>
117116
</resultset>
118117

119-
120118
<resultset name="org-description">
121119
<return alias="org" class="Organization"/>
122120
<return-join alias="emp" property="org.employments"/>
@@ -149,14 +147,14 @@
149147
fld_name as name,
150148
fld_model as model,
151149
fld_speed as speed,
152-
fld_length as flength,
150+
fld_length as length,
153151
fld_width as width,
154152
fld_length * fld_width as surface,
155153
fld_length * fld_width *10 as volume
156154
from SpaceShip
157155
</sql-query>
158156

159-
<sql-query name="orgNamesOnly">
157+
<sql-query name="orgNamesOnly">
160158
<return-scalar column="NAME" type="string"/>
161159
SELECT org.NAME FROM ORGANIZATION org
162160
</sql-query>
@@ -204,56 +202,75 @@
204202
ORDER BY STARTDATE ASC, EMPLOYEE ASC
205203
</sql-query>
206204

207-
<sql-query name="organizationreturnproperty">
205+
<sql-query name="organization-using-manual-aliases">
208206
<return alias="org" class="Organization">
209-
<return-property name="id" column="ORGID"/>
210-
<return-property name="name" column="NAME"/>
207+
<return-property name="id" column="org_id"/>
208+
<return-property name="name" column="org_name"/>
211209
</return>
212210
<return-join alias="emp" property="org.employments">
213-
<return-property name="key" column="EMPLOYER"/>
214-
<return-property name="element" column="EMPID"/>
215-
<return-property name="element.employee" column="EMPLOYEE"/>
216-
<return-property name="element.employer" column="EMPLOYER"/>
217-
<return-property name="element.startDate" column="XSTARTDATE"/>
218-
<return-property name="element.endDate" column="ENDDATE"/>
219-
<return-property name="element.regionCode" column="REGIONCODE"/>
220-
<return-property name="element.employmentId" column="EMPID"/>
211+
<return-property name="key" column="emp_employer"/>
212+
<return-property name="element" column="emp_id"/>
213+
<return-property name="element.employee" column="emp_employee"/>
214+
<return-property name="element.employer" column="emp_employer"/>
215+
<return-property name="element.startDate" column="emp_startDate"/>
216+
<return-property name="element.endDate" column="emp_endDate"/>
217+
<return-property name="element.regionCode" column="emp_regionCode"/>
218+
<return-property name="element.employmentId" column="emp_id"/>
221219
<return-property name="element.salary">
222-
<return-column name="AVALUE"/>
223-
<return-column name="CURRENCY"/>
220+
<return-column name="emp_avalue"/>
221+
<return-column name="emp_currency"/>
224222
</return-property>
225223
</return-join>
226-
SELECT org.ORGID as orgid,
227-
org.NAME as name,
228-
emp.EMPLOYER as employer,
229-
emp.EMPID as empid,
230-
emp.EMPLOYEE as employee,
231-
emp.EMPLOYER as employer,
232-
emp.STARTDATE as xstartDate,
233-
emp.ENDDATE as endDate,
234-
emp.REGIONCODE as regionCode,
235-
emp.AVALUE as AVALUE,
236-
emp.CURRENCY as CURRENCY
224+
SELECT org.ORGID as org_id,
225+
org.NAME as org_name,
226+
emp.EMPLOYER as emp_employer,
227+
emp.EMPID as emp_id,
228+
emp.EMPLOYEE as emp_employee,
229+
emp.STARTDATE as emp_startDate,
230+
emp.ENDDATE as emp_endDate,
231+
emp.REGIONCODE as emp_regionCode,
232+
emp.AVALUE as emp_avalue,
233+
emp.CURRENCY as emp_currency
237234
FROM ORGANIZATION org
238235
LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
239236
</sql-query>
240237

241-
242-
<sql-query name="organizationautodetect" resultset-ref="org-description">
238+
<sql-query name="organization-using-column-names" resultset-ref="org-description">
243239
<!-- equal to "organizationpropertyreturn" but since no {} nor return-property are used hibernate will fallback to use the columns directly from the mapping -->
244-
SELECT org.ORGID as orgid,
245-
org.NAME as name,
246-
emp.EMPLOYER as employer,
247-
emp.EMPID as empid,
248-
emp.EMPLOYEE as employee,
249-
emp.EMPLOYER as employer,
250-
emp.STARTDATE as startDate,
251-
emp.ENDDATE as endDate,
252-
emp.REGIONCODE as regionCode,
240+
SELECT org.ORGID as ORGID,
241+
org.NAME as NAME,
242+
emp.EMPLOYER as EMPLOYER,
243+
emp.EMPID as EMPID,
244+
emp.EMPLOYEE as EMPLOYEE,
245+
emp.STARTDATE as STARTDATE,
246+
emp.ENDDATE as ENDDATE,
247+
emp.REGIONCODE as REGIONCODE,
253248
emp.AVALUE as AVALUE,
254249
emp.CURRENCY as CURRENCY
255250
FROM ORGANIZATION org
256251
LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
257252
</sql-query>
258253

254+
<sql-query name="organization-using-column-names-and-manual-aliases">
255+
<!-- equal to "organizationpropertyreturn" but will default to use columns directly from the mapping for properties without return-property element -->
256+
<return alias="org" class="Organization">
257+
<return-property name="id" column="ORGANISATION_ID"/>
258+
</return>
259+
<return-join alias="emp" property="org.employments">
260+
<return-property name="element" column="EMPLOYMENT_ID"/>
261+
<return-property name="element.id" column="EMPLOYMENT_ID"/>
262+
</return-join>
263+
SELECT org.ORGID as ORGANISATION_ID,
264+
org.NAME as NAME,
265+
emp.EMPID as EMPLOYMENT_ID,
266+
emp.EMPLOYEE as EMPLOYEE,
267+
emp.EMPLOYER as EMPLOYER,
268+
emp.STARTDATE as STARTDATE,
269+
emp.ENDDATE as ENDDATE,
270+
emp.REGIONCODE as REGIONCODE,
271+
emp.AVALUE as AVALUE,
272+
emp.CURRENCY as CURRENCY
273+
FROM ORGANIZATION org
274+
LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
275+
</sql-query>
259276
</hibernate-mapping>

src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs

Lines changed: 99 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,14 @@
1+
using System;
12
using System.Collections;
3+
using NHibernate.Criterion;
24
using NHibernate.Transform;
35
using NUnit.Framework;
4-
using NHibernate.Criterion;
56

67
namespace NHibernate.Test.SqlTest.Query
78
{
89
[TestFixture]
910
public class GeneralTest : TestCase
1011
{
11-
protected const string OrganizationFetchJoinEmploymentSQL =
12-
"SELECT org.ORGID as {org.id}, " +
13-
" org.NAME as {org.name}, " +
14-
" emp.EMPLOYER as {emp.key}, " +
15-
" emp.EMPID as {emp.element}, " +
16-
" {emp.element.*} " +
17-
"FROM ORGANIZATION org " +
18-
" LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER";
19-
20-
protected const string OrganizationJoinEmploymentSQL =
21-
"SELECT org.ORGID as {org.id}, " +
22-
" org.NAME as {org.name}, " +
23-
" {emp.*} " +
24-
"FROM ORGANIZATION org " +
25-
" LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER";
26-
2712
protected const string EmploymentSQL = "SELECT * FROM EMPLOYMENT";
2813

2914
protected string EmploymentSQLMixedScalarEntity =
@@ -295,7 +280,7 @@ public void MappedAliasStrategy()
295280

296281
s = OpenSession();
297282
t = s.BeginTransaction();
298-
sqlQuery = s.GetNamedQuery("organizationreturnproperty");
283+
sqlQuery = s.GetNamedQuery("organization-using-manual-aliases");
299284
sqlQuery.SetResultTransformer(CriteriaSpecification.AliasToEntityMap);
300285
list = sqlQuery.List();
301286
Assert.AreEqual(2, list.Count);
@@ -452,9 +437,9 @@ public void AutoDetectAliasing()
452437

453438
// TODO H3: H3.2 can guess the return column type so they can use just addScalar("employerid"),
454439
// but NHibernate currently can't do it.
455-
list =
456-
s.CreateSQLQuery(EmploymentSQLMixedScalarEntity).AddScalar("employerid", NHibernateUtil.Int64).AddEntity(
457-
typeof(Employment)).List();
440+
list = s.CreateSQLQuery(EmploymentSQLMixedScalarEntity)
441+
.AddScalar("employerid", NHibernateUtil.Int64)
442+
.AddEntity(typeof(Employment)).List();
458443
Assert.AreEqual(1, list.Count);
459444
o = (object[]) list[0];
460445
Assert.AreEqual(2, o.Length);
@@ -467,34 +452,6 @@ public void AutoDetectAliasing()
467452
list = queryWithCollection.List();
468453
Assert.AreEqual(list.Count, 1);
469454

470-
s.Clear();
471-
472-
list = s.CreateSQLQuery(OrganizationJoinEmploymentSQL)
473-
.AddEntity("org", typeof(Organization))
474-
.AddJoin("emp", "org.employments")
475-
.List();
476-
Assert.AreEqual(2, list.Count);
477-
478-
s.Clear();
479-
480-
list = s.CreateSQLQuery(OrganizationFetchJoinEmploymentSQL)
481-
.AddEntity("org", typeof(Organization))
482-
.AddJoin("emp", "org.employments")
483-
.List();
484-
Assert.AreEqual(2, list.Count);
485-
486-
s.Clear();
487-
488-
// TODO : why twice?
489-
s.GetNamedQuery("organizationreturnproperty").List();
490-
list = s.GetNamedQuery("organizationreturnproperty").List();
491-
Assert.AreEqual(2, list.Count);
492-
493-
s.Clear();
494-
495-
list = s.GetNamedQuery("organizationautodetect").List();
496-
Assert.AreEqual(2, list.Count);
497-
498455
t.Commit();
499456
s.Close();
500457

@@ -538,6 +495,99 @@ public void AutoDetectAliasing()
538495
s.Close();
539496
}
540497

498+
public void CanQueryWithGeneratedAliasesOnly_UsingWildcard()
499+
{
500+
const string SQL =
501+
"SELECT org.ORGID as {org.id}, " +
502+
" org.NAME as {org.name}, " +
503+
" {emp.*} " +
504+
"FROM ORGANIZATION org " +
505+
" LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER";
506+
507+
VerifyOrganisationQuery(session => session.CreateSQLQuery(SQL)
508+
.AddEntity("org", typeof(Organization))
509+
.AddJoin("emp", "org.employments"));
510+
}
511+
512+
[Test]
513+
public void CanQueryWithGeneratedAliasesOnly_UsingCollectionElementWildcard()
514+
{
515+
const string SQL =
516+
"SELECT org.ORGID as {org.id}, " +
517+
" org.NAME as {org.name}, " +
518+
" emp.EMPLOYER as {emp.key}, " +
519+
" emp.EMPID as {emp.element}, " +
520+
" {emp.element.*} " +
521+
"FROM ORGANIZATION org " +
522+
" LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER";
523+
524+
VerifyOrganisationQuery(session => session.CreateSQLQuery(SQL)
525+
.AddEntity("org", typeof(Organization))
526+
.AddJoin("emp", "org.employments"));
527+
}
528+
529+
[Test]
530+
public void CanQueryWithColumnNamesOnly()
531+
{
532+
VerifyOrganisationQuery(session => session.GetNamedQuery("organization-using-manual-aliases"));
533+
}
534+
535+
[Test]
536+
public void CanQueryWithManualAliasesOnly()
537+
{
538+
VerifyOrganisationQuery(session => session.GetNamedQuery("organization-using-column-names"));
539+
}
540+
541+
[Test]
542+
public void CanQueryWithMixOfColumnNamesAndManualAliases()
543+
{
544+
VerifyOrganisationQuery(session => session.GetNamedQuery("organization-using-column-names-and-manual-aliases"));
545+
}
546+
547+
private void VerifyOrganisationQuery(Func<ISession, IQuery> queryFactory)
548+
{
549+
using (ISession s = OpenSession())
550+
using (ITransaction t = s.BeginTransaction())
551+
{
552+
var ifa = new Organization("IFA");
553+
var jboss = new Organization("JBoss");
554+
var gavin = new Person("Gavin");
555+
var emp = new Employment(gavin, jboss, "AU");
556+
s.Save(jboss);
557+
s.Save(ifa);
558+
s.Save(gavin);
559+
s.Save(emp);
560+
561+
var list = queryFactory(s).List();
562+
Assert.AreEqual(2, list.Count);
563+
}
564+
}
565+
566+
[Test]
567+
public void CanQueryWithManualComponentPropertyAliases()
568+
{
569+
using (ISession s = OpenSession())
570+
using (ITransaction t = s.BeginTransaction())
571+
{
572+
SpaceShip enterprise = new SpaceShip();
573+
enterprise.Model = "USS";
574+
enterprise.Name = "Entreprise";
575+
enterprise.Speed = 50d;
576+
Dimension d = new Dimension(45, 10);
577+
enterprise.Dimensions = d;
578+
s.Save(enterprise);
579+
580+
s.Flush();
581+
s.Clear();
582+
583+
object[] result = (object[])s.GetNamedQuery("spaceship").UniqueResult();
584+
enterprise = (SpaceShip)result[0];
585+
Assert.AreEqual(50d, enterprise.Speed, "Speed");
586+
Assert.AreEqual(45, enterprise.Dimensions.Length, "Dimensions.Length");
587+
Assert.AreEqual(10, enterprise.Dimensions.Width, "Dimensions.Width");
588+
}
589+
}
590+
541591
[Test]
542592
public void MixAndMatchEntityScalar()
543593
{

src/NHibernate/Loader/Custom/ColumnCollectionAliases.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ public ColumnCollectionAliases(IDictionary<string, string[]> userProvidedAliases
2323

2424
this.keyAliases = GetUserProvidedAliases("key", persister.KeyColumnNames);
2525
this.indexAliases = GetUserProvidedAliases("index", persister.IndexColumnNames);
26-
this.elementAliases = GetUserProvidedAliases("element", persister.ElementColumnNames);
2726

2827
// NH-1612: Add aliases for all composite element properties to support access
2928
// to individual composite element properties in <return-property> elements.

0 commit comments

Comments
 (0)