|
From: <fab...@us...> - 2009-01-03 17:26:41
|
Revision: 3974
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3974&view=rev
Author: fabiomaulo
Date: 2009-01-03 17:26:30 +0000 (Sat, 03 Jan 2009)
Log Message:
-----------
Fix NH-1612 (thanks to Gerke Geurts)
Modified Paths:
--------------
trunk/nhibernate/src/NHibernate/Loader/Custom/CustomLoader.cs
trunk/nhibernate/src/NHibernate/Loader/Custom/Sql/SQLQueryParser.cs
trunk/nhibernate/src/NHibernate/Loader/GeneratedCollectionAliases.cs
trunk/nhibernate/src/NHibernate/Loader/Loader.cs
trunk/nhibernate/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs
trunk/nhibernate/src/NHibernate.Test/App.config
trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Mappings.hbm.xml
trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs
Modified: trunk/nhibernate/src/NHibernate/Loader/Custom/CustomLoader.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Loader/Custom/CustomLoader.cs 2009-01-02 18:52:54 UTC (rev 3973)
+++ trunk/nhibernate/src/NHibernate/Loader/Custom/CustomLoader.cs 2009-01-03 17:26:30 UTC (rev 3974)
@@ -369,7 +369,7 @@
{
object[] resultRow;
// NH Different behavior (patched in NH-1612 to solve Hibernate issue HHH-2831).
- if (!hasScalars && hasTransformer)
+ if (!hasScalars && (hasTransformer || data.Length == 0))
{
resultRow = data;
}
Modified: trunk/nhibernate/src/NHibernate/Loader/Custom/Sql/SQLQueryParser.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Loader/Custom/Sql/SQLQueryParser.cs 2009-01-02 18:52:54 UTC (rev 3973)
+++ trunk/nhibernate/src/NHibernate/Loader/Custom/Sql/SQLQueryParser.cs 2009-01-03 17:26:30 UTC (rev 3974)
@@ -131,6 +131,7 @@
ISqlLoadableCollection collectionPersister = context.GetCollectionPersisterByAlias(aliasName);
string collectionSuffix = context.GetCollectionSuffixByAlias(aliasName);
+ // NH Different behavior for NH-1612
if ("*".Equals(propertyName))
{
if (fieldResults.Count != 0)
@@ -140,37 +141,50 @@
string selectFragment = collectionPersister.SelectFragment(aliasName, collectionSuffix);
aliasesFound++;
- return selectFragment + ", " + ResolveProperties(aliasName, propertyName);
+
+ // Collection may just contain elements and no entities, in which case resolution of
+ // collection properties is enough.
+ return collectionPersister.ElementType.IsEntityType
+ ? selectFragment + ", " + ResolveProperties(aliasName, "*")
+ : selectFragment;
}
- else if ("element.*".Equals(propertyName))
+
+ if (propertyName.StartsWith("element."))
{
- return ResolveProperties(aliasName, "*");
- }
- else
- {
- string[] columnAliases;
+ string elementPropertyName = propertyName.Substring("element.".Length);
- // Let return-propertys override whatever the persister has for aliases.
- if (!fieldResults.TryGetValue(propertyName,out columnAliases))
+ if (collectionPersister.ElementType.IsEntityType)
{
- columnAliases = collectionPersister.GetCollectionPropertyColumnAliases(propertyName, collectionSuffix);
+ return ResolveProperties(aliasName, elementPropertyName);
}
-
- if (columnAliases == null || columnAliases.Length == 0)
+ else if (elementPropertyName == "*")
{
- throw new QueryException("No column name found for property [" + propertyName + "] for alias [" + aliasName + "]",
- originalQueryString);
+ throw new QueryException("Using element.* syntax is only supported for entity elements.");
}
- if (columnAliases.Length != 1)
- {
- // TODO: better error message since we actually support composites if names are explicitly listed.
- throw new QueryException(
- "SQL queries only support properties mapped to a single column - property [" + propertyName + "] is mapped to "
- + columnAliases.Length + " columns.", originalQueryString);
- }
- aliasesFound++;
- return columnAliases[0];
}
+
+ string[] columnAliases;
+
+ // Let return-propertys override whatever the persister has for aliases.
+ if (!fieldResults.TryGetValue(propertyName, out columnAliases))
+ {
+ columnAliases = collectionPersister.GetCollectionPropertyColumnAliases(propertyName, collectionSuffix);
+ }
+
+ if (columnAliases == null || columnAliases.Length == 0)
+ {
+ throw new QueryException("No column name found for property [" + propertyName + "] for alias [" + aliasName + "]",
+ originalQueryString);
+ }
+ if (columnAliases.Length != 1)
+ {
+ // TODO: better error message since we actually support composites if names are explicitly listed.
+ throw new QueryException(
+ "SQL queries only support properties mapped to a single column - property [" + propertyName + "] is mapped to "
+ + columnAliases.Length + " columns.", originalQueryString);
+ }
+ aliasesFound++;
+ return columnAliases[0];
}
private string ResolveProperties(string aliasName, string propertyName)
Modified: trunk/nhibernate/src/NHibernate/Loader/GeneratedCollectionAliases.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Loader/GeneratedCollectionAliases.cs 2009-01-02 18:52:54 UTC (rev 3973)
+++ trunk/nhibernate/src/NHibernate/Loader/GeneratedCollectionAliases.cs 2009-01-03 17:26:30 UTC (rev 3974)
@@ -18,7 +18,7 @@
private readonly IDictionary<string, string[]> userProvidedAliases;
public GeneratedCollectionAliases(IDictionary<string, string[]> userProvidedAliases, ICollectionPersister persister,
- string suffix)
+ string suffix)
{
this.suffix = suffix;
this.userProvidedAliases = userProvidedAliases;
@@ -27,7 +27,11 @@
indexAliases = GetUserProvidedAliases("index", persister.GetIndexColumnAliases(suffix));
- elementAliases = GetUserProvidedAliases("element", persister.GetElementColumnAliases(suffix));
+ // NH-1612: Add aliases for all composite element properties to support access
+ // to individual composite element properties in <return-property> elements.
+ elementAliases = persister.ElementType.IsComponentType
+ ? GetUserProvidedCompositeElementAliases(persister.GetElementColumnAliases(suffix))
+ : GetUserProvidedAliases("element", persister.GetElementColumnAliases(suffix));
identifierAlias = GetUserProvidedAlias("id", persister.GetIdentifierColumnAlias(suffix));
}
@@ -35,6 +39,20 @@
public GeneratedCollectionAliases(ICollectionPersister persister, string str)
: this(new CollectionHelper.EmptyMapClass<string, string[]>(), persister, str) {}
+ private string[] GetUserProvidedCompositeElementAliases(string[] defaultAliases)
+ {
+ var aliases = new List<string>();
+ foreach (KeyValuePair<string, string[]> userProvidedAlias in userProvidedAliases)
+ {
+ if (userProvidedAlias.Key.StartsWith("element."))
+ {
+ aliases.AddRange(userProvidedAlias.Value);
+ }
+ }
+
+ return aliases.Count > 0 ? aliases.ToArray() : defaultAliases;
+ }
+
/// <summary>
/// Returns the suffixed result-set column-aliases for columns making up the key for this collection (i.e., its FK to
/// its owner).
Modified: trunk/nhibernate/src/NHibernate/Loader/Loader.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2009-01-02 18:52:54 UTC (rev 3973)
+++ trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2009-01-03 17:26:30 UTC (rev 3974)
@@ -392,11 +392,11 @@
int entitySpan = EntityPersisters.Length;
List<object> hydratedObjects = entitySpan == 0 ? null : new List<object>(entitySpan * 10);
-
+
IDbCommand st = PrepareQueryCommand(queryParameters, false, session);
- IDataReader rs =
- GetResultSet(st, queryParameters.HasAutoDiscoverScalarTypes, queryParameters.Callable, selection, session);
+ IDataReader rs = GetResultSet(st, queryParameters.HasAutoDiscoverScalarTypes, queryParameters.Callable, selection,
+ session);
// would be great to move all this below here into another method that could also be used
// from the new scrolling stuff.
@@ -428,9 +428,8 @@
log.Debug("result set row: " + count);
}
- object result =
- GetRowFromResultSet(rs, session, queryParameters, lockModeArray, optionalObjectKey, hydratedObjects, keys,
- returnProxies);
+ object result = GetRowFromResultSet(rs, session, queryParameters, lockModeArray, optionalObjectKey, hydratedObjects,
+ keys, returnProxies);
results.Add(result);
if (createSubselects)
@@ -445,11 +444,11 @@
log.Debug(string.Format("done processing result set ({0} rows)", count));
}
}
- catch(Exception e)
- {
- e.Data["actual-sql-query"] = st.CommandText;
- throw;
- }
+ catch (Exception e)
+ {
+ e.Data["actual-sql-query"] = st.CommandText;
+ throw;
+ }
finally
{
session.Batcher.CloseCommand(st, rs);
Modified: trunk/nhibernate/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs 2009-01-02 18:52:54 UTC (rev 3973)
+++ trunk/nhibernate/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs 2009-01-03 17:26:30 UTC (rev 3974)
@@ -1386,8 +1386,7 @@
public string[] GetCollectionPropertyColumnAliases(string propertyName, string suffix)
{
object aliases;
- collectionPropertyColumnAliases.TryGetValue(propertyName, out aliases);
- if (aliases == null)
+ if (!collectionPropertyColumnAliases.TryGetValue(propertyName, out aliases))
{
return null;
}
@@ -1425,13 +1424,29 @@
if (type.IsComponentType)
{
- IAbstractComponentType ct = (IAbstractComponentType) type;
+ // NH-1612: Recursively add column aliases for nested components to support the selection
+ // of individual component properties in native SQL queries. This also seems to provide
+ // a more complete solution to HHH-1019 (http://opensource.atlassian.com/projects/hibernate/browse/HHH-1019)
+ // because it works for <load-collection> and <return-join>.
+ int columnIndex = 0;
+
+ var ct = (IAbstractComponentType) type;
string[] propertyNames = ct.PropertyNames;
- for (int i = 0; i < propertyNames.Length; i++)
+ for (int propertyIndex = 0; propertyIndex < propertyNames.Length; propertyIndex++)
{
- string name = propertyNames[i];
- collectionPropertyColumnAliases[aliasName + "." + name] = columnAliases[i];
- collectionPropertyColumnNames[aliasName + "." + name] = columnNames[i];
+ string name = propertyNames[propertyIndex];
+ IType propertyType = ct.Subtypes[propertyIndex];
+ int propertyColSpan = propertyType.IsComponentType
+ ? ((IAbstractComponentType) propertyType).PropertyNames.Length
+ : 1;
+
+ var propertyColumnAliases = new string[propertyColSpan];
+ var propertyColumnNames = new string[propertyColSpan];
+ System.Array.Copy(columnAliases, columnIndex, propertyColumnAliases, 0, propertyColSpan);
+ System.Array.Copy(columnNames, columnIndex, propertyColumnNames, 0, propertyColSpan);
+ InitCollectionPropertyMap(aliasName + "." + name, propertyType, propertyColumnAliases, propertyColumnNames);
+
+ columnIndex += propertyColSpan;
}
}
}
Modified: trunk/nhibernate/src/NHibernate.Test/App.config
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/App.config 2009-01-02 18:52:54 UTC (rev 3973)
+++ trunk/nhibernate/src/NHibernate.Test/App.config 2009-01-03 17:26:30 UTC (rev 3974)
@@ -123,7 +123,7 @@
</logger>
<logger name="NHibernate.SQL">
- <level value="OFF" />
+ <level value="DEBUG" />
</logger>
<logger name="NHibernate.Tool.hbm2ddl.SchemaExport">
Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Mappings.hbm.xml
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Mappings.hbm.xml 2009-01-02 18:52:54 UTC (rev 3973)
+++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Mappings.hbm.xml 2009-01-03 17:26:30 UTC (rev 3974)
@@ -75,7 +75,7 @@
<sql-query name="AreaStatisticsLoader" xml:space="preserve">
<load-collection role="Area.Statistics" alias="s">
- <return-property name="key" column="code" />
+ <return-property name="key" column="area_code" />
<return-property name="index" column="year" />
<return-property name="element.CitizenCount" column="citizen_count" />
<return-property name="element.GDP">
Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs 2009-01-02 18:52:54 UTC (rev 3973)
+++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs 2009-01-03 17:26:30 UTC (rev 3974)
@@ -5,7 +5,7 @@
namespace NHibernate.Test.NHSpecificTest.NH1612
{
- [TestFixture, Ignore("Not fixed yet.")]
+ [TestFixture]
public class NativeSqlCollectionLoaderFixture : BugTestCase
{
#region Tests - <return-join>
@@ -18,16 +18,8 @@
Assert.That(country, Is.Not.Null);
Assert.That(country.Routes, Is.EquivalentTo(routes));
-
- // cleanup
- using (ISession session = OpenSession())
- {
- using (ITransaction tx = session.BeginTransaction())
- {
- session.Delete(country);
- tx.Commit();
- }
- }
+
+ Cleanup();
}
[Test]
@@ -37,15 +29,7 @@
Country country = LoadCountryWithNativeSQL(CreateCountry(routes), "LoadCountryRoutesWithCustomAliases");
Assert.That(country, Is.Not.Null);
Assert.That(country.Routes, Is.EquivalentTo(routes));
- // cleanup
- using (ISession session = OpenSession())
- {
- using (ITransaction tx = session.BeginTransaction())
- {
- session.Delete(country);
- tx.Commit();
- }
- }
+ Cleanup();
}
[Test]
@@ -57,15 +41,7 @@
Assert.That(country, Is.Not.Null);
Assert.That((ICollection) country.Statistics.Keys, Is.EquivalentTo((ICollection) stats.Keys), "Keys");
Assert.That((ICollection) country.Statistics.Values, Is.EquivalentTo((ICollection) stats.Values), "Elements");
- // cleanup
- using (ISession session = OpenSession())
- {
- using (ITransaction tx = session.BeginTransaction())
- {
- session.Delete(country);
- tx.Commit();
- }
- }
+ CleanupWithPersons();
}
[Test]
@@ -77,6 +53,7 @@
Assert.That(country, Is.Not.Null);
Assert.That((ICollection) country.Statistics.Keys, Is.EquivalentTo((ICollection) stats.Keys), "Keys");
Assert.That((ICollection) country.Statistics.Values, Is.EquivalentTo((ICollection) stats.Values), "Elements");
+ CleanupWithPersons();
}
[Test]
@@ -88,40 +65,81 @@
Assert.That(country, Is.Not.Null);
Assert.That((ICollection) country.Statistics.Keys, Is.EquivalentTo((ICollection) stats.Keys), "Keys");
Assert.That((ICollection) country.Statistics.Values, Is.EquivalentTo((ICollection) stats.Values), "Elements");
+
+ CleanupWithPersons();
}
[Test]
public void LoadEntitiesWithWithSimpleHbmAliasInjection()
{
City[] cities = CreateCities();
- Country country = LoadCountryWithNativeSQL(CreateCountry(cities), "LoadCountryCitiesWithSimpleHbmAliasInjection");
- Assert.That(country, Is.Not.Null);
- Assert.That(country.Cities, Is.EquivalentTo(cities));
+ Country country = CreateCountry(cities);
+ Save(country);
+ using (ISession session = OpenSession())
+ {
+ var c =
+ session.GetNamedQuery("LoadCountryCitiesWithSimpleHbmAliasInjection").SetString("country_code", country.Code).
+ UniqueResult<Country>();
+ Assert.That(c, Is.Not.Null);
+ Assert.That(c.Cities, Is.EquivalentTo(cities));
+ }
+ CleanupWithCities();
}
[Test]
public void LoadEntitiesWithComplexHbmAliasInjection()
{
City[] cities = CreateCities();
- Country country = LoadCountryWithNativeSQL(CreateCountry(cities), "LoadCountryCitiesWithComplexHbmAliasInjection");
- Assert.That(country, Is.Not.Null);
- Assert.That(country.Cities, Is.EquivalentTo(cities));
+ Country country = CreateCountry(cities);
+ Save(country);
+ using (ISession session = OpenSession())
+ {
+ var c =
+ session.GetNamedQuery("LoadCountryCitiesWithComplexHbmAliasInjection").SetString("country_code", country.Code).
+ UniqueResult<Country>();
+ Assert.That(c, Is.Not.Null);
+ Assert.That(c.Cities, Is.EquivalentTo(cities));
+ }
+ CleanupWithCities();
}
[Test]
public void LoadEntitiesWithExplicitColumnMappings()
{
City[] cities = CreateCities();
- Country country = LoadCountryWithNativeSQL(CreateCountry(cities), "LoadCountryCitiesWithCustomAliases");
- Assert.That(country, Is.Not.Null);
- Assert.That(country.Cities, Is.EquivalentTo(cities));
+ Country country = CreateCountry(cities);
+ Save(country);
+ using (ISession session = OpenSession())
+ {
+ var c =
+ session.GetNamedQuery("LoadCountryCitiesWithCustomAliases").SetString("country_code", country.Code).
+ UniqueResult<Country>();
+ Assert.That(c, Is.Not.Null);
+ Assert.That(c.Cities, Is.EquivalentTo(cities));
+ }
+
+ // cleanup
+ CleanupWithCities();
}
- [Test, ExpectedException(typeof (QueryException))]
+ [Test]
public void NativeQueryWithUnresolvedHbmAliasInjection()
{
IDictionary<int, AreaStatistics> stats = CreateStatistics();
- LoadCountryWithNativeSQL(CreateCountry(stats), "LoadAreaStatisticsWithFaultyHbmAliasInjection");
+ try
+ {
+ LoadCountryWithNativeSQL(CreateCountry(stats), "LoadAreaStatisticsWithFaultyHbmAliasInjection");
+ Assert.Fail("Expected exception");
+ }
+ catch(QueryException)
+ {
+ // ok
+ }
+ finally
+ {
+ // cleanup
+ CleanupWithPersons();
+ }
}
private Country LoadCountryWithNativeSQL(Country country, string queryName)
@@ -151,10 +169,14 @@
{
string[] routes = CreateRoutes();
Country country = CreateCountry(routes);
- Country c = SaveAndReload(country);
- Assert.That(c, Is.Not.Null, "country");
- Assert.That(c.Routes, Is.EquivalentTo(routes), "country.Routes");
-
+ Save(country);
+ using (ISession session = OpenSession())
+ {
+ var c = session.Get<Country>(country.Code);
+ Assert.That(c, Is.Not.Null, "country");
+ Assert.That(c.Routes, Is.EquivalentTo(routes), "country.Routes");
+ }
+ Cleanup();
}
[Test]
@@ -162,10 +184,15 @@
{
IDictionary<int, AreaStatistics> stats = CreateStatistics();
Country country = CreateCountry(stats);
- Area a = SaveAndReload(country);
- Assert.That(a, Is.Not.Null, "area");
- Assert.That((ICollection)a.Statistics.Keys, Is.EquivalentTo((ICollection)stats.Keys), "area.Keys");
- Assert.That((ICollection)a.Statistics.Values, Is.EquivalentTo((ICollection)stats.Values), "area.Elements");
+ Save(country);
+ using (ISession session = OpenSession())
+ {
+ var a = session.Get<Area>(country.Code);
+ Assert.That(a, Is.Not.Null, "area");
+ Assert.That((ICollection) a.Statistics.Keys, Is.EquivalentTo((ICollection) stats.Keys), "area.Keys");
+ Assert.That((ICollection) a.Statistics.Values, Is.EquivalentTo((ICollection) stats.Values), "area.Elements");
+ }
+ CleanupWithPersons();
}
[Test]
@@ -173,15 +200,19 @@
{
City[] cities = CreateCities();
Country country = CreateCountry(cities);
- Country c = SaveAndReload(country);
- Assert.That(c, Is.Not.Null, "country");
- Assert.That(c.Cities, Is.EquivalentTo(cities), "country.Cities");
+ Save(country);
+ using (ISession session = OpenSession())
+ {
+ var c = session.Get<Country>(country.Code);
+
+ Assert.That(c, Is.Not.Null, "country");
+ Assert.That(c.Cities, Is.EquivalentTo(cities), "country.Cities");
+ }
+ CleanupWithCities();
}
- private TArea SaveAndReload<TArea>(TArea area) where TArea : Area
+ private void Save<TArea>(TArea area) where TArea : Area
{
- //Ensure country is saved and session cache is empty to force from now on the reload of all
- //persistence objects from the database.
using (ISession session = OpenSession())
{
using (ITransaction tx = session.BeginTransaction())
@@ -189,12 +220,7 @@
session.Save(area);
tx.Commit();
}
-
}
- using (ISession session = OpenSession())
- {
- return session.Get<TArea>(area.Code);
- }
}
#endregion
@@ -261,6 +287,48 @@
#endregion
+ #region cleanup
+
+ private void Cleanup()
+ {
+ using (ISession session = OpenSession())
+ {
+ using (ITransaction tx = session.BeginTransaction())
+ {
+ session.Delete("from Country");
+ tx.Commit();
+ }
+ }
+ }
+
+ private void CleanupWithPersons()
+ {
+ using (ISession session = OpenSession())
+ {
+ using (ITransaction tx = session.BeginTransaction())
+ {
+ session.Delete("from Person");
+ session.Delete("from Country");
+ tx.Commit();
+ }
+ }
+ }
+
+ private void CleanupWithCities()
+ {
+ using (ISession session = OpenSession())
+ {
+ using (ITransaction tx = session.BeginTransaction())
+ {
+ session.Delete("from City");
+ session.Delete("from Country");
+ tx.Commit();
+ }
+ }
+ }
+
+ #endregion
+
#region Factory methods
private static Country CreateCountry()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|