Skip to content

NH-3303: Refactoring of custom SQL code #161

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 9 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
93 changes: 54 additions & 39 deletions src/NHibernate.Test/SqlTest/Query/NativeSQLQueries.hbm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
<generator class="increment"/>
</id>
<property name="name" column="NAME" not-null="true"/>

</class>

<class name="Employment" table="EMPLOYMENT">
Expand Down Expand Up @@ -116,7 +115,6 @@
<return-join alias="pers" property="emp.employee"/>
</resultset>


<resultset name="org-description">
<return alias="org" class="Organization"/>
<return-join alias="emp" property="org.employments"/>
Expand Down Expand Up @@ -204,58 +202,75 @@
ORDER BY STARTDATE ASC, EMPLOYEE ASC
</sql-query>

<sql-query name="organizationreturnproperty">
<sql-query name="organization-using-manual-aliases">
<return alias="org" class="Organization">
<return-property name="id" column="ORGID"/>
<return-property name="name" column="NAME"/>
<return-property name="id" column="org_id"/>
<return-property name="name" column="org_name"/>
</return>
<return-join alias="emp" property="org.employments">
<return-property name="key" column="EMPLOYER"/>
<return-property name="element" column="EMPID"/>
<return-property name="element.employee" column="EMPLOYEE"/>
<return-property name="element.employer" column="EMPLOYER"/>
<return-property name="element.startDate" column="XSTARTDATE"/>
<return-property name="element.endDate" column="ENDDATE"/>
<return-property name="element.regionCode" column="REGIONCODE"/>
<return-property name="element.employmentId" column="EMPID"/>
<return-property name="key" column="emp_employer"/>
<return-property name="element" column="emp_id"/>
<return-property name="element.employee" column="emp_employee"/>
<return-property name="element.employer" column="emp_employer"/>
<return-property name="element.startDate" column="emp_startDate"/>
<return-property name="element.endDate" column="emp_endDate"/>
<return-property name="element.regionCode" column="emp_regionCode"/>
<return-property name="element.employmentId" column="emp_id"/>
<return-property name="element.salary">
<return-column name="AVALUE"/>
<return-column name="CURRENCY"/>
<return-column name="emp_avalue"/>
<return-column name="emp_currency"/>
</return-property>
</return-join>
SELECT org.ORGID as orgid,
org.NAME as name,
emp.EMPLOYER as employer,
emp.EMPID as empid,
emp.EMPLOYEE as employee,
emp.EMPLOYER as employer,
emp.STARTDATE as xstartDate,
emp.ENDDATE as endDate,
emp.REGIONCODE as regionCode,
emp.AVALUE as AVALUE,
emp.CURRENCY as CURRENCY
SELECT org.ORGID as org_id,
org.NAME as org_name,
emp.EMPLOYER as emp_employer,
emp.EMPID as emp_id,
emp.EMPLOYEE as emp_employee,
emp.STARTDATE as emp_startDate,
emp.ENDDATE as emp_endDate,
emp.REGIONCODE as emp_regionCode,
emp.AVALUE as emp_avalue,
emp.CURRENCY as emp_currency
FROM ORGANIZATION org
LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
</sql-query>


<sql-query name="organizationautodetect" resultset-ref="org-description">
<sql-query name="organization-using-column-names" resultset-ref="org-description">
<!-- equal to "organizationpropertyreturn" but since no {} nor return-property are used hibernate will fallback to use the columns directly from the mapping -->
<return alias="org" class="Organization"/>
<return-join alias="emp" property="org.employments"/>
SELECT org.ORGID as orgid,
org.NAME as name,
emp.EMPLOYER as employer,
emp.EMPID as empid,
emp.EMPLOYEE as employee,
emp.EMPLOYER as employer,
emp.STARTDATE as startDate,
emp.ENDDATE as endDate,
emp.REGIONCODE as regionCode,
SELECT org.ORGID as ORGID,
org.NAME as NAME,
emp.EMPLOYER as EMPLOYER,
emp.EMPID as EMPID,
emp.EMPLOYEE as EMPLOYEE,
emp.STARTDATE as STARTDATE,
emp.ENDDATE as ENDDATE,
emp.REGIONCODE as REGIONCODE,
emp.AVALUE as AVALUE,
emp.CURRENCY as CURRENCY
FROM ORGANIZATION org
LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
</sql-query>

<sql-query name="organization-using-column-names-and-manual-aliases">
<!-- equal to "organizationpropertyreturn" but will default to use columns directly from the mapping for properties without return-property element -->
<return alias="org" class="Organization">
<return-property name="id" column="ORGANISATION_ID"/>
</return>
<return-join alias="emp" property="org.employments">
<return-property name="element" column="EMPLOYMENT_ID"/>
<return-property name="element.id" column="EMPLOYMENT_ID"/>
</return-join>
SELECT org.ORGID as ORGANISATION_ID,
org.NAME as NAME,
emp.EMPID as EMPLOYMENT_ID,
emp.EMPLOYEE as EMPLOYEE,
emp.EMPLOYER as EMPLOYER,
emp.STARTDATE as STARTDATE,
emp.ENDDATE as ENDDATE,
emp.REGIONCODE as REGIONCODE,
emp.AVALUE as AVALUE,
emp.CURRENCY as CURRENCY
FROM ORGANIZATION org
LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
</sql-query>
</hibernate-mapping>
123 changes: 74 additions & 49 deletions src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs
Original file line number Diff line number Diff line change
@@ -1,29 +1,14 @@
using System;
using System.Collections;
using NHibernate.Criterion;
using NHibernate.Transform;
using NUnit.Framework;
using NHibernate.Criterion;

namespace NHibernate.Test.SqlTest.Query
{
[TestFixture]
public class GeneralTest : TestCase
{
protected const string OrganizationFetchJoinEmploymentSQL =
"SELECT org.ORGID as {org.id}, " +
" org.NAME as {org.name}, " +
" emp.EMPLOYER as {emp.key}, " +
" emp.EMPID as {emp.element}, " +
" {emp.element.*} " +
"FROM ORGANIZATION org " +
" LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER";

protected const string OrganizationJoinEmploymentSQL =
"SELECT org.ORGID as {org.id}, " +
" org.NAME as {org.name}, " +
" {emp.*} " +
"FROM ORGANIZATION org " +
" LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER";

protected const string EmploymentSQL = "SELECT * FROM EMPLOYMENT";

protected string EmploymentSQLMixedScalarEntity =
Expand Down Expand Up @@ -295,7 +280,7 @@ public void MappedAliasStrategy()

s = OpenSession();
t = s.BeginTransaction();
sqlQuery = s.GetNamedQuery("organizationreturnproperty");
sqlQuery = s.GetNamedQuery("organization-using-manual-aliases");
sqlQuery.SetResultTransformer(CriteriaSpecification.AliasToEntityMap);
list = sqlQuery.List();
Assert.AreEqual(2, list.Count);
Expand Down Expand Up @@ -452,9 +437,9 @@ public void AutoDetectAliasing()

// TODO H3: H3.2 can guess the return column type so they can use just addScalar("employerid"),
// but NHibernate currently can't do it.
list =
s.CreateSQLQuery(EmploymentSQLMixedScalarEntity).AddScalar("employerid", NHibernateUtil.Int64).AddEntity(
typeof(Employment)).List();
list = s.CreateSQLQuery(EmploymentSQLMixedScalarEntity)
.AddScalar("employerid", NHibernateUtil.Int64)
.AddEntity(typeof(Employment)).List();
Assert.AreEqual(1, list.Count);
o = (object[]) list[0];
Assert.AreEqual(2, o.Length);
Expand All @@ -467,34 +452,6 @@ public void AutoDetectAliasing()
list = queryWithCollection.List();
Assert.AreEqual(list.Count, 1);

s.Clear();

list = s.CreateSQLQuery(OrganizationJoinEmploymentSQL)
.AddEntity("org", typeof(Organization))
.AddJoin("emp", "org.employments")
.List();
Assert.AreEqual(2, list.Count);

s.Clear();

list = s.CreateSQLQuery(OrganizationFetchJoinEmploymentSQL)
.AddEntity("org", typeof(Organization))
.AddJoin("emp", "org.employments")
.List();
Assert.AreEqual(2, list.Count);

s.Clear();

// TODO : why twice?
s.GetNamedQuery("organizationreturnproperty").List();
list = s.GetNamedQuery("organizationreturnproperty").List();
Assert.AreEqual(2, list.Count);

s.Clear();

list = s.GetNamedQuery("organizationautodetect").List();
Assert.AreEqual(2, list.Count);

t.Commit();
s.Close();

Expand Down Expand Up @@ -538,6 +495,74 @@ public void AutoDetectAliasing()
s.Close();
}

public void CanQueryWithGeneratedAliasesOnly_UsingWildcard()
{
const string SQL =
"SELECT org.ORGID as {org.id}, " +
" org.NAME as {org.name}, " +
" {emp.*} " +
"FROM ORGANIZATION org " +
" LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER";

VerifyOrganisationQuery(session => session.CreateSQLQuery(SQL)
.AddEntity("org", typeof(Organization))
.AddJoin("emp", "org.employments"));
}

[Test]
public void CanQueryWithGeneratedAliasesOnly_UsingCollectionElementWildcard()
{
const string SQL =
"SELECT org.ORGID as {org.id}, " +
" org.NAME as {org.name}, " +
" emp.EMPLOYER as {emp.key}, " +
" emp.EMPID as {emp.element}, " +
" {emp.element.*} " +
"FROM ORGANIZATION org " +
" LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER";

VerifyOrganisationQuery(session => session.CreateSQLQuery(SQL)
.AddEntity("org", typeof(Organization))
.AddJoin("emp", "org.employments"));
}

[Test]
public void CanQueryWithColumnNamesOnly()
{
VerifyOrganisationQuery(session => session.GetNamedQuery("organization-using-manual-aliases"));
}

[Test]
public void CanQueryWithManualAliasesOnly()
{
VerifyOrganisationQuery(session => session.GetNamedQuery("organization-using-column-names"));
}

[Test]
public void CanQueryWithMixOfColumnNamesAndManualAliases()
{
VerifyOrganisationQuery(session => session.GetNamedQuery("organization-using-column-names-and-manual-aliases"));
}

private void VerifyOrganisationQuery(Func<ISession, IQuery> queryFactory)
{
using (ISession s = OpenSession())
using (ITransaction t = s.BeginTransaction())
{
var ifa = new Organization("IFA");
var jboss = new Organization("JBoss");
var gavin = new Person("Gavin");
var emp = new Employment(gavin, jboss, "AU");
s.Save(jboss);
s.Save(ifa);
s.Save(gavin);
s.Save(emp);

var list = queryFactory(s).List();
Assert.AreEqual(2, list.Count);
}
}

[Test]
public void MixAndMatchEntityScalar()
{
Expand Down
4 changes: 1 addition & 3 deletions src/NHibernate/Engine/Query/NativeSQLQueryPlan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ namespace NHibernate.Engine.Query
[Serializable]
public class NativeSQLQueryPlan
{
private static readonly IInternalLogger log = LoggerProvider.LoggerFor(typeof(NativeSQLQueryPlan));

private readonly string sourceQuery;
private readonly SQLCustomQuery customQuery;

Expand Down Expand Up @@ -119,7 +117,7 @@ public int PerformExecuteUpdate(QueryParameters queryParameters, ISessionImpleme
private SqlString ExpandDynamicFilterParameters(SqlString sqlString, ICollection<IParameterSpecification> parameterSpecs, ISessionImplementor session)
{
var enabledFilters = session.EnabledFilters;
if (enabledFilters.Count == 0 || sqlString.ToString().IndexOf(ParserHelper.HqlVariablePrefix) < 0)
if (enabledFilters.Count == 0 || sqlString.IndexOf(ParserHelper.HqlVariablePrefix, 0, sqlString.Length, StringComparison.Ordinal) < 0)
{
return sqlString;
}
Expand Down
4 changes: 2 additions & 2 deletions src/NHibernate/Impl/SessionFactoryImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1177,8 +1177,8 @@ private IDictionary<string, HibernateException> CheckNamedQueries()
NativeSQLQuerySpecification spec;
if (qd.ResultSetRef != null)
{
ResultSetMappingDefinition definition = sqlResultSetMappings[qd.ResultSetRef];
if (definition == null)
ResultSetMappingDefinition definition;
if (!sqlResultSetMappings.TryGetValue(qd.ResultSetRef, out definition))
{
throw new MappingException("Unable to find resultset-ref definition: " + qd.ResultSetRef);
}
Expand Down
3 changes: 2 additions & 1 deletion src/NHibernate/Loader/BasicLoader.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using NHibernate.Engine;
using NHibernate.Engine;
using NHibernate.Loader.Custom;
using NHibernate.Persister.Collection;
using NHibernate.Persister.Entity;
using NHibernate.Type;
Expand Down
27 changes: 0 additions & 27 deletions src/NHibernate/Loader/Custom/CollectionFetchReturn.cs

This file was deleted.

Loading