From: <aye...@us...> - 2008-07-18 07:32:52
|
Revision: 3640 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3640&view=rev Author: ayenderahien Date: 2008-07-18 07:32:56 +0000 (Fri, 18 Jul 2008) Log Message: ----------- NH-1359 - Applying patch from Will Shaver to create an IProjection from a DetachedCriteria Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/Projections.cs trunk/nhibernate/src/NHibernate/Criterion/Subqueries.cs trunk/nhibernate/src/NHibernate/Criterion/SubqueryExpression.cs trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs trunk/nhibernate/src/NHibernate/Loader/Loader.cs trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj trunk/nhibernate/src/NHibernate/NHibernate-3.5.csproj trunk/nhibernate/src/NHibernate/SqlCommand/InFragment.cs trunk/nhibernate/src/NHibernate/SqlCommand/SubselectClauseExtractor.cs trunk/nhibernate/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1101/Domain.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-3.5.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Criterion/SelectSubqueryExpression.cs trunk/nhibernate/src/NHibernate/Criterion/SubqueryProjection.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1359/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1359/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1359/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1359/Person.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/Projections.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Projections.cs 2008-07-18 06:52:02 UTC (rev 3639) +++ trunk/nhibernate/src/NHibernate/Criterion/Projections.cs 2008-07-18 07:32:56 UTC (rev 3640) @@ -241,5 +241,11 @@ { return new ConditionalProjection(criterion, whenTrue, whenFalse); } + + public static IProjection SubQuery(DetachedCriteria detachedCriteria) + { + SelectSubqueryExpression expr = new SelectSubqueryExpression(detachedCriteria); + return new SubqueryProjection(expr); + } } -} \ No newline at end of file +} Added: trunk/nhibernate/src/NHibernate/Criterion/SelectSubqueryExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/SelectSubqueryExpression.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/SelectSubqueryExpression.cs 2008-07-18 07:32:56 UTC (rev 3640) @@ -0,0 +1,23 @@ +using System; +using NHibernate.SqlCommand; + +namespace NHibernate.Criterion +{ + /// <summary> + /// A comparison between a property value in the outer query and the + /// result of a subquery + /// </summary> + [Serializable] + public class SelectSubqueryExpression : SubqueryExpression + { + internal SelectSubqueryExpression(DetachedCriteria dc) + : base(null, null, dc) + { + } + + protected override SqlString ToLeftSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery) + { + return SqlString.Empty; + } + } +} Modified: trunk/nhibernate/src/NHibernate/Criterion/Subqueries.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Subqueries.cs 2008-07-18 06:52:02 UTC (rev 3639) +++ trunk/nhibernate/src/NHibernate/Criterion/Subqueries.cs 2008-07-18 07:32:56 UTC (rev 3640) @@ -190,5 +190,10 @@ { return new SimpleSubqueryExpression(value, "<=", "some", dc); } + + public static AbstractCriterion Select(DetachedCriteria detachedCriteria) + { + return new SelectSubqueryExpression(detachedCriteria); + } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Criterion/SubqueryExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/SubqueryExpression.cs 2008-07-18 06:52:02 UTC (rev 3639) +++ trunk/nhibernate/src/NHibernate/Criterion/SubqueryExpression.cs 2008-07-18 07:32:56 UTC (rev 3640) @@ -27,7 +27,7 @@ this.op = op; } - protected IType[] GetTypes() + public IType[] GetTypes() { return types; } @@ -98,7 +98,7 @@ return null; } - private void InitializeInnerQueryAndParameters(ICriteriaQuery criteriaQuery) + public void InitializeInnerQueryAndParameters(ICriteriaQuery criteriaQuery) { ISessionFactoryImplementor factory = criteriaQuery.Factory; innerQuery = @@ -115,4 +115,4 @@ get { return criteriaImpl; } } } -} \ No newline at end of file +} Added: trunk/nhibernate/src/NHibernate/Criterion/SubqueryProjection.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/SubqueryProjection.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Criterion/SubqueryProjection.cs 2008-07-18 07:32:56 UTC (rev 3640) @@ -0,0 +1,59 @@ +using System; +using NHibernate.Impl; +using NHibernate.SqlCommand; +using NHibernate.Type; + +namespace NHibernate.Criterion +{ + using System.Collections.Generic; + + /// <summary> + /// A property value, or grouped property value + /// </summary> + [Serializable] + public class SubqueryProjection : SimpleProjection + { + private SelectSubqueryExpression _subQuery; + + protected internal SubqueryProjection(SelectSubqueryExpression subquery) + { + _subQuery = subquery; + } + public override string ToString() + { + return _subQuery.ToString(); + } + + public override bool IsGrouped + { + get { return false; } + } + + public override bool IsAggregate + { + get { return false; } + } + + public override IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery) + { + _subQuery.InitializeInnerQueryAndParameters(criteriaQuery); + return _subQuery.GetTypes(); + } + + public override SqlString ToSqlString(ICriteria criteria, int loc, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters) + { + SqlString sqlStringSubquery = _subQuery.ToSqlString(criteria, criteriaQuery, enabledFilters); + return sqlStringSubquery.Append(new SqlString(new object[] + { + " as y", + loc.ToString(), + "_" + })); + } + + public override SqlString ToGroupSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters) + { + throw new InvalidOperationException("not a grouping projection"); + } + } +} Modified: trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs 2008-07-18 06:52:02 UTC (rev 3639) +++ trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs 2008-07-18 07:32:56 UTC (rev 3640) @@ -73,7 +73,7 @@ .Add(StringHelper.Join(", ", columnsOrAliases)) .Add(" FROM (SELECT ROW_NUMBER() OVER(ORDER BY "); - AppendSortExpressions(sortExpressions, result); + AppendSortExpressions(columnsOrAliases, sortExpressions, result); result.Add(") as row, "); @@ -84,22 +84,27 @@ if (notLastColumn) result.Add(", "); } - - for (int i = 1; i <= sortExpressions.Length; ++i) + for (int i = 0; i < sortExpressions.Length; i++) { - result.Add(", query.__hibernate_sort_expr_") - .Add(i.ToString()) - .Add("__"); + string sortExpression = RemoveSortOrderDirection(sortExpressions[i]); + if(!columnsOrAliases.Contains(sortExpression)) + { + result.Add(", query.__hibernate_sort_expr_") + .Add(i.ToString()) + .Add("__"); + } } result.Add(" FROM (") .Add(select); - for (int i = 1; i <= sortExpressions.Length; i++) + for (int i = 0; i < sortExpressions.Length; i++) { - // Drop the ASC/DESC at the end of the sort expression which might look like "count(distinct frog.Id)desc" or "frog.Name asc". - string sortExpression = Regex.Replace(sortExpressions[i - 1].Trim(), @"(\)|\s)(?i:asc|desc)$", "$1").Trim(); + string sortExpression = RemoveSortOrderDirection(sortExpressions[i]); + if(columnsOrAliases.Contains(sortExpression)) + continue; + if (aliasToColumn.ContainsKey(sortExpression)) sortExpression = aliasToColumn[sortExpression]; @@ -116,23 +121,36 @@ .Add(offset.ToString()) .Add(" ORDER BY "); - AppendSortExpressions(sortExpressions, result); + AppendSortExpressions(columnsOrAliases, sortExpressions, result); return result.ToSqlString(); } - private void AppendSortExpressions(string[] sortExpressions, SqlStringBuilder result) + private static string RemoveSortOrderDirection(string sortExpression) { - for (int i = 1; i <= sortExpressions.Length; i++) + // Drop the ASC/DESC at the end of the sort expression which might look like "count(distinct frog.Id)desc" or "frog.Name asc". + return Regex.Replace(sortExpression.Trim(), @"(\)|\s)(?i:asc|desc)$", "$1").Trim(); + } + + private static void AppendSortExpressions(ICollection<string> columnsOrAliases, string[] sortExpressions, SqlStringBuilder result) + { + for (int i = 0; i < sortExpressions.Length; i++) { - if (i > 1) + if(i > 1) result.Add(", "); - result.Add("__hibernate_sort_expr_") - .Add(i.ToString()) - .Add("__"); - - if (sortExpressions[i - 1].Trim().ToLower().EndsWith("desc")) + string sortExpression = RemoveSortOrderDirection(sortExpressions[i]); + if(columnsOrAliases.Contains(sortExpression)) + { + result.Add(sortExpression); + } + else + { + result.Add("__hibernate_sort_expr_") + .Add(i.ToString()) + .Add("__"); + } + if (sortExpressions[i].Trim().ToLower().EndsWith("desc")) result.Add(" DESC"); } } @@ -181,6 +199,8 @@ index += 1; } + string alias = token; + bool isFunctionCallOrQuotedString = token.Contains("'") || token.Contains("("); // this is heuristic guess, if the expression contains ' or (, it is probably // not appropriate to just slice parts off of it @@ -188,11 +208,9 @@ { int dot = token.IndexOf('.'); if (dot != -1) - token = token.Substring(dot + 1); + alias = token.Substring(dot + 1); } - string alias = token; - // notice! we are checking here the existence of "as" "alias", two // tokens from the current one if (index + 1 < tokens.Count && Modified: trunk/nhibernate/src/NHibernate/Loader/Loader.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2008-07-18 06:52:02 UTC (rev 3639) +++ trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2008-07-18 07:32:56 UTC (rev 3640) @@ -391,7 +391,7 @@ int entitySpan = EntityPersisters.Length; ArrayList hydratedObjects = entitySpan == 0 ? null : new ArrayList(entitySpan * 10); - ; + IDbCommand st = PrepareQueryCommand(queryParameters, false, session); IDataReader rs = @@ -1830,4 +1830,4 @@ #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj 2008-07-18 06:52:02 UTC (rev 3639) +++ trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj 2008-07-18 07:32:56 UTC (rev 3640) @@ -586,6 +586,7 @@ <Compile Include="Dialect\Lock\UpdateLockingStrategy.cs" /> <Compile Include="Dialect\MsSqlCeDialect.cs" /> <Compile Include="Dialect\MySQL5Dialect.cs" /> + <Compile Include="Criterion\SelectSubqueryExpression.cs" /> <Compile Include="Dialect\PostgreSQL82Dialect.cs" /> <Compile Include="Dialect\Schema\FirebirdMetaData.cs" /> <Compile Include="Dialect\Schema\ITableMetadata.cs" /> @@ -594,6 +595,7 @@ <Compile Include="Dialect\Sybase11Dialect.cs" /> <Compile Include="Driver\ISqlParameterFormatter.cs" /> <Compile Include="Driver\SqlStringFormatter.cs" /> + <Compile Include="Criterion\SubqueryProjection.cs" /> <Compile Include="EmptyInterceptor.cs" /> <Compile Include="Engine\ActionQueue.cs" /> <Compile Include="Engine\AssociationKey.cs" /> Modified: trunk/nhibernate/src/NHibernate/NHibernate-3.5.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate-3.5.csproj 2008-07-18 06:52:02 UTC (rev 3639) +++ trunk/nhibernate/src/NHibernate/NHibernate-3.5.csproj 2008-07-18 07:32:56 UTC (rev 3640) @@ -586,6 +586,7 @@ <Compile Include="Criterion\Restrictions.cs" /> <Compile Include="Criterion\RowCountInt64Projection.cs" /> <Compile Include="Criterion\RowCountProjection.cs" /> + <Compile Include="Criterion\SelectSubqueryExpression.cs" /> <Compile Include="Criterion\SimpleExpression.cs" /> <Compile Include="Criterion\SimpleProjection.cs" /> <Compile Include="Criterion\SimpleSubqueryExpression.cs" /> @@ -594,6 +595,7 @@ <Compile Include="Criterion\SQLProjection.cs" /> <Compile Include="Criterion\Subqueries.cs" /> <Compile Include="Criterion\SubqueryExpression.cs" /> + <Compile Include="Criterion\SubqueryProjection.cs" /> <Compile Include="DebugHelpers\DictionaryProxy.cs" /> <Compile Include="DebugHelpers\CollectionProxy.cs" /> <Compile Include="Dialect\Function\AnsiExtractFunction.cs" /> Modified: trunk/nhibernate/src/NHibernate/SqlCommand/InFragment.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/InFragment.cs 2008-07-18 06:52:02 UTC (rev 3639) +++ trunk/nhibernate/src/NHibernate/SqlCommand/InFragment.cs 2008-07-18 07:32:56 UTC (rev 3640) @@ -1,3 +1,4 @@ + using System; using System.Collections; using NHibernate.Util; @@ -119,6 +120,8 @@ } else { + if(values.Count == 0) + throw new ArgumentOutOfRangeException("Attempting to parse a null value into an sql string."); object value = values[0]; if (Null.Equals(value)) { @@ -136,4 +139,4 @@ return buf.ToSqlString(); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/SqlCommand/SubselectClauseExtractor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/SubselectClauseExtractor.cs 2008-07-18 06:52:02 UTC (rev 3639) +++ trunk/nhibernate/src/NHibernate/SqlCommand/SubselectClauseExtractor.cs 2008-07-18 07:32:56 UTC (rev 3640) @@ -16,7 +16,7 @@ private int lastOrderByIndex; private int lastOrderByPartIndex; - + private int parenNestCount; private object[] sqlParts; /// <summary> @@ -72,7 +72,7 @@ public SqlString GetSqlString() { IEnumerator partEnumerator = sqlParts.GetEnumerator(); - + parenNestCount = 0; // Process the parts until FROM is found while (partEnumerator.MoveNext()) { @@ -94,12 +94,11 @@ return builder.ToSqlString(); } - private static int FindFromClauseInPart(string part) + private int FindFromClauseInPart(string part) { int afterLastClosingParenIndex = 0; int fromIndex = StringHelper.IndexOfCaseInsensitive(part, FromClauseToken); - int parenNestCount = 0; - + for (int i = 0; i < part.Length; i++) { if (parenNestCount == 0 && i > fromIndex) @@ -129,6 +128,9 @@ fromIndex = StringHelper.IndexOfCaseInsensitive(part, FromClauseToken); } + if(parenNestCount > 0) + return -1; + return fromIndex; } Modified: trunk/nhibernate/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs 2008-07-18 06:52:02 UTC (rev 3639) +++ trunk/nhibernate/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs 2008-07-18 07:32:56 UTC (rev 3640) @@ -17,49 +17,49 @@ SqlString str = d.GetLimitString(new SqlString("SELECT fish.id FROM fish"), 0, 10); Assert.AreEqual( - "SELECT TOP 10 id FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_1__) as row, query.id, query.__hibernate_sort_expr_1__ FROM (SELECT fish.id, CURRENT_TIMESTAMP as __hibernate_sort_expr_1__ FROM fish) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_1__", + "SELECT TOP 10 id FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_0__) as row, query.id, query.__hibernate_sort_expr_0__ FROM (SELECT fish.id, CURRENT_TIMESTAMP as __hibernate_sort_expr_0__ FROM fish) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_0__", str.ToString()); str = d.GetLimitString(new SqlString("SELECT DISTINCT fish_.id FROM fish fish_"), 0, 10); Assert.AreEqual( - "SELECT TOP 10 id FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_1__) as row, query.id, query.__hibernate_sort_expr_1__ FROM (SELECT DISTINCT fish_.id, CURRENT_TIMESTAMP as __hibernate_sort_expr_1__ FROM fish fish_) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_1__", + "SELECT TOP 10 id FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_0__) as row, query.id, query.__hibernate_sort_expr_0__ FROM (SELECT DISTINCT fish_.id, CURRENT_TIMESTAMP as __hibernate_sort_expr_0__ FROM fish fish_) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_0__", str.ToString()); str = d.GetLimitString(new SqlString("SELECT DISTINCT fish_.id as ixx9_ FROM fish fish_"), 0, 10); Assert.AreEqual( - "SELECT TOP 10 ixx9_ FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_1__) as row, query.ixx9_, query.__hibernate_sort_expr_1__ FROM (SELECT DISTINCT fish_.id as ixx9_, CURRENT_TIMESTAMP as __hibernate_sort_expr_1__ FROM fish fish_) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_1__", + "SELECT TOP 10 ixx9_ FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_0__) as row, query.ixx9_, query.__hibernate_sort_expr_0__ FROM (SELECT DISTINCT fish_.id as ixx9_, CURRENT_TIMESTAMP as __hibernate_sort_expr_0__ FROM fish fish_) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_0__", str.ToString()); str = d.GetLimitString(new SqlString("SELECT * FROM fish ORDER BY name"), 5, 15); Assert.AreEqual( - "SELECT TOP 15 * FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_1__) as row, query.*, query.__hibernate_sort_expr_1__ FROM (SELECT *, name as __hibernate_sort_expr_1__ FROM fish) query ) page WHERE page.row > 5 ORDER BY __hibernate_sort_expr_1__", + "SELECT TOP 15 * FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_0__) as row, query.*, query.__hibernate_sort_expr_0__ FROM (SELECT *, name as __hibernate_sort_expr_0__ FROM fish) query ) page WHERE page.row > 5 ORDER BY __hibernate_sort_expr_0__", str.ToString()); str = d.GetLimitString(new SqlString("SELECT fish.id, fish.name FROM fish ORDER BY name DESC"), 7, 28); Assert.AreEqual( - "SELECT TOP 28 id, name FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_1__ DESC) as row, query.id, query.name, query.__hibernate_sort_expr_1__ FROM (SELECT fish.id, fish.name, name as __hibernate_sort_expr_1__ FROM fish) query ) page WHERE page.row > 7 ORDER BY __hibernate_sort_expr_1__ DESC", + "SELECT TOP 28 id, name FROM (SELECT ROW_NUMBER() OVER(ORDER BY name DESC) as row, query.id, query.name FROM (SELECT fish.id, fish.name FROM fish) query ) page WHERE page.row > 7 ORDER BY name DESC", str.ToString()); str = d.GetLimitString( new SqlString("SELECT * FROM fish LEFT JOIN (SELECT * FROM meat ORDER BY weight) AS t ORDER BY name DESC"), 10, 20); Assert.AreEqual( - "SELECT TOP 20 * FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_1__ DESC) as row, query.*, query.__hibernate_sort_expr_1__ FROM (SELECT *, name as __hibernate_sort_expr_1__ FROM fish LEFT JOIN (SELECT * FROM meat ORDER BY weight) AS t) query ) page WHERE page.row > 10 ORDER BY __hibernate_sort_expr_1__ DESC", + "SELECT TOP 20 * FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_0__ DESC) as row, query.*, query.__hibernate_sort_expr_0__ FROM (SELECT *, name as __hibernate_sort_expr_0__ FROM fish LEFT JOIN (SELECT * FROM meat ORDER BY weight) AS t) query ) page WHERE page.row > 10 ORDER BY __hibernate_sort_expr_0__ DESC", str.ToString()); str = d.GetLimitString(new SqlString("SELECT *, (SELECT COUNT(1) FROM fowl WHERE fish_id = fish.id) AS some_count FROM fish"), 0, 10); Assert.AreEqual( - "SELECT TOP 10 *, some_count FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_1__) as row, query.*, query.some_count, query.__hibernate_sort_expr_1__ FROM (SELECT *, (SELECT COUNT(1) FROM fowl WHERE fish_id = fish.id) AS some_count, CURRENT_TIMESTAMP as __hibernate_sort_expr_1__ FROM fish) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_1__", + "SELECT TOP 10 *, some_count FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_0__) as row, query.*, query.some_count, query.__hibernate_sort_expr_0__ FROM (SELECT *, (SELECT COUNT(1) FROM fowl WHERE fish_id = fish.id) AS some_count, CURRENT_TIMESTAMP as __hibernate_sort_expr_0__ FROM fish) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_0__", str.ToString()); str = d.GetLimitString(new SqlString("SELECT * FROM fish WHERE scales = ", Parameter.Placeholder), 0, 10); Assert.AreEqual( - "SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_1__) as row, query.*, query.__hibernate_sort_expr_1__ FROM (SELECT *, CURRENT_TIMESTAMP as __hibernate_sort_expr_1__ FROM fish WHERE scales = ?) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_1__", + "SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_0__) as row, query.*, query.__hibernate_sort_expr_0__ FROM (SELECT *, CURRENT_TIMESTAMP as __hibernate_sort_expr_0__ FROM fish WHERE scales = ?) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_0__", str.ToString()); str = d.GetLimitString(new SqlString("SELECT f.Type, COUNT(DISTINCT f.Name) AS Name FROM Fish f GROUP BY f.Type ORDER BY COUNT(DISTINCT f.Name)"), 0, 10); Assert.AreEqual( - "SELECT TOP 10 Type, Name FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_1__) as row, query.Type, query.Name, query.__hibernate_sort_expr_1__ FROM (SELECT f.Type, COUNT(DISTINCT f.Name) AS Name, COUNT(DISTINCT f.Name) as __hibernate_sort_expr_1__ FROM Fish f GROUP BY f.Type) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_1__", + "SELECT TOP 10 Type, Name FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_0__) as row, query.Type, query.Name, query.__hibernate_sort_expr_0__ FROM (SELECT f.Type, COUNT(DISTINCT f.Name) AS Name, COUNT(DISTINCT f.Name) as __hibernate_sort_expr_0__ FROM Fish f GROUP BY f.Type) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_0__", str.ToString()); } @@ -69,13 +69,13 @@ MsSql2005Dialect d = new MsSql2005Dialect(); SqlString result = d.GetLimitString(new SqlString("select concat(a.Description,', ', a.Description) as desc from Animal a"), 0, 10); - Assert.AreEqual("SELECT TOP 10 desc FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_1__) as row, query.desc, query.__hibernate_sort_expr_1__ FROM (select concat(a.Description,', ', a.Description) as desc, CURRENT_TIMESTAMP as __hibernate_sort_expr_1__ from Animal a) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_1__", result.ToString()); + Assert.AreEqual("SELECT TOP 10 desc FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_0__) as row, query.desc, query.__hibernate_sort_expr_0__ FROM (select concat(a.Description,', ', a.Description) as desc, CURRENT_TIMESTAMP as __hibernate_sort_expr_0__ from Animal a) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_0__", result.ToString()); // The test use the function "cast" because cast need the keyWork "as" too SqlString str = d.GetLimitString(new SqlString("SELECT fish.id, cast('astring, with,comma' as string) as bar FROM fish"), 0, 10); Assert.AreEqual( - "SELECT TOP 10 id, bar FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_1__) as row, query.id, query.bar, query.__hibernate_sort_expr_1__ FROM (SELECT fish.id, cast('astring, with,comma' as string) as bar, CURRENT_TIMESTAMP as __hibernate_sort_expr_1__ FROM fish) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_1__", + "SELECT TOP 10 id, bar FROM (SELECT ROW_NUMBER() OVER(ORDER BY __hibernate_sort_expr_0__) as row, query.id, query.bar, query.__hibernate_sort_expr_0__ FROM (SELECT fish.id, cast('astring, with,comma' as string) as bar, CURRENT_TIMESTAMP as __hibernate_sort_expr_0__ FROM fish) query ) page WHERE page.row > 0 ORDER BY __hibernate_sort_expr_0__", str.ToString()); } [Test] Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1101/Domain.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1101/Domain.cs 2008-07-18 06:52:02 UTC (rev 3639) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1101/Domain.cs 2008-07-18 07:32:56 UTC (rev 3640) @@ -2,7 +2,9 @@ { public class A { +#pragma warning disable 649 private int id; +#pragma warning restore 649 private string descript; private B b; public A() {} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1359/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1359/Fixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1359/Fixture.cs 2008-07-18 07:32:56 UTC (rev 3640) @@ -0,0 +1,196 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using NHibernate.Criterion; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH1359 +{ + [TestFixture] + public class Fixture : BugTestCase + { + public override string BugNumber + { + get { return "NH1359"; } + } + + protected override void OnTearDown() + { + base.OnTearDown(); + using(ISession session = OpenSession()) + { + using(ITransaction tx = session.BeginTransaction()) + { + session.Delete("from Person"); + tx.Commit(); + } + } + } + + protected override void OnSetUp() + { + using(ISession s = OpenSession()) + { + using(ITransaction tx = s.BeginTransaction()) + { + Person e1 = new Person("Joe", 10, 9); + Person e2 = new Person("Sally", 20, 8); + Person e3 = new Person("Tim", 20, 7); //20 + Person e4 = new Person("Fred", 40, 40); + Person e5 = new Person("Fred", 50, 50); + s.Save(e1); + s.Save(e2); + s.Save(e3); + s.Save(e4); + s.Save(e5); + Pet p = new Pet("Fido", "Dog", 25, e1); + Pet p2 = new Pet("Biff", "Dog", 10, e1); + s.Save(p); + s.Save(p2); + tx.Commit(); + } + } + } + + [Test] + public void CanSetSubQueryProjectionFromDetachedCriteriaWithCountProjection() + { + using(ISession s = OpenSession()) + { + // This query doesn't make sense at all + DetachedCriteria dc = DetachedCriteria.For<Person>() + .SetProjection(Projections.Count("Id")); + + ICriteria c = s.CreateCriteria(typeof(Person)) + .SetProjection(Projections.SubQuery(dc)) + .Add(Expression.Eq("Name", "Fred")); + + IList list = c.List(); + Assert.AreEqual(2, list.Count); + foreach(object item in list) + { + Assert.AreEqual(5, item); + } + } + } + + public class HeaviestPet + { + public string Name; + public double Weight; + } + + [Test] + public void CanSubqueryRelatedObjectsNotInMainQuery() + { + using(ISession s = OpenSession()) + { + DetachedCriteria dc = DetachedCriteria.For<Person>().CreateCriteria("Pets", "pets") + .SetProjection(Projections.Max("pets.Weight")); + ICriteria c = s.CreateCriteria(typeof(Person)) + .SetProjection(Projections.ProjectionList() + .Add(Projections.SubQuery(dc), "Weight") + .Add(Projections.Property("Name"), "Name")) + .Add(Restrictions.Eq("Name", "Joe")); + c.SetResultTransformer(Transformers.AliasToBean(typeof(HeaviestPet))); + + IList<HeaviestPet> list = c.List<HeaviestPet>(); + Assert.AreEqual(1, list.Count); + foreach(HeaviestPet pet in list) + { + Assert.AreEqual("Joe", pet.Name); + Assert.AreEqual(25, pet.Weight); + } + } + } + + [Test] + public void CanGetSelectSubqueryWithSpecifiedParameter() + { + using (ISession s = OpenSession()) + { + DetachedCriteria dc = DetachedCriteria.For<Person>().Add(Restrictions.Eq("Name", "Joe")) + .SetProjection(Projections.Max("Name")); + ICriteria c = s.CreateCriteria(typeof(Person)) + .SetProjection(Projections.ProjectionList() + .Add(Projections.SubQuery(dc), "Name")) + .Add(Restrictions.Eq("Name", "Joe")); + c.SetResultTransformer(Transformers.AliasToBean(typeof(HeaviestPet))); + IList<HeaviestPet> list = c.List<HeaviestPet>(); + Assert.AreEqual(1, list.Count); + foreach(HeaviestPet pet in list) + { + Assert.AreEqual("Joe", pet.Name); + } + } + } + + + [Test] + public void CanPageAndSortResultsWithParametersAndFilters() + { + using(ISession s = OpenSession()) + { + s.EnableFilter("ExampleFilter").SetParameter("WeightVal", 100); + DetachedCriteria dc = DetachedCriteria.For<Person>().CreateCriteria("Pets", "pets") + .SetProjection(Projections.Max("pets.Weight")) + .Add(Restrictions.Eq("pets.Weight", 10.0)); + ICriteria c = s.CreateCriteria(typeof(Person)) + .SetProjection(Projections.ProjectionList() + .Add(Projections.SubQuery(dc), "Weight") + .Add(Projections.Property("Name"), "Name")) + .Add(Restrictions.Eq("Name", "Joe")); + + c.SetResultTransformer(Transformers.AliasToBean(typeof(HeaviestPet))); + c.SetMaxResults(1); + c.AddOrder(new Order("Id", true)); + IList<HeaviestPet> list = c.List<HeaviestPet>(); + Assert.AreEqual(1, list.Count); + foreach(HeaviestPet pet in list) + { + Assert.AreEqual("Joe", pet.Name); + Assert.AreEqual(10.0, pet.Weight); + } + } + } + + [Test] + public void CanPageAndSortWithMultipleColumnsOfSameName() + { + using(ISession s = OpenSession()) + { + ICriteria c = s.CreateCriteria(typeof(Person),"root") + .CreateCriteria("root.Pets","pets") + .SetProjection(Projections.ProjectionList() + .Add(Projections.Property("root.Id"), "Id") + .Add(Projections.Property("root.Name"), "Name")) + .Add(Restrictions.Eq("Name", "Fido")); + c.AddOrder(new Order("Id", true)); + c.SetResultTransformer(Transformers.AliasToBean(typeof(Person))); + c.SetMaxResults(1); + IList<Person> list = c.List<Person>(); + Assert.AreEqual(1, list.Count); + } + } + + [Test] + public void CanOrderByNamedSubquery() + { + using(ISession s = OpenSession()) + { + DetachedCriteria dc = DetachedCriteria.For<Person>().Add(Restrictions.Eq("Name", "Joe")) + .SetProjection(Projections.Max("Name")); + ICriteria c = s.CreateCriteria(typeof(Person)) + .SetProjection(Projections.ProjectionList() + .Add(Projections.SubQuery(dc), "NameSubquery")) + .Add(Restrictions.Eq("Name", "Joe")); + c.AddOrder(new Order("NameSubquery", true)); + c.SetMaxResults(1); + IList list = c.List(); + Assert.AreEqual(1, list.Count); + } + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1359/Mappings.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1359/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1359/Mappings.hbm.xml 2008-07-18 07:32:56 UTC (rev 3640) @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.NHSpecificTest.NH1359"> + + <class name="Person" lazy="false"> + <id name="Id"> + <generator class="native" /> + </id> + <bag name="Pets" inverse="true" lazy="false" cascade="all-delete-orphan"> + <key column="PersonId" /> + <one-to-many class="Pet"/> + <filter name="ExampleFilter" condition=":WeightVal >= Weight" /> + </bag> + <property name="Name"/> + <property name="IQ"/> + <property name="ShoeSize"/> + </class> + + <class name="Pet" lazy="false"> + <id name="Id"> + <generator class="native" /> + </id> + <many-to-one name="Owner" column="PersonId" not-null="true"/> + <property name="Name"/> + <property name="Species"/> + <property name="Weight"/> + </class> + + <filter-def name="ExampleFilter"> + <filter-param name="WeightVal" type="int"/> + </filter-def> + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1359/Person.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1359/Person.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1359/Person.cs 2008-07-18 07:32:56 UTC (rev 3640) @@ -0,0 +1,107 @@ +using System.Collections; + +namespace NHibernate.Test.NHSpecificTest.NH1359 +{ + public class Person + { + private int id; + private int iq; + private string name; + private IList pets; + private int shoeSize; + + public Person() + { + Pets = new ArrayList(); + } + + public Person(string name, int iq, int shoeSize) + { + this.name = name; + this.iq = iq; + this.shoeSize = shoeSize; + Pets = new ArrayList(); + } + + public virtual int Id + { + get { return id; } + set { id = value; } + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual int IQ + { + get { return iq; } + set { iq = value; } + } + + public virtual int ShoeSize + { + get { return shoeSize; } + set { shoeSize = value; } + } + + public virtual IList Pets + { + get { return pets; } + protected set { pets = value; } + } + } + + public class Pet + { + private int id; + private string name; + private Person owner; + private string species; + private double weight; + + public Pet() + { + } + + public Pet(string name, string species, int weight, Person owner) + { + this.name = name; + this.species = species; + this.weight = weight; + this.owner = owner; + } + + public virtual int Id + { + get { return id; } + set { id = value; } + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual string Species + { + get { return species; } + set { species = value; } + } + + public virtual double Weight + { + get { return weight; } + set { weight = value; } + } + + public virtual Person Owner + { + get { return owner; } + set { owner = value; } + } + } +} Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-18 06:52:02 UTC (rev 3639) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-18 07:32:56 UTC (rev 3640) @@ -390,6 +390,8 @@ <Compile Include="NHSpecificTest\Docs\Associations\BiM21\Person.cs" /> <Compile Include="NHSpecificTest\Docs\ExampleParentChild\Child.cs" /> <Compile Include="NHSpecificTest\Docs\ExampleParentChild\Parent.cs" /> + <Compile Include="NHSpecificTest\NH1359\Fixture.cs" /> + <Compile Include="NHSpecificTest\NH1359\Person.cs" /> <Compile Include="NHSpecificTest\Docs\ExampleParentChild\UpdateFixture.cs" /> <Compile Include="NHSpecificTest\Docs\PersistentClasses\Cat.cs" /> <Compile Include="NHSpecificTest\EmptyMappingsFixture.cs" /> @@ -1316,6 +1318,7 @@ <EmbeddedResource Include="UserCollection\Parameterized\Mapping.hbm.xml" /> </ItemGroup> <ItemGroup> + <EmbeddedResource Include="NHSpecificTest\NH1359\Mappings.hbm.xml" /> <EmbeddedResource Include="IdTest\Car.hbm.xml" /> <EmbeddedResource Include="IdTest\Plane.hbm.xml" /> <EmbeddedResource Include="IdTest\Product.hbm.xml" /> Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-3.5.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-3.5.csproj 2008-07-18 06:52:02 UTC (rev 3639) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-3.5.csproj 2008-07-18 07:32:56 UTC (rev 3640) @@ -390,6 +390,8 @@ <Compile Include="NHSpecificTest\NH1355\UserTypeTimestamp.cs"> <SubType>Code</SubType> </Compile> + <Compile Include="NHSpecificTest\NH1359\Fixture.cs" /> + <Compile Include="NHSpecificTest\NH1359\Person.cs" /> <Compile Include="NHSpecificTest\NH1362\Fixture.cs"> <SubType>Code</SubType> </Compile> @@ -1316,6 +1318,9 @@ <EmbeddedResource Include="NHSpecificTest\NH693\SpaceTableName.hbm.xml" /> </ItemGroup> <ItemGroup> + <EmbeddedResource Include="NHSpecificTest\NH1359\Mappings.hbm.xml" /> + </ItemGroup> + <ItemGroup> <Folder Include="Properties\" /> <Folder Include="Unionsubclass2\" /> </ItemGroup> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-07-21 04:50:01
|
Revision: 3642 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3642&view=rev Author: fabiomaulo Date: 2008-07-21 04:49:58 +0000 (Mon, 21 Jul 2008) Log Message: ----------- - Enabled <tuplizer> (NH-1397) - Fix NH-1395 - Fix NH-1396 Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Cfg/HbmConstants.cs trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs trunk/nhibernate/src/NHibernate/EmptyInterceptor.cs trunk/nhibernate/src/NHibernate/Engine/UnsavedValueFactory.cs trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs trunk/nhibernate/src/NHibernate/Mapping/PersistentClass.cs trunk/nhibernate/src/NHibernate/Mapping/Subclass.cs trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityEntityModeToTuplizerMapping.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Address.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Company.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Customer.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/DataProxyHandler.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/IProxyMarker.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/Customer.hbm.xml trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/ProxyInterceptor.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Person.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/ProxyHelper.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/Customer.hbm.xml trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/EntityNameInterceptor.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityInstantiator.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityTuplizer.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs Modified: trunk/nhibernate/src/NHibernate/Cfg/HbmConstants.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/HbmConstants.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Cfg/HbmConstants.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -48,5 +48,6 @@ public const string nsResultset = nsPrefix + ":resultset"; public const string nsUnionSubclass = nsPrefix + ":union-subclass"; + public const string nsTuplizer = nsPrefix + ":tuplizer"; } } Modified: trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -106,36 +106,32 @@ protected void BindClass(XmlNode node, PersistentClass model) { - string className = node.Attributes["name"] == null ? null : FullClassName(node.Attributes["name"].Value, mappings); + // transfer an explicitly defined entity name + // handle the lazy attribute + XmlAttribute lazyNode = node.Attributes["lazy"]; + bool lazy = lazyNode == null ? mappings.DefaultLazy : "true".Equals(lazyNode.Value); + // go ahead and set the lazy here, since pojo.proxy can override it. + model.IsLazy = lazy; - // CLASS - model.ClassName = ClassForFullNameChecked(className, "persistent class {0} not found").AssemblyQualifiedName; - - string entityName = node.Attributes["entity-name"] == null ? null : node.Attributes["name"].Value; + string entityName = (node.Attributes["entity-name"] != null ? node.Attributes["entity-name"].Value : null) + ?? + ClassForNameChecked(node.Attributes["name"].Value, mappings, "persistent class {0} not found"). + FullName; if (entityName == null) - entityName = model.MappedClass.FullName; - if (entityName == null) { throw new MappingException("Unable to determine entity name"); } model.EntityName = entityName; - // PROXY INTERFACE - XmlAttribute proxyNode = node.Attributes["proxy"]; - XmlAttribute lazyNode = node.Attributes["lazy"]; - bool lazy = lazyNode == null ? mappings.DefaultLazy : "true".Equals(lazyNode.Value); + BindPocoRepresentation(node, model); + BindXmlRepresentation(node, model); + BindMapRepresentation(node, model); - // go ahead and set the lazy here, since pojo.proxy can override it. - model.IsLazy = lazy; + BindPersistentClassCommonValues(node, model); + } - if (proxyNode != null) - { - model.ProxyInterfaceName = ClassForNameChecked(proxyNode.Value, mappings, "proxy class not found: {0}").AssemblyQualifiedName; - model.IsLazy = true; - } - else if (model.IsLazy) - model.ProxyInterfaceName = model.MappedClass.AssemblyQualifiedName; - + private void BindPersistentClassCommonValues(XmlNode node, PersistentClass model) + { // DISCRIMINATOR XmlAttribute discriminatorNode = node.Attributes["discriminator-value"]; model.DiscriminatorValue = (discriminatorNode == null) ? model.EntityName : discriminatorNode.Value; @@ -179,8 +175,8 @@ //persister = typeof( EntityPersister ); } else - model.EntityPersisterClass = - ClassForNameChecked(persisterNode.Value, mappings, "could not instantiate persister class: {0}"); + model.EntityPersisterClass = ClassForNameChecked(persisterNode.Value, mappings, + "could not instantiate persister class: {0}"); // CUSTOM SQL HandleCustomSQL(node, model); @@ -200,6 +196,71 @@ model.IsAbstract = isAbstract; } + private void BindMapRepresentation(XmlNode node, PersistentClass entity) + { + XmlNode tuplizer = LocateTuplizerDefinition(node, EntityMode.Map); + if (tuplizer != null) + { + string tupClassName = FullClassName(tuplizer.Attributes["class"].Value, mappings); + entity.AddTuplizer(EntityMode.Map, tupClassName); + } + } + + private void BindXmlRepresentation(XmlNode node, PersistentClass entity) + { + string nodeName = null; + XmlAttribute nodeAtt = node.Attributes["node"]; + if(nodeAtt != null) + nodeName = nodeAtt.Value; + if (nodeName == null) + nodeName = StringHelper.Unqualify(entity.EntityName); + entity.NodeName = nodeName; + + XmlNode tuplizer = LocateTuplizerDefinition(node, EntityMode.Xml); + if (tuplizer != null) + { + string tupClassName = FullClassName(tuplizer.Attributes["class"].Value, mappings); + entity.AddTuplizer(EntityMode.Xml, tupClassName); + } + } + + private void BindPocoRepresentation(XmlNode node, PersistentClass entity) + { + string className = node.Attributes["name"] == null + ? null + : ClassForNameChecked(node.Attributes["name"].Value, mappings, "persistent class {0} not found"). + AssemblyQualifiedName; + + entity.ClassName = className; + + XmlAttribute proxyNode = node.Attributes["proxy"]; + if (proxyNode != null) + { + entity.ProxyInterfaceName = ClassForNameChecked(proxyNode.Value, mappings, "proxy class not found: {0}").AssemblyQualifiedName; + entity.IsLazy = true; + } + else if (entity.IsLazy) + entity.ProxyInterfaceName = className; + + XmlNode tuplizer = LocateTuplizerDefinition(node, EntityMode.Poco); + if (tuplizer != null) + { + string tupClassName = FullClassName(tuplizer.Attributes["class"].Value, mappings); + entity.AddTuplizer(EntityMode.Poco, tupClassName); + } + } + + private XmlNode LocateTuplizerDefinition(XmlNode container, EntityMode mode) + { + string modeToFind = EntityModeHelper.ToString(mode); + foreach (XmlNode node in container.SelectNodes(HbmConstants.nsTuplizer, namespaceManager)) + { + if (modeToFind.Equals(node.Attributes["entity-mode"].Value)) + return node; + } + return null; + } + private void BindJoin(XmlNode node, Join join) { PersistentClass persistentClass = join.PersistentClass; @@ -1116,27 +1177,20 @@ private static string GetEntityName(XmlNode elem, Mappings model) { - // TODO: H3.2 Implement real entityName (look at IEntityPersister for feature) - //string entityName = XmlHelper.GetAttributeValue(elem, "entity-name"); - //return entityName == null ? GetClassName( elem.Attributes[ "class" ], model ) : entityName; - XmlAttribute att = elem.Attributes["class"]; + string entityName = XmlHelper.GetAttributeValue(elem, "entity-name"); + if (entityName == null) + { + XmlAttribute att = elem.Attributes["class"]; - if (att == null) - return null; + return att == null ? null : GetClassName(att.Value, model); + } + else + { + return entityName; + } - return GetClassName(att.Value, model); } - private static string GetQualifiedClassName(XmlNode elem, Mappings model) - { - XmlAttribute att = elem.Attributes["class"]; - - if (att == null) - return null; - - return GetQualifiedClassName(att.Value, model); - } - protected XmlNodeList SelectNodes(XmlNode node, string xpath) { return node.SelectNodes(xpath, namespaceManager); Modified: trunk/nhibernate/src/NHibernate/EmptyInterceptor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/EmptyInterceptor.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/EmptyInterceptor.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -58,7 +58,7 @@ return null; } - public string GetEntityName(object entity) + public virtual string GetEntityName(object entity) { return null; } Modified: trunk/nhibernate/src/NHibernate/Engine/UnsavedValueFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/UnsavedValueFactory.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Engine/UnsavedValueFactory.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -45,14 +45,11 @@ object defaultValue = identifierGetter.Get(Instantiate(constructor)); return new IdentifierValue(defaultValue); } - // TODO: NH - the branch below is actually never visited, so it's commented out - /* - else if( identifierGetter != null && ( identifierType is ValueTypeType ) ) + else if (identifierGetter != null && (identifierType is PrimitiveType)) { - object defaultValue = ( ( ValueTypeType ) identifierType ).DefaultValue; - return new Cascades.IdentifierValue( defaultValue ); + object defaultValue = ((PrimitiveType) identifierType).DefaultValue; + return new IdentifierValue(defaultValue); } - */ else { return IdentifierValue.SaveNull; Modified: trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -730,6 +730,7 @@ /// <returns></returns> public object Instantiate(IEntityPersister persister, object id) { + ErrorIfClosed(); object result = interceptor.Instantiate(persister.EntityName, entityMode, id); if (result == null) { Modified: trunk/nhibernate/src/NHibernate/Mapping/PersistentClass.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/PersistentClass.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Mapping/PersistentClass.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -59,7 +59,7 @@ private string temporaryIdTableName; private string temporaryIdTableDDL; - private IDictionary<EntityMode, System.Type> tuplizerImpls; + private IDictionary<EntityMode, string> tuplizerImpls; private Versioning.OptimisticLock optimisticLockMode; @@ -571,14 +571,11 @@ get { return temporaryIdTableDDL; } } - public virtual IDictionary<EntityMode, System.Type> TuplizerMap + public virtual IDictionary<EntityMode, string> TuplizerMap { get { - if (tuplizerImpls == null) - return null; - - return new Dictionary<EntityMode, System.Type>(tuplizerImpls); + return tuplizerImpls == null ? null : new UnmodifiableDictionary<EntityMode, string>(tuplizerImpls); } } @@ -1157,11 +1154,11 @@ get { return identifierMapper != null; } } - public void AddTuplizer(EntityMode entityMode, System.Type implClass) + public void AddTuplizer(EntityMode entityMode, string implClass) { if (tuplizerImpls == null) { - tuplizerImpls = new Dictionary<EntityMode, System.Type>(); + tuplizerImpls = new Dictionary<EntityMode, string>(); } tuplizerImpls[entityMode] = implClass; } @@ -1170,7 +1167,9 @@ { if (tuplizerImpls == null) return null; - return tuplizerImpls[mode].AssemblyQualifiedName; + string result; + tuplizerImpls.TryGetValue(mode, out result); + return result; } public bool HasNaturalId() Modified: trunk/nhibernate/src/NHibernate/Mapping/Subclass.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/Subclass.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Mapping/Subclass.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -161,19 +161,19 @@ get { return Superclass.FilterMap; } } - public override IDictionary<EntityMode, System.Type> TuplizerMap + public override IDictionary<EntityMode, string> TuplizerMap { get { - IDictionary<EntityMode, System.Type> specificTuplizerDefs = base.TuplizerMap; - IDictionary<EntityMode, System.Type> superclassTuplizerDefs = Superclass.TuplizerMap; + IDictionary<EntityMode, string> specificTuplizerDefs = base.TuplizerMap; + IDictionary<EntityMode, string> superclassTuplizerDefs = Superclass.TuplizerMap; if (specificTuplizerDefs == null && superclassTuplizerDefs == null) { return null; } else { - IDictionary<EntityMode, System.Type> combined = new Dictionary<EntityMode, System.Type>(); + IDictionary<EntityMode, string> combined = new Dictionary<EntityMode, string>(); if (superclassTuplizerDefs != null) { ArrayHelper.AddAll(combined, superclassTuplizerDefs); @@ -182,7 +182,7 @@ { ArrayHelper.AddAll(combined, specificTuplizerDefs); } - return combined; + return new UnmodifiableDictionary<EntityMode, string>(combined); } } } Modified: trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityEntityModeToTuplizerMapping.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityEntityModeToTuplizerMapping.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityEntityModeToTuplizerMapping.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using NHibernate.Mapping; +using NHibernate.Util; namespace NHibernate.Tuple.Entity { @@ -25,19 +26,14 @@ public EntityEntityModeToTuplizerMapping(PersistentClass mappedEntity, EntityMetamodel em) { // create our own copy of the user-supplied tuplizer impl map - Dictionary<EntityMode, System.Type> userSuppliedTuplizerImpls; - if (mappedEntity.TuplizerMap != null) - { - userSuppliedTuplizerImpls = new Dictionary<EntityMode, System.Type>(mappedEntity.TuplizerMap); - } - else - { - userSuppliedTuplizerImpls = new Dictionary<EntityMode, System.Type>(); - } + Dictionary<EntityMode, string> userSuppliedTuplizerImpls = mappedEntity.TuplizerMap != null + ? new Dictionary<EntityMode, string>( + mappedEntity.TuplizerMap) + : new Dictionary<EntityMode, string>(); // Build the dynamic-map tuplizer... ITuplizer dynamicMapTuplizer; - System.Type tuplizerImpl; + string tuplizerImpl; if (!userSuppliedTuplizerImpls.TryGetValue(EntityMode.Map, out tuplizerImpl)) { dynamicMapTuplizer = new DynamicMapEntityTuplizer(em, mappedEntity); @@ -51,7 +47,7 @@ // then the pojo tuplizer, using the dynamic-map tuplizer if no pojo representation is available ITuplizer pojoTuplizer; - System.Type tempObject2; + string tempObject2; userSuppliedTuplizerImpls.TryGetValue(EntityMode.Poco, out tempObject2); userSuppliedTuplizerImpls.Remove(EntityMode.Poco); tuplizerImpl = tempObject2; @@ -82,22 +78,23 @@ } // then handle any user-defined entity modes... - foreach (KeyValuePair<EntityMode, System.Type> pair in userSuppliedTuplizerImpls) + foreach (KeyValuePair<EntityMode, string> pair in userSuppliedTuplizerImpls) { IEntityTuplizer tuplizer = BuildEntityTuplizer(pair.Value, mappedEntity, em); AddTuplizer(pair.Key, tuplizer); } } - private static IEntityTuplizer BuildEntityTuplizer(System.Type implClass, PersistentClass pc, EntityMetamodel em) + private static IEntityTuplizer BuildEntityTuplizer(string className, PersistentClass pc, EntityMetamodel em) { try { + System.Type implClass = ReflectHelper.ClassForName(className); return (IEntityTuplizer)implClass.GetConstructor(entityTuplizerCTORSignature).Invoke(new object[] { em, pc }); } catch (Exception t) { - throw new HibernateException("Could not build tuplizer [" + implClass.FullName + "]", t); + throw new HibernateException("Could not build tuplizer [" + className + "]", t); } } Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Address.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Address.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Address.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,10 @@ +namespace NHibernate.Test.DynamicEntity +{ + public interface Address + { + long Id { get; set;} + string Street { get; set;} + string City { get; set;} + string PostalCode { get; set;} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Company.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Company.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Company.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,8 @@ +namespace NHibernate.Test.DynamicEntity +{ + public interface Company + { + long Id { get; set;} + string Name { get; set;} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Customer.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Customer.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Customer.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,7 @@ +namespace NHibernate.Test.DynamicEntity +{ + public interface Customer:Person + { + Company Company { get; set;} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/DataProxyHandler.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/DataProxyHandler.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/DataProxyHandler.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,59 @@ +using System.Collections; +using Castle.Core.Interceptor; + +namespace NHibernate.Test.DynamicEntity +{ + public sealed class DataProxyHandler : Castle.Core.Interceptor.IInterceptor + { + private readonly Hashtable data = new Hashtable(); + private readonly string entityName; + + public DataProxyHandler(string entityName, object id) + { + this.entityName = entityName; + data["Id"] = id; + } + + public string EntityName + { + get { return entityName; } + } + + public Hashtable Data + { + get { return data; } + } + + #region IInterceptor Members + + public void Intercept(IInvocation invocation) + { + invocation.ReturnValue = null; + string methodName = invocation.Method.Name; + if ("get_DataHandler".Equals(methodName)) + { + invocation.ReturnValue = this; + } + else if (methodName.StartsWith("set_")) + { + string propertyName = methodName.Substring(4); + data[propertyName] = invocation.Arguments[0]; + } + else if (methodName.StartsWith("get_")) + { + string propertyName = methodName.Substring(4); + invocation.ReturnValue = data[propertyName]; + } + else if ("ToString".Equals(methodName)) + { + invocation.ReturnValue = entityName + "#" + data["Id"]; + } + else if ("GetHashCode".Equals(methodName)) + { + invocation.ReturnValue = GetHashCode(); + } + } + + #endregion + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/IProxyMarker.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/IProxyMarker.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/IProxyMarker.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,7 @@ +namespace NHibernate.Test.DynamicEntity +{ + public interface IProxyMarker + { + DataProxyHandler DataHandler { get;} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/Customer.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/Customer.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/Customer.hbm.xml 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8" ?> + +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.DynamicEntity"> + + <!-- + Mapping the Customer and Company interfaces. Our custom Interceptor + will be responsible for: + a) creating instances representing these interfaces; + b) determining the appropriate entity-name (i.e., which entity mapping to use) given an instance of one of these proxies. + --> + <class name="Person" table="t_person" abstract="false"> + <!-- <class name="Person" table="t_person" discriminator-value="person"> --> + <id name="Id"> + <generator class="native"/> + </id> + <discriminator force="false"/> + <property name="Name"/> + + <many-to-one name="Address" cascade="all" column="addr_id"/> + + <set name="Family" lazy="true" cascade="all"> + <key column="pers_id"/> + <one-to-many class="Person"/> + </set> + + <subclass name="Customer" discriminator-value="customer" abstract="false"> + <many-to-one name="Company" cascade="none" column="comp_id"/> + </subclass> + </class> + + <!-- Company interface mapping --> + <class name="Company" table="t_company" abstract="false"> + <id name="Id"> + <generator class="native"/> + </id> + <property name="Name"/> + </class> + + <class name="Address" table="t_address" abstract="false"> + <id name="Id"> + <generator class="native"/> + </id> + <property name="Street"/> + <property name="City"/> + <property name="PostalCode"/> + </class> + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,92 @@ +using System.Collections; +using NHibernate.Cfg; +using NUnit.Framework; + +namespace NHibernate.Test.DynamicEntity.Interceptor +{ + [TestFixture] + public class InterceptorDynamicEntity : TestCase + { + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + protected override IList Mappings + { + get { return new string[] {"DynamicEntity.Interceptor.Customer.hbm.xml"}; } + } + + protected override void Configure(Configuration configuration) + { + configuration.SetInterceptor(new ProxyInterceptor()); + } + + [Test] + public void It() + { + // Test saving these dyna-proxies + ISession session = OpenSession(); + session.BeginTransaction(); + Company company = ProxyHelper.NewCompanyProxy(); + company.Name = "acme"; + session.Save(company); + Customer customer = ProxyHelper.NewCustomerProxy(); + customer.Name = "Steve"; + customer.Company = company; + session.Save(customer); + session.Transaction.Commit(); + session.Close(); + + Assert.IsNotNull(company.Id, "company id not assigned"); + Assert.IsNotNull(customer.Id, "customer id not assigned"); + + // Test loading these dyna-proxies, along with flush processing + session = OpenSession(); + session.BeginTransaction(); + customer = session.Load<Customer>(customer.Id); + Assert.IsFalse(NHibernateUtil.IsInitialized(customer), "should-be-proxy was initialized"); + + customer.Name = "other"; + session.Flush(); + Assert.IsFalse(NHibernateUtil.IsInitialized(customer.Company), "should-be-proxy was initialized"); + + session.Refresh(customer); + Assert.AreEqual("other", customer.Name, "name not updated"); + Assert.AreEqual("acme", customer.Company.Name, "company association not correct"); + + session.Transaction.Commit(); + session.Close(); + + // Test detached entity re-attachment with these dyna-proxies + customer.Name = "Steve"; + session = OpenSession(); + session.BeginTransaction(); + session.Update(customer); + session.Flush(); + session.Refresh(customer); + Assert.AreEqual("Steve", customer.Name, "name not updated"); + session.Transaction.Commit(); + session.Close(); + + // Test querying + session = OpenSession(); + session.BeginTransaction(); + int count = session.CreateQuery("from Customer").List().Count; + Assert.AreEqual(1, count, "querying dynamic entity"); + session.Clear(); + count = session.CreateQuery("from Person").List().Count; + Assert.AreEqual(1, count, "querying dynamic entity"); + session.Transaction.Commit(); + session.Close(); + + // test deleteing + session = OpenSession(); + session.BeginTransaction(); + session.Delete(company); + session.Delete(customer); + session.Transaction.Commit(); + session.Close(); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/ProxyInterceptor.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/ProxyInterceptor.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/ProxyInterceptor.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,27 @@ +namespace NHibernate.Test.DynamicEntity.Interceptor +{ + public class ProxyInterceptor : EmptyInterceptor + { + public override string GetEntityName(object entity) + { + string entityName = ProxyHelper.ExtractEntityName(entity) ?? base.GetEntityName(entity); + return entityName; + } + + public override object Instantiate(string entityName, EntityMode entityMode, object id) + { + if (entityMode == EntityMode.Poco) + { + if (typeof(Customer).FullName.Equals(entityName)) + { + return ProxyHelper.NewCustomerProxy(id); + } + else if (typeof(Company).FullName.Equals(entityName)) + { + return ProxyHelper.NewCompanyProxy(id); + } + } + return base.Instantiate(entityName, entityMode, id); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Person.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Person.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Person.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,12 @@ +using Iesi.Collections.Generic; + +namespace NHibernate.Test.DynamicEntity +{ + public interface Person + { + long Id { get; set;} + string Name { get; set;} + Address Address { get;set;} + ISet<Person> Family { get; set;} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/ProxyHelper.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/ProxyHelper.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/ProxyHelper.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,79 @@ +using Castle.DynamicProxy; + +namespace NHibernate.Test.DynamicEntity +{ + public class ProxyHelper + { + private static readonly ProxyGenerator proxyGenerator = new ProxyGenerator(); + + public static Person NewPersonProxy() + { + return NewPersonProxy(0L); + } + + public static Person NewPersonProxy(object id) + { + return + (Person) + proxyGenerator.CreateInterfaceProxyWithoutTarget(typeof (Person), + new System.Type[] {typeof (IProxyMarker), typeof (Person)}, + new DataProxyHandler(typeof (Person).FullName, id)); + } + + public static Customer NewCustomerProxy() + { + return NewCustomerProxy(0L); + } + + public static Customer NewCustomerProxy(object id) + { + return + (Customer) + proxyGenerator.CreateInterfaceProxyWithoutTarget(typeof (Customer), + new System.Type[] {typeof (IProxyMarker), typeof (Customer)}, + new DataProxyHandler(typeof (Customer).FullName, id)); + } + + public static Company NewCompanyProxy() + { + return NewCompanyProxy(0L); + } + + public static Company NewCompanyProxy(object id) + { + return + (Company) + proxyGenerator.CreateInterfaceProxyWithoutTarget(typeof (Company), + new System.Type[] {typeof (IProxyMarker), typeof (Company)}, + new DataProxyHandler(typeof (Company).FullName, id)); + } + + public static Address NewAddressProxy() + { + return NewAddressProxy(0L); + } + + public static Address NewAddressProxy(object id) + { + return + (Address) + proxyGenerator.CreateInterfaceProxyWithoutTarget(typeof (Address), + new System.Type[] {typeof (IProxyMarker), typeof (Address)}, + new DataProxyHandler(typeof (Address).FullName, id)); + } + + public static string ExtractEntityName(object obj) + { + // Our custom Proxy instances actually bundle + // their appropriate entity name, so we simply extract it from there + // if this represents one of our proxies; otherwise, we return null + IProxyMarker pm = obj as IProxyMarker; + if (pm != null) + { + DataProxyHandler myHandler = pm.DataHandler; + return myHandler.EntityName; + } + return null; + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/Customer.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/Customer.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/Customer.hbm.xml 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8" ?> + +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.DynamicEntity"> + + <!-- + Mapping the Customer and Company interfaces. Our custom Interceptor + will be responsible for: + a) creating instances representing these interfaces; + b) determining the appropriate entity-name (i.e., which entity mapping to use) given an instance of one of these proxies. + --> + <class name="Person" table="t_person" discriminator-value="person" abstract="false"> + <tuplizer class="NHibernate.Test.DynamicEntity.Tuplizer.MyEntityTuplizer, NHibernate.Test" entity-mode="poco"/> + <id name="Id"> + <generator class="native"/> + </id> + <discriminator force="false"/> + <property name="Name"/> + + <many-to-one name="Address" cascade="all" column="addr_id"/> + + <set name="Family" lazy="true" cascade="all" generic="true"> + <key column="pers_id"/> + <one-to-many class="Person"/> + </set> + + <subclass name="Customer" discriminator-value="customer" abstract="false"> + <tuplizer class="NHibernate.Test.DynamicEntity.Tuplizer.MyEntityTuplizer, NHibernate.Test" entity-mode="poco"/> + <many-to-one name="Company" cascade="none" column="comp_id"/> + </subclass> + </class> + + <!-- Company interface mapping --> + <class name="Company" table="t_company" abstract="false"> + <tuplizer class="NHibernate.Test.DynamicEntity.Tuplizer.MyEntityTuplizer, NHibernate.Test" entity-mode="poco"/> + <id name="Id"> + <generator class="native"/> + </id> + <property name="Name"/> + </class> + + <class name="Address" table="t_address" abstract="false"> + <tuplizer class="NHibernate.Test.DynamicEntity.Tuplizer.MyEntityTuplizer, NHibernate.Test" entity-mode="poco"/> + <id name="Id"> + <generator class="native"/> + </id> + <property name="Street"/> + <property name="City"/> + <property name="PostalCode"/> + </class> + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/EntityNameInterceptor.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/EntityNameInterceptor.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/EntityNameInterceptor.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,11 @@ +namespace NHibernate.Test.DynamicEntity.Tuplizer +{ + public class EntityNameInterceptor : EmptyInterceptor + { + public override string GetEntityName(object entity) + { + string entityName = ProxyHelper.ExtractEntityName(entity) ?? base.GetEntityName(entity); + return entityName; + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityInstantiator.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityInstantiator.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityInstantiator.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,56 @@ +using System; +using NHibernate.Tuple; + +namespace NHibernate.Test.DynamicEntity.Tuplizer +{ + public class MyEntityInstantiator : IInstantiator + { + private readonly System.Type entityType; + + public MyEntityInstantiator(System.Type entityType) + { + this.entityType = entityType; + } + + public object Instantiate(object id) + { + if (typeof(Person).Equals(entityType)) + { + return ProxyHelper.NewPersonProxy(id); + } + if (typeof(Customer).Equals(entityType)) + { + return ProxyHelper.NewCustomerProxy(id); + } + else if (typeof(Company).Equals(entityType)) + { + return ProxyHelper.NewCompanyProxy(id); + } + else if (typeof(Address).Equals(entityType)) + { + return ProxyHelper.NewAddressProxy(id); + } + else + { + throw new ArgumentException("unknown entity for instantiation [" + entityType.FullName + "]"); + } + } + + public object Instantiate() + { + return Instantiate(null); + } + + public bool IsInstance(object obj) + { + try + { + return entityType.IsInstanceOfType(obj); + } + catch (Exception e) + { + throw new HibernateException("could not get handle to entity-name as interface : " + e); + } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityTuplizer.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityTuplizer.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityTuplizer.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,24 @@ +using NHibernate.Mapping; +using NHibernate.Tuple.Entity; + +namespace NHibernate.Test.DynamicEntity.Tuplizer +{ + public class MyEntityTuplizer : PocoEntityTuplizer + { + public MyEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) : base(entityMetamodel, mappedEntity) {} + + protected override Tuple.IInstantiator BuildInstantiator(PersistentClass persistentClass) + { + return new MyEntityInstantiator(persistentClass.MappedClass); + } + + protected override Proxy.IProxyFactory BuildProxyFactory(PersistentClass persistentClass, NHibernate.Properties.IGetter idGetter, NHibernate.Properties.ISetter idSetter) + { + // allows defining a custom proxy factory, which is responsible for + // generating lazy proxies for a given entity. + // + // Here we simply use the default... + return base.BuildProxyFactory(persistentClass, idGetter, idSetter); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,108 @@ +using System.Collections; +using Iesi.Collections.Generic; +using NHibernate.Cfg; +using NUnit.Framework; + +namespace NHibernate.Test.DynamicEntity.Tuplizer +{ + [TestFixture] + public class TuplizerDynamicEntity : TestCase + { + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + protected override IList Mappings + { + get { return new string[] {"DynamicEntity.Tuplizer.Customer.hbm.xml"}; } + } + + protected override void Configure(Configuration configuration) + { + configuration.SetInterceptor(new EntityNameInterceptor()); + } + + [Test] + public void It() + { + // Test saving these dyna-proxies + ISession session = OpenSession(); + session.BeginTransaction(); + Company company = ProxyHelper.NewCompanyProxy(); + company.Name = "acme"; + session.Save(company); + Customer customer = ProxyHelper.NewCustomerProxy(); + customer.Name = "Steve"; + customer.Company = company; + Address address = ProxyHelper.NewAddressProxy(); + address.Street = "somewhere over the rainbow"; + address.City = "lawerence, kansas"; + address.PostalCode = "toto"; + customer.Address = address; + customer.Family = new HashedSet<Person>(); + Person son = ProxyHelper.NewPersonProxy(); + son.Name = "son"; + customer.Family.Add(son); + Person wife = ProxyHelper.NewPersonProxy(); + wife.Name = "wife"; + customer.Family.Add(wife); + session.Save(customer); + session.Transaction.Commit(); + session.Close(); + + Assert.IsNotNull(company.Id, "company id not assigned"); + Assert.IsNotNull(customer.Id, "customer id not assigned"); + Assert.IsNotNull(address.Id, "address id not assigned"); + Assert.IsNotNull(son.Id, "son:Person id not assigned"); + Assert.IsNotNull(wife.Id, "wife:Person id not assigned"); + + // Test loading these dyna-proxies, along with flush processing + session = OpenSession(); + session.BeginTransaction(); + customer = session.Load<Customer>(customer.Id); + Assert.IsFalse(NHibernateUtil.IsInitialized(customer), "should-be-proxy was initialized"); + + customer.Name = "other"; + session.Flush(); + Assert.IsFalse(NHibernateUtil.IsInitialized(customer.Company), "should-be-proxy was initialized"); + + session.Refresh(customer); + Assert.AreEqual("other", customer.Name, "name not updated"); + Assert.AreEqual("acme", customer.Company.Name, "company association not correct"); + + session.Transaction.Commit(); + session.Close(); + + // Test detached entity re-attachment with these dyna-proxies + customer.Name = "Steve"; + session = OpenSession(); + session.BeginTransaction(); + session.Update(customer); + session.Flush(); + session.Refresh(customer); + Assert.AreEqual("Steve", customer.Name, "name not updated"); + session.Transaction.Commit(); + session.Close(); + + // Test querying + session = OpenSession(); + session.BeginTransaction(); + int count = session.CreateQuery("from Customer").List().Count; + Assert.AreEqual(1, count, "querying dynamic entity"); + session.Clear(); + count = session.CreateQuery("from Person").List().Count; + Assert.AreEqual(3, count, "querying dynamic entity"); + session.Transaction.Commit(); + session.Close(); + + // test deleteing + session = OpenSession(); + session.BeginTransaction(); + session.Delete(company); + session.Delete(customer); + session.Transaction.Commit(); + session.Close(); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-21 04:49:58 UTC (rev 3642) @@ -120,6 +120,19 @@ <Compile Include="DriverTest\NullReferenceFixture.cs" /> <Compile Include="DriverTest\OracleClientDriverFixture.cs" /> <Compile Include="DriverTest\OracleDataClientDriverFixture.cs" /> + <Compile Include="DynamicEntity\Address.cs" /> + <Compile Include="DynamicEntity\Company.cs" /> + <Compile Include="DynamicEntity\Customer.cs" /> + <Compile Include="DynamicEntity\DataProxyHandler.cs" /> + <Compile Include="DynamicEntity\Interceptor\InterceptorDynamicEntity.cs" /> + <Compile Include="DynamicEntity\Interceptor\ProxyInterceptor.cs" /> + <Compile Include="DynamicEntity\IProxyMarker.cs" /> + <Compile Include="DynamicEntity\Person.cs" /> + <Compile Include="DynamicEntity\ProxyHelper.cs" /> + <Compile Include="DynamicEntity\Tuplizer\EntityNameInterceptor.cs" /> + <Compile Include="DynamicEntity\Tuplizer\MyEntityInstantiator.cs" /> + <Compile Include="DynamicEntity\Tuplizer\MyEntityTuplizer.cs" /> + <Compile Include="DynamicEntity\Tuplizer\TuplizerDynamicEntity.cs" /> <Compile Include="EngineTest\TypedValueFixture.cs" /> <Compile Include="ExceptionsTest\Group.cs" /> <Compile Include="ExceptionsTest\MSSQLExceptionConverterExample.cs" /> @@ -1345,6 +1358,11 @@ <EmbeddedResource Include="NHSpecificTest\NH1291AnonExample\Mappings.hbm.xml" /> </ItemGroup> <ItemGroup> + <EmbeddedResource Include="DynamicEntity\Interceptor\Customer.hbm.xml" /> + <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="DynamicEntity\Tuplizer\Customer.hbm.xml" /> + </ItemGroup> + <ItemGroup> <Folder Include="Properties\" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-07-21 05:23:51
|
Revision: 3643 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3643&view=rev Author: fabiomaulo Date: 2008-07-21 05:23:55 +0000 (Mon, 21 Jul 2008) Log Message: ----------- Breaking Change : The EntityMode accessible from ISession (NH-1398) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/ISession.cs trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs Modified: trunk/nhibernate/src/NHibernate/ISession.cs =================================================================== --- trunk/nhibernate/src/NHibernate/ISession.cs 2008-07-21 04:49:58 UTC (rev 3642) +++ trunk/nhibernate/src/NHibernate/ISession.cs 2008-07-21 05:23:55 UTC (rev 3643) @@ -70,6 +70,9 @@ /// </remarks> public interface ISession : IDisposable { + /// <summary> The entity mode in effect for this session.</summary> + EntityMode ActiveEntityMode { get;} // NH different implementation: changend name to don't have conflicts + /// <summary> /// Force the <c>ISession</c> to flush. /// </summary> Modified: trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2008-07-21 04:49:58 UTC (rev 3642) +++ trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2008-07-21 05:23:55 UTC (rev 3643) @@ -1921,6 +1921,11 @@ get { return entityMode; } } + public EntityMode ActiveEntityMode + { + get { return entityMode; } + } + public override string FetchProfile { get { return fetchProfile; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-07-21 15:21:29
|
Revision: 3644 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3644&view=rev Author: fabiomaulo Date: 2008-07-21 15:21:34 +0000 (Mon, 21 Jul 2008) Log Message: ----------- - Support for EntityMode.Map (NH-1401) - Support DefaultEntityMode in Settings (NH-1401) - Support Cache for Dynamic entities (NH-1402) BREAKING CHANGE: - see Configuration.cs for method related with Cache Concurrency Strategy Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Cfg/ClassExtractor.cs trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs trunk/nhibernate/src/NHibernate/Cfg/Environment.cs trunk/nhibernate/src/NHibernate/Cfg/MappingsQueueEntry.cs trunk/nhibernate/src/NHibernate/Cfg/SettingsFactory.cs trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassIdBinder.cs trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityMetamodel.cs trunk/nhibernate/src/NHibernate/nhibernate-configuration.xsd trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj trunk/nhibernate/src/NHibernate.Test/TestCase.cs Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/EntityModeTest/ trunk/nhibernate/src/NHibernate.Test/EntityModeTest/Map/ trunk/nhibernate/src/NHibernate.Test/EntityModeTest/Map/Basic/ trunk/nhibernate/src/NHibernate.Test/EntityModeTest/Map/Basic/DynamicClassFixture.cs trunk/nhibernate/src/NHibernate.Test/EntityModeTest/Map/Basic/ProductLine.hbm.xml Modified: trunk/nhibernate/src/NHibernate/Cfg/ClassExtractor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/ClassExtractor.cs 2008-07-21 05:23:55 UTC (rev 3643) +++ trunk/nhibernate/src/NHibernate/Cfg/ClassExtractor.cs 2008-07-21 15:21:34 UTC (rev 3644) @@ -1,4 +1,3 @@ -using System; using System.Collections; using System.Xml; using Iesi.Collections; @@ -23,7 +22,7 @@ public ClassEntry(string extends, string className, string assembly, string @namespace) { _fullExtends = extends == null ? null : TypeNameParser.Parse(extends, @namespace, assembly); - _fullClassName = TypeNameParser.Parse(className, @namespace, assembly); + _fullClassName = className == null ? null : TypeNameParser.Parse(className, @namespace, assembly); } public AssemblyQualifiedTypeName FullExtends Modified: trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2008-07-21 05:23:55 UTC (rev 3643) +++ trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2008-07-21 15:21:34 UTC (rev 3644) @@ -444,25 +444,25 @@ /// </summary> public Mappings CreateMappings(Dialect.Dialect dialect) { - return new Mappings(classes, - collections, - tables, - namedQueries, - namedSqlQueries, - sqlResultSetMappings, - imports, - secondPasses, - propertyReferences, - namingStrategy, - typeDefs, - filterDefinitions, - extendsQueue, - auxiliaryDatabaseObjects, - tableNameBinding, + return new Mappings(classes, + collections, + tables, + namedQueries, + namedSqlQueries, + sqlResultSetMappings, + imports, + secondPasses, + propertyReferences, + namingStrategy, + typeDefs, + filterDefinitions, + extendsQueue, + auxiliaryDatabaseObjects, + tableNameBinding, columnNameBindingPerTable, defaultAssembly, defaultNamespace, - dialect + dialect ); } @@ -1291,19 +1291,9 @@ // Load class-cache foreach (ClassCacheConfiguration ccc in hc.SessionFactory.ClassesCache) { - System.Type clazz; - try - { - clazz = ReflectHelper.ClassForName(ccc.Class); - } - catch (TypeLoadException tle) - { - throw new HibernateConfigException("class-cache Configuration: Could not find class " + ccc.Class, tle); - } - string region = string.IsNullOrEmpty(ccc.Region) ? ccc.Class : ccc.Region; bool includeLazy = (ccc.Include != ClassCacheInclude.NonLazy); - SetCacheConcurrencyStrategy(clazz, CfgXmlHelper.ClassCacheUsageConvertToString(ccc.Usage), region, includeLazy); + SetCacheConcurrencyStrategy(ccc.Class, CfgXmlHelper.ClassCacheUsageConvertToString(ccc.Usage), region, includeLazy); } // Load collection-cache @@ -1317,7 +1307,7 @@ } string region = string.IsNullOrEmpty(ccc.Region) ? role : ccc.Region; - SetCacheConcurrencyStrategy(role, CfgXmlHelper.ClassCacheUsageConvertToString(ccc.Usage), region); + SetCollectionCacheConcurrencyStrategy(role, CfgXmlHelper.ClassCacheUsageConvertToString(ccc.Usage), region); } // Events @@ -1347,6 +1337,20 @@ return this; } + internal RootClass GetRootClassMapping(string clazz) + { + try + { + return (RootClass)GetClassMapping(clazz); + } + catch (InvalidCastException) + { + throw new HibernateConfigException( + "class-cache Configuration: You may only specify a cache for root <class> mappings " + + "(cache was specified for " + clazz + ")"); + } + } + internal RootClass GetRootClassMapping(System.Type clazz) { PersistentClass persistentClass = GetClassMapping(clazz); @@ -1371,36 +1375,40 @@ /// <summary> /// Set up a cache for an entity class /// </summary> - public Configuration SetCacheConcurrencyStrategy(System.Type clazz, string concurrencyStrategy) + public Configuration SetCacheConcurrencyStrategy(String clazz, String concurrencyStrategy) { - SetCacheConcurrencyStrategy(clazz, concurrencyStrategy, clazz.FullName); + SetCacheConcurrencyStrategy(clazz, concurrencyStrategy, clazz); return this; } - internal void SetCacheConcurrencyStrategy(System.Type clazz, string concurrencyStrategy, string region) + public void SetCacheConcurrencyStrategy(String clazz, String concurrencyStrategy, String region) { SetCacheConcurrencyStrategy(clazz, concurrencyStrategy, region, true); } - internal void SetCacheConcurrencyStrategy(System.Type clazz, string concurrencyStrategy, - string region, bool includeLazy) + internal void SetCacheConcurrencyStrategy(String clazz, String concurrencyStrategy, String region, bool includeLazy) { - RootClass rootClass = GetRootClassMapping(clazz); + RootClass rootClass = GetRootClassMapping(StringHelper.GetFullClassname(clazz)); + if (rootClass == null) + { + throw new HibernateConfigException("Cannot cache an unknown entity: " + clazz); + } rootClass.CacheConcurrencyStrategy = concurrencyStrategy; rootClass.CacheRegionName = region; rootClass.SetLazyPropertiesCacheable(includeLazy); } + /// <summary> /// Set up a cache for a collection role /// </summary> - public Configuration SetCacheConcurrencyStrategy(string collectionRole, string concurrencyStrategy) + public Configuration SetCollectionCacheConcurrencyStrategy(string collectionRole, string concurrencyStrategy) { - SetCacheConcurrencyStrategy(collectionRole, concurrencyStrategy, collectionRole); + SetCollectionCacheConcurrencyStrategy(collectionRole, concurrencyStrategy, collectionRole); return this; } - internal void SetCacheConcurrencyStrategy(string collectionRole, string concurrencyStrategy, string region) + internal void SetCollectionCacheConcurrencyStrategy(string collectionRole, string concurrencyStrategy, string region) { NHibernate.Mapping.Collection collection = GetCollectionMapping(collectionRole); collection.CacheConcurrencyStrategy = concurrencyStrategy; @@ -1613,7 +1621,7 @@ else { object[] listeners = - (object[]) System.Array.CreateInstance(eventListeners.GetListenerClassFor(type), listenerClasses.Length); + (object[])System.Array.CreateInstance(eventListeners.GetListenerClassFor(type), listenerClasses.Length); for (int i = 0; i < listeners.Length; i++) { try @@ -1657,88 +1665,88 @@ switch (type) { case ListenerType.Autoflush: - eventListeners.AutoFlushEventListeners = new IAutoFlushEventListener[] { }; + eventListeners.AutoFlushEventListeners = new IAutoFlushEventListener[] { }; break; case ListenerType.Merge: - eventListeners.MergeEventListeners = new IMergeEventListener[] { }; + eventListeners.MergeEventListeners = new IMergeEventListener[] { }; break; case ListenerType.Create: - eventListeners.PersistEventListeners = new IPersistEventListener[] { }; + eventListeners.PersistEventListeners = new IPersistEventListener[] { }; break; case ListenerType.CreateOnFlush: - eventListeners.PersistOnFlushEventListeners = new IPersistEventListener[] { }; + eventListeners.PersistOnFlushEventListeners = new IPersistEventListener[] { }; break; case ListenerType.Delete: - eventListeners.DeleteEventListeners = new IDeleteEventListener[] { }; + eventListeners.DeleteEventListeners = new IDeleteEventListener[] { }; break; case ListenerType.DirtyCheck: - eventListeners.DirtyCheckEventListeners = new IDirtyCheckEventListener[] { }; + eventListeners.DirtyCheckEventListeners = new IDirtyCheckEventListener[] { }; break; case ListenerType.Evict: - eventListeners.EvictEventListeners = new IEvictEventListener[] { }; + eventListeners.EvictEventListeners = new IEvictEventListener[] { }; break; case ListenerType.Flush: - eventListeners.FlushEventListeners = new IFlushEventListener[] { }; + eventListeners.FlushEventListeners = new IFlushEventListener[] { }; break; case ListenerType.FlushEntity: - eventListeners.FlushEntityEventListeners = new IFlushEntityEventListener[] { }; + eventListeners.FlushEntityEventListeners = new IFlushEntityEventListener[] { }; break; case ListenerType.Load: - eventListeners.LoadEventListeners = new ILoadEventListener[] { }; + eventListeners.LoadEventListeners = new ILoadEventListener[] { }; break; case ListenerType.LoadCollection: - eventListeners.InitializeCollectionEventListeners = new IInitializeCollectionEventListener[] { }; + eventListeners.InitializeCollectionEventListeners = new IInitializeCollectionEventListener[] { }; break; case ListenerType.Lock: - eventListeners.LockEventListeners = new ILockEventListener[] { }; + eventListeners.LockEventListeners = new ILockEventListener[] { }; break; case ListenerType.Refresh: - eventListeners.RefreshEventListeners = new IRefreshEventListener[] { }; + eventListeners.RefreshEventListeners = new IRefreshEventListener[] { }; break; case ListenerType.Replicate: - eventListeners.ReplicateEventListeners = new IReplicateEventListener[] { }; + eventListeners.ReplicateEventListeners = new IReplicateEventListener[] { }; break; case ListenerType.SaveUpdate: - eventListeners.SaveOrUpdateEventListeners = new ISaveOrUpdateEventListener[] { }; + eventListeners.SaveOrUpdateEventListeners = new ISaveOrUpdateEventListener[] { }; break; case ListenerType.Save: - eventListeners.SaveEventListeners = new ISaveOrUpdateEventListener[] { }; + eventListeners.SaveEventListeners = new ISaveOrUpdateEventListener[] { }; break; case ListenerType.PreUpdate: - eventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[] { }; + eventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[] { }; break; case ListenerType.Update: - eventListeners.UpdateEventListeners = new ISaveOrUpdateEventListener[] { }; + eventListeners.UpdateEventListeners = new ISaveOrUpdateEventListener[] { }; break; case ListenerType.PreLoad: - eventListeners.PreLoadEventListeners = new IPreLoadEventListener[] { }; + eventListeners.PreLoadEventListeners = new IPreLoadEventListener[] { }; break; case ListenerType.PreDelete: - eventListeners.PreDeleteEventListeners = new IPreDeleteEventListener[] { }; + eventListeners.PreDeleteEventListeners = new IPreDeleteEventListener[] { }; break; case ListenerType.PreInsert: - eventListeners.PreInsertEventListeners = new IPreInsertEventListener[] { }; + eventListeners.PreInsertEventListeners = new IPreInsertEventListener[] { }; break; case ListenerType.PostLoad: - eventListeners.PostLoadEventListeners = new IPostLoadEventListener[] { }; + eventListeners.PostLoadEventListeners = new IPostLoadEventListener[] { }; break; case ListenerType.PostInsert: - eventListeners.PostInsertEventListeners = new IPostInsertEventListener[] { }; + eventListeners.PostInsertEventListeners = new IPostInsertEventListener[] { }; break; case ListenerType.PostUpdate: - eventListeners.PostUpdateEventListeners = new IPostUpdateEventListener[] { }; + eventListeners.PostUpdateEventListeners = new IPostUpdateEventListener[] { }; break; case ListenerType.PostDelete: - eventListeners.PostDeleteEventListeners = new IPostDeleteEventListener[] { }; + eventListeners.PostDeleteEventListeners = new IPostDeleteEventListener[] { }; break; case ListenerType.PostCommitUpdate: - eventListeners.PostCommitUpdateEventListeners = new IPostUpdateEventListener[] { }; + eventListeners.PostCommitUpdateEventListeners = new IPostUpdateEventListener[] { }; break; case ListenerType.PostCommitInsert: - eventListeners.PostCommitInsertEventListeners = new IPostInsertEventListener[] { }; + eventListeners.PostCommitInsertEventListeners = new IPostInsertEventListener[] { }; break; case ListenerType.PostCommitDelete: - eventListeners.PostCommitDeleteEventListeners = new IPostDeleteEventListener[] { }; + eventListeners.PostCommitDeleteEventListeners = new IPostDeleteEventListener[] { }; break; default: log.Warn("Unrecognized listener type [" + type + "]"); @@ -1760,88 +1768,88 @@ switch (type) { case ListenerType.Autoflush: - eventListeners.AutoFlushEventListeners = (IAutoFlushEventListener[]) listeners; + eventListeners.AutoFlushEventListeners = (IAutoFlushEventListener[])listeners; break; case ListenerType.Merge: - eventListeners.MergeEventListeners = (IMergeEventListener[])listeners; + eventListeners.MergeEventListeners = (IMergeEventListener[])listeners; break; case ListenerType.Create: - eventListeners.PersistEventListeners = (IPersistEventListener[])listeners; + eventListeners.PersistEventListeners = (IPersistEventListener[])listeners; break; case ListenerType.CreateOnFlush: - eventListeners.PersistOnFlushEventListeners = (IPersistEventListener[])listeners; + eventListeners.PersistOnFlushEventListeners = (IPersistEventListener[])listeners; break; case ListenerType.Delete: - eventListeners.DeleteEventListeners = (IDeleteEventListener[])listeners; + eventListeners.DeleteEventListeners = (IDeleteEventListener[])listeners; break; case ListenerType.DirtyCheck: - eventListeners.DirtyCheckEventListeners = (IDirtyCheckEventListener[])listeners; + eventListeners.DirtyCheckEventListeners = (IDirtyCheckEventListener[])listeners; break; case ListenerType.Evict: - eventListeners.EvictEventListeners = (IEvictEventListener[])listeners; + eventListeners.EvictEventListeners = (IEvictEventListener[])listeners; break; case ListenerType.Flush: - eventListeners.FlushEventListeners = (IFlushEventListener[])listeners; + eventListeners.FlushEventListeners = (IFlushEventListener[])listeners; break; case ListenerType.FlushEntity: - eventListeners.FlushEntityEventListeners = (IFlushEntityEventListener[])listeners; + eventListeners.FlushEntityEventListeners = (IFlushEntityEventListener[])listeners; break; case ListenerType.Load: - eventListeners.LoadEventListeners = (ILoadEventListener[])listeners; + eventListeners.LoadEventListeners = (ILoadEventListener[])listeners; break; case ListenerType.LoadCollection: - eventListeners.InitializeCollectionEventListeners = (IInitializeCollectionEventListener[])listeners; + eventListeners.InitializeCollectionEventListeners = (IInitializeCollectionEventListener[])listeners; break; case ListenerType.Lock: - eventListeners.LockEventListeners = (ILockEventListener[])listeners; + eventListeners.LockEventListeners = (ILockEventListener[])listeners; break; case ListenerType.Refresh: - eventListeners.RefreshEventListeners = (IRefreshEventListener[])listeners; + eventListeners.RefreshEventListeners = (IRefreshEventListener[])listeners; break; case ListenerType.Replicate: - eventListeners.ReplicateEventListeners = (IReplicateEventListener[])listeners; + eventListeners.ReplicateEventListeners = (IReplicateEventListener[])listeners; break; case ListenerType.SaveUpdate: - eventListeners.SaveOrUpdateEventListeners = (ISaveOrUpdateEventListener[])listeners; + eventListeners.SaveOrUpdateEventListeners = (ISaveOrUpdateEventListener[])listeners; break; case ListenerType.Save: - eventListeners.SaveEventListeners = (ISaveOrUpdateEventListener[])listeners; + eventListeners.SaveEventListeners = (ISaveOrUpdateEventListener[])listeners; break; case ListenerType.PreUpdate: - eventListeners.PreUpdateEventListeners = (IPreUpdateEventListener[])listeners; + eventListeners.PreUpdateEventListeners = (IPreUpdateEventListener[])listeners; break; case ListenerType.Update: - eventListeners.UpdateEventListeners = (ISaveOrUpdateEventListener[])listeners; + eventListeners.UpdateEventListeners = (ISaveOrUpdateEventListener[])listeners; break; case ListenerType.PreLoad: - eventListeners.PreLoadEventListeners = (IPreLoadEventListener[])listeners; + eventListeners.PreLoadEventListeners = (IPreLoadEventListener[])listeners; break; case ListenerType.PreDelete: - eventListeners.PreDeleteEventListeners = (IPreDeleteEventListener[])listeners; + eventListeners.PreDeleteEventListeners = (IPreDeleteEventListener[])listeners; break; case ListenerType.PreInsert: - eventListeners.PreInsertEventListeners = (IPreInsertEventListener[])listeners; + eventListeners.PreInsertEventListeners = (IPreInsertEventListener[])listeners; break; case ListenerType.PostLoad: - eventListeners.PostLoadEventListeners = (IPostLoadEventListener[])listeners; + eventListeners.PostLoadEventListeners = (IPostLoadEventListener[])listeners; break; case ListenerType.PostInsert: - eventListeners.PostInsertEventListeners = (IPostInsertEventListener[])listeners; + eventListeners.PostInsertEventListeners = (IPostInsertEventListener[])listeners; break; case ListenerType.PostUpdate: - eventListeners.PostUpdateEventListeners = (IPostUpdateEventListener[])listeners; + eventListeners.PostUpdateEventListeners = (IPostUpdateEventListener[])listeners; break; case ListenerType.PostDelete: - eventListeners.PostDeleteEventListeners = (IPostDeleteEventListener[])listeners; + eventListeners.PostDeleteEventListeners = (IPostDeleteEventListener[])listeners; break; case ListenerType.PostCommitUpdate: - eventListeners.PostCommitUpdateEventListeners = (IPostUpdateEventListener[])listeners; + eventListeners.PostCommitUpdateEventListeners = (IPostUpdateEventListener[])listeners; break; case ListenerType.PostCommitInsert: - eventListeners.PostCommitInsertEventListeners = (IPostInsertEventListener[])listeners; + eventListeners.PostCommitInsertEventListeners = (IPostInsertEventListener[])listeners; break; case ListenerType.PostCommitDelete: - eventListeners.PostCommitDeleteEventListeners = (IPostDeleteEventListener[])listeners; + eventListeners.PostCommitDeleteEventListeners = (IPostDeleteEventListener[])listeners; break; default: log.Warn("Unrecognized listener type [" + type + "]"); @@ -1865,7 +1873,7 @@ { if (table.IsPhysicalTable) { - ITableMetadata tableInfo = databaseMetadata.GetTableMetadata(table.Name, table.Schema ?? defaultSchema, + ITableMetadata tableInfo = databaseMetadata.GetTableMetadata(table.Name, table.Schema ?? defaultSchema, table.Catalog ?? defaultCatalog, table.IsQuoted); if (tableInfo == null) { @@ -1897,7 +1905,7 @@ if (fk.HasPhysicalConstraint) { bool create = tableInfo == null || ( - tableInfo.GetForeignKeyMetadata(fk.Name) == null && + tableInfo.GetForeignKeyMetadata(fk.Name) == null && (!(dialect is MySQLDialect) || tableInfo.GetIndexMetadata(fk.Name) == null) ); if (create) @@ -1939,7 +1947,7 @@ if (!pc.IsInherited) { IPersistentIdentifierGenerator ig = - pc.Identifier.CreateIdentifierGenerator(dialect, defaultCatalog, defaultSchema, (RootClass) pc) as + pc.Identifier.CreateIdentifierGenerator(dialect, defaultCatalog, defaultSchema, (RootClass)pc) as IPersistentIdentifierGenerator; if (ig != null) @@ -1952,8 +1960,8 @@ if (collection.IsIdentified) { IPersistentIdentifierGenerator ig = - ((IdentifierCollection) collection).Identifier.CreateIdentifierGenerator(dialect, defaultCatalog, defaultSchema, - null) as IPersistentIdentifierGenerator; + ((IdentifierCollection)collection).Identifier.CreateIdentifierGenerator(dialect, defaultCatalog, defaultSchema, + null) as IPersistentIdentifierGenerator; if (ig != null) generators[ig.GeneratorKey()] = ig; Modified: trunk/nhibernate/src/NHibernate/Cfg/Environment.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/Environment.cs 2008-07-21 05:23:55 UTC (rev 3643) +++ trunk/nhibernate/src/NHibernate/Cfg/Environment.cs 2008-07-21 15:21:34 UTC (rev 3644) @@ -49,8 +49,8 @@ { Assembly thisAssembly = Assembly.GetExecutingAssembly(); AssemblyInformationalVersionAttribute[] attrs = (AssemblyInformationalVersionAttribute[]) - thisAssembly.GetCustomAttributes( - typeof(AssemblyInformationalVersionAttribute), false); + thisAssembly.GetCustomAttributes( + typeof(AssemblyInformationalVersionAttribute), false); if (attrs != null && attrs.Length > 0) { @@ -85,6 +85,9 @@ /// <summary> A default database catalog name to use for unqualified tablenames</summary> public const string DefaultCatalog = "default_catalog"; + /// <summary>The EntityMode in which set the Session opened from the SessionFactory.</summary> + public const string DefaultEntityMode = "default_entity_mode"; + public const string ShowSql = "show_sql"; public const string MaxFetchDepth = "max_fetch_depth"; public const string CurrentSessionContextClass = "current_session_context_class"; @@ -192,7 +195,7 @@ if (config == null) { - log.Info(string.Format("{0} section not found in application configuration file",CfgXmlHelper.CfgSectionName)); + log.Info(string.Format("{0} section not found in application configuration file", CfgXmlHelper.CfgSectionName)); return; } @@ -246,7 +249,7 @@ /// </remarks> public static IDictionary<string, string> Properties { - get { return new Dictionary<string,string>(GlobalProperties); } + get { return new Dictionary<string, string>(GlobalProperties); } } [Obsolete] @@ -293,7 +296,7 @@ { string defaultBytecodeProvider = "lcg"; string provider = PropertiesHelper.GetString(PropertyBytecodeProvider, properties, - defaultBytecodeProvider); + defaultBytecodeProvider); log.Info("Bytecode provider name : " + provider); return BuildBytecodeProvider(provider); } Modified: trunk/nhibernate/src/NHibernate/Cfg/MappingsQueueEntry.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/MappingsQueueEntry.cs 2008-07-21 05:23:55 UTC (rev 3643) +++ trunk/nhibernate/src/NHibernate/Cfg/MappingsQueueEntry.cs 2008-07-21 15:21:34 UTC (rev 3644) @@ -33,7 +33,8 @@ foreach (ClassExtractor.ClassEntry ce in classEntries) { - result.Add(ce.FullClassName); + if (ce.FullClassName != null) + result.Add(ce.FullClassName); } return result; @@ -69,4 +70,4 @@ get { return containedClassNames; } } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Cfg/SettingsFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/SettingsFactory.cs 2008-07-21 05:23:55 UTC (rev 3643) +++ trunk/nhibernate/src/NHibernate/Cfg/SettingsFactory.cs 2008-07-21 15:21:34 UTC (rev 3644) @@ -99,12 +99,12 @@ log.Info("Default schema: " + defaultSchema); if (defaultCatalog != null) log.Info("Default catalog: " + defaultCatalog); - settings.DefaultSchemaName=defaultSchema; - settings.DefaultCatalogName=defaultCatalog; + settings.DefaultSchemaName = defaultSchema; + settings.DefaultCatalogName = defaultCatalog; int batchFetchSize = PropertiesHelper.GetInt32(Environment.DefaultBatchFetchSize, properties, 1); log.Info("Default batch fetch size: " + batchFetchSize); - settings.DefaultBatchFetchSize= batchFetchSize; + settings.DefaultBatchFetchSize = batchFetchSize; //Statistics and logging: @@ -126,11 +126,11 @@ settings.QueryTranslatorFactory = CreateQueryTranslatorFactory(properties); - IDictionary<string, string> querySubstitutions = - PropertiesHelper.ToDictionary(Environment.QuerySubstitutions, " ,=;:\n\t\r\f", properties); + IDictionary<string, string> querySubstitutions = PropertiesHelper.ToDictionary(Environment.QuerySubstitutions, + " ,=;:\n\t\r\f", properties); if (log.IsInfoEnabled) { - log.Info("Query language substitutions: " + CollectionPrinter.ToString((IDictionary)querySubstitutions)); + log.Info("Query language substitutions: " + CollectionPrinter.ToString((IDictionary) querySubstitutions)); } string autoSchemaExport = PropertiesHelper.GetString(Environment.Hbm2ddlAuto, properties, null); @@ -169,13 +169,13 @@ if (useQueryCache) { - string queryCacheFactoryClassName = - PropertiesHelper.GetString(Environment.QueryCacheFactory, properties, typeof(StandardQueryCacheFactory).FullName); + string queryCacheFactoryClassName = PropertiesHelper.GetString(Environment.QueryCacheFactory, properties, + typeof (StandardQueryCacheFactory).FullName); log.Info("query cache factory: " + queryCacheFactoryClassName); try { - settings.QueryCacheFactory = (IQueryCacheFactory) Activator.CreateInstance( - ReflectHelper.ClassForName(queryCacheFactoryClassName)); + settings.QueryCacheFactory = + (IQueryCacheFactory) Activator.CreateInstance(ReflectHelper.ClassForName(queryCacheFactoryClassName)); } catch (Exception cnfe) { @@ -200,18 +200,23 @@ { try { - isolation = (IsolationLevel) Enum.Parse(typeof(IsolationLevel), isolationString); + isolation = (IsolationLevel) Enum.Parse(typeof (IsolationLevel), isolationString); log.Info("Using Isolation Level: " + isolation); } catch (ArgumentException ae) { log.Error("error configuring IsolationLevel " + isolationString, ae); throw new HibernateException( - "The isolation level of " + isolationString + " is not a valid IsolationLevel. Please " + - "use one of the Member Names from the IsolationLevel.", ae); + "The isolation level of " + isolationString + " is not a valid IsolationLevel. Please " + + "use one of the Member Names from the IsolationLevel.", ae); } } + EntityMode defaultEntityMode = + EntityModeHelper.Parse(PropertiesHelper.GetString(Environment.DefaultEntityMode, properties, "poco")); + log.Info("Default entity-mode: " + defaultEntityMode); + settings.DefaultEntityMode = defaultEntityMode; + bool namedQueryChecking = PropertiesHelper.GetBoolean(Environment.QueryStartupChecking, properties, true); log.Info("Named query checking : " + EnabledDisabled(namedQueryChecking)); settings.IsNamedQueryStartupCheckingEnabled = namedQueryChecking; Modified: trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs 2008-07-21 05:23:55 UTC (rev 3643) +++ trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs 2008-07-21 15:21:34 UTC (rev 3644) @@ -147,9 +147,11 @@ // IMPORT // For entities, the EntityName is the key to find a persister // NH Different behavior: we are using the association between EntityName and its more certain implementation (AssemblyQualifiedName) - mappings.AddImport(model.MappedClass.AssemblyQualifiedName, model.EntityName); + // Dynamic entities have no class, reverts to EntityName. -AK + string qualifiedName = model.MappedClass == null ? model.EntityName : model.MappedClass.AssemblyQualifiedName; + mappings.AddImport(qualifiedName, model.EntityName); if (mappings.IsAutoImport && model.EntityName.IndexOf('.') > 0) - mappings.AddImport(model.MappedClass.AssemblyQualifiedName, StringHelper.Unqualify(model.EntityName)); + mappings.AddImport(qualifiedName, StringHelper.Unqualify(model.EntityName)); // BATCH SIZE XmlAttribute batchNode = node.Attributes["batch-size"]; @@ -1175,20 +1177,14 @@ return type; } - private static string GetEntityName(XmlNode elem, Mappings model) + protected static string GetEntityName(XmlNode elem, Mappings model) { string entityName = XmlHelper.GetAttributeValue(elem, "entity-name"); - if (entityName == null) - { - XmlAttribute att = elem.Attributes["class"]; + string className = XmlHelper.GetAttributeValue(elem, "class"); + entityName = entityName + ?? (className == null ? null : StringHelper.GetFullClassname(FullClassName(className, model))); - return att == null ? null : GetClassName(att.Value, model); - } - else - { - return entityName; - } - + return entityName; } protected XmlNodeList SelectNodes(XmlNode node, string xpath) Modified: trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassIdBinder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassIdBinder.cs 2008-07-21 05:23:55 UTC (rev 3643) +++ trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassIdBinder.cs 2008-07-21 15:21:34 UTC (rev 3644) @@ -1,10 +1,7 @@ -using System.Collections; using System.Collections.Generic; using System.Xml; - using NHibernate.Cfg.MappingSchema; using NHibernate.Mapping; -using NHibernate.Type; using NHibernate.Util; namespace NHibernate.Cfg.XmlHbmBinding @@ -29,7 +26,7 @@ AddColumns(idSchema, id); CreateIdentifierProperty(idSchema, rootClass, id); - VerifiyIdTypeIsValid(id, rootClass.MappedClass.Name); + VerifiyIdTypeIsValid(id, rootClass.EntityName); BindGenerator(idSchema, id); id.Table.SetIdentifierValue(id); BindUnsavedValue(idSchema, id); @@ -61,9 +58,10 @@ if (idSchema.name != null) { string access = idSchema.access ?? mappings.DefaultAccess; - id.SetTypeUsingReflection(rootClass.MappedClass.AssemblyQualifiedName, idSchema.name, access); + id.SetTypeUsingReflection(rootClass.MappedClass == null ? null : rootClass.MappedClass.AssemblyQualifiedName, + idSchema.name, access); - Mapping.Property property = new Mapping.Property(id); + Property property = new Property(id); property.Name = idSchema.name; if (property.Value.Type == null) @@ -230,4 +228,4 @@ return column; } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs 2008-07-21 05:23:55 UTC (rev 3643) +++ trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs 2008-07-21 15:21:34 UTC (rev 3644) @@ -451,8 +451,7 @@ private void BindOneToMany(XmlNode node, OneToMany model) { - model.ReferencedEntityName = ClassForNameChecked(node.Attributes["class"].Value, mappings, - "associated class not found: {0}").FullName; + model.ReferencedEntityName = GetEntityName(node, mappings); string notFound = XmlHelper.GetAttributeValue(node, "not-found"); model.IsIgnoreNotFound = "ignore".Equals(notFound); Modified: trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityMetamodel.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityMetamodel.cs 2008-07-21 05:23:55 UTC (rev 3643) +++ trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityMetamodel.cs 2008-07-21 15:21:34 UTC (rev 3644) @@ -91,14 +91,15 @@ entityType = TypeFactory.ManyToOne(name); type = persistentClass.MappedClass; rootType = persistentClass.RootClazz.MappedClass; - rootTypeAssemblyQualifiedName = rootType.AssemblyQualifiedName; + rootTypeAssemblyQualifiedName = rootType == null ? null : rootType.AssemblyQualifiedName; - identifierProperty = - PropertyFactory.BuildIdentifierProperty(persistentClass, sessionFactory.GetIdentifierGenerator(rootName)); + identifierProperty = PropertyFactory.BuildIdentifierProperty(persistentClass, + sessionFactory.GetIdentifierGenerator(rootName)); versioned = persistentClass.IsVersioned; - bool lazyAvailable = persistentClass.HasPocoRepresentation && FieldInterceptionHelper.IsInstrumented(persistentClass.MappedClass); + bool lazyAvailable = persistentClass.HasPocoRepresentation + && FieldInterceptionHelper.IsInstrumented(persistentClass.MappedClass); bool hasLazy = false; propertySpan = persistentClass.PropertyClosureSpan; @@ -155,6 +156,7 @@ } #region temporary + bool lazyProperty = prop.IsLazy && lazyAvailable; if (lazyProperty) hasLazy = true; @@ -169,11 +171,13 @@ updateInclusions[i] = DetermineUpdateValueGenerationType(prop, properties[i]); propertyVersionability[i] = properties[i].IsVersionable; nonlazyPropertyUpdateability[i] = properties[i].IsUpdateable && !lazyProperty; - propertyCheckability[i] = propertyUpdateability[i] || - (propertyTypes[i].IsAssociationType && - ((IAssociationType) propertyTypes[i]).IsAlwaysDirtyChecked); + propertyCheckability[i] = propertyUpdateability[i] + || + (propertyTypes[i].IsAssociationType + && ((IAssociationType) propertyTypes[i]).IsAlwaysDirtyChecked); cascadeStyles[i] = properties[i].CascadeStyle; + #endregion if (properties[i].IsLazy) @@ -224,24 +228,23 @@ hasLazyProperties = hasLazy; if (hasLazyProperties) log.Info("lazy property fetching available for: " + name); - lazy = persistentClass.IsLazy && - (!persistentClass.HasPocoRepresentation || !ReflectHelper.IsFinalClass(persistentClass.ProxyInterface)); + lazy = persistentClass.IsLazy + && (!persistentClass.HasPocoRepresentation || !ReflectHelper.IsFinalClass(persistentClass.ProxyInterface)); mutable = persistentClass.IsMutable; if (!persistentClass.IsAbstract.HasValue) { // legacy behavior (with no abstract attribute specified) - isAbstract = persistentClass.HasPocoRepresentation && - ReflectHelper.IsAbstractClass(persistentClass.MappedClass); + isAbstract = persistentClass.HasPocoRepresentation && ReflectHelper.IsAbstractClass(persistentClass.MappedClass); } else { isAbstract = persistentClass.IsAbstract.Value; - if (!isAbstract && persistentClass.HasPocoRepresentation && - ReflectHelper.IsAbstractClass(persistentClass.MappedClass)) + if (!isAbstract && persistentClass.HasPocoRepresentation + && ReflectHelper.IsAbstractClass(persistentClass.MappedClass)) { - log.Warn("entity [" + type.FullName + - "] is abstract-class/interface explicitly mapped as non-abstract; be sure to supply entity-names"); + log.Warn("entity [" + type.FullName + + "] is abstract-class/interface explicitly mapped as non-abstract; be sure to supply entity-names"); } } selectBeforeUpdate = persistentClass.SelectBeforeUpdate; @@ -252,9 +255,7 @@ explicitPolymorphism = persistentClass.IsExplicitPolymorphism; inherited = persistentClass.IsInherited; superclass = inherited ? persistentClass.Superclass.EntityName : null; - superclassType = inherited ? - persistentClass.Superclass.MappedClass : - null; + superclassType = inherited ? persistentClass.Superclass.MappedClass : null; hasSubclasses = persistentClass.HasSubclasses; optimisticLockMode = persistentClass.OptimisticLockMode; @@ -675,4 +676,4 @@ get { return naturalIdPropertyNumbers; } } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/nhibernate-configuration.xsd =================================================================== --- trunk/nhibernate/src/NHibernate/nhibernate-configuration.xsd 2008-07-21 05:23:55 UTC (rev 3643) +++ trunk/nhibernate/src/NHibernate/nhibernate-configuration.xsd 2008-07-21 15:21:34 UTC (rev 3644) @@ -97,6 +97,7 @@ <xs:enumeration value="proxyfactory.factory_class" /> <xs:enumeration value="adonet.factory_class" /> <xs:enumeration value="default_batch_fetch_size" /> + <xs:enumeration value="default_entity_mode" /> </xs:restriction> </xs:simpleType> </xs:attribute> Added: trunk/nhibernate/src/NHibernate.Test/EntityModeTest/Map/Basic/DynamicClassFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/EntityModeTest/Map/Basic/DynamicClassFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/EntityModeTest/Map/Basic/DynamicClassFixture.cs 2008-07-21 15:21:34 UTC (rev 3644) @@ -0,0 +1,98 @@ +using System.Collections; +using System.Collections.Generic; +using NHibernate.Cfg; +using NHibernate.Engine; +using NUnit.Framework; + +namespace NHibernate.Test.EntityModeTest.Map.Basic +{ + [TestFixture] + public class DynamicClassFixture : TestCase + { + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + protected override IList Mappings + { + get { return new string[] {"EntityModeTest.Map.Basic.ProductLine.hbm.xml"}; } + } + + protected override void Configure(Configuration configuration) + { + configuration.SetProperty(Environment.DefaultEntityMode, EntityModeHelper.ToString(EntityMode.Map)); + } + + [Test] + public void TestLazyDynamicClass() + { + ITransaction t; + using(ISession s = OpenSession()) + { + ISessionImplementor si = (ISessionImplementor) s; + Assert.IsTrue(si.EntityMode == EntityMode.Map, "Incorrectly handled default_entity_mode"); + ISession other = s.GetSession(EntityMode.Poco); + other.Close(); + Assert.IsFalse(other.IsOpen); + } + IDictionary cars; + IList models; + using (ISession s = OpenSession()) + { + t = s.BeginTransaction(); + + cars = new Hashtable(); + cars["Description"] = "Cars"; + + IDictionary monaro = new Hashtable(); + monaro["ProductLine"] = cars; + monaro["Name"] = "Monaro"; + monaro["Description"] = "Holden Monaro"; + + IDictionary hsv = new Hashtable(); + hsv["ProductLine"] = cars; + hsv["Name"] = "hsv"; + hsv["Description"] = "Holden hsv"; + + models = new List<IDictionary>(); + models.Add(monaro); + models.Add(hsv); + + cars["Models"] = models; + + s.Save("ProductLine", cars); + t.Commit(); + } + + using (ISession s = OpenSession()) + { + t = s.BeginTransaction(); + cars = (IDictionary) s.CreateQuery("from ProductLine pl order by pl.Description").UniqueResult(); + models = (IList) cars["Models"]; + Assert.IsFalse(NHibernateUtil.IsInitialized(models)); + Assert.AreEqual(2, models.Count); + Assert.IsTrue(NHibernateUtil.IsInitialized(models)); + s.Clear(); + IList list = s.CreateQuery("from Model m").List(); + foreach (IDictionary ht in list) + { + Assert.IsFalse(NHibernateUtil.IsInitialized(ht["ProductLine"])); + } + IDictionary model = (IDictionary) list[0]; + Assert.IsTrue(((IList) ((IDictionary) model["ProductLine"])["Models"]).Contains(model)); + s.Clear(); + + t.Commit(); + } + + using (ISession s = OpenSession()) + { + t = s.BeginTransaction(); + cars = (IDictionary) s.CreateQuery("from ProductLine pl order by pl.Description").UniqueResult(); + s.Delete(cars); + t.Commit(); + } + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/EntityModeTest/Map/Basic/DynamicClassFixture.cs ___________________________________________________________________ Added: svn:mergeinfo + Added: trunk/nhibernate/src/NHibernate.Test/EntityModeTest/Map/Basic/ProductLine.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/EntityModeTest/Map/Basic/ProductLine.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/EntityModeTest/Map/Basic/ProductLine.hbm.xml 2008-07-21 15:21:34 UTC (rev 3644) @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8" ?> + +<!-- + This mapping demonstrates "dynamic" entities. +--> + +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> + <class entity-name="ProductLine"> + <id name="Id" column="productId" type="System.Int32"> + <generator class="native"/> + </id> + <property name="Description" not-null="true" length="200" type="string"/> + + <bag name="Models" cascade="all" inverse="true"> + <key column="productId"/> + <one-to-many class="Model"/> + </bag> + + </class> + <class entity-name="Model"> + <id name="Id" column="modelId" type="System.Int32"> + <generator class="native"/> + </id> + + <property name="Name" not-null="true" length="25" type="string"/> + <property name="Description" not-null="true" length="200" type="string"/> + <many-to-one name="ProductLine" column="productId" not-null="true" class="ProductLine"/> + + </class> + + +</hibernate-mapping> Property changes on: trunk/nhibernate/src/NHibernate.Test/EntityModeTest/Map/Basic/ProductLine.hbm.xml ___________________________________________________________________ Added: svn:mergeinfo + Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-21 05:23:55 UTC (rev 3643) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-21 15:21:34 UTC (rev 3644) @@ -134,6 +134,7 @@ <Compile Include="DynamicEntity\Tuplizer\MyEntityTuplizer.cs" /> <Compile Include="DynamicEntity\Tuplizer\TuplizerDynamicEntity.cs" /> <Compile Include="EngineTest\TypedValueFixture.cs" /> + <Compile Include="EntityModeTest\Map\Basic\DynamicClassFixture.cs" /> <Compile Include="ExceptionsTest\Group.cs" /> <Compile Include="ExceptionsTest\MSSQLExceptionConverterExample.cs" /> <Compile Include="ExceptionsTest\PropertyAccessExceptionFixture.cs" /> @@ -1360,6 +1361,7 @@ <ItemGroup> <EmbeddedResource Include="DynamicEntity\Interceptor\Customer.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="EntityModeTest\Map\Basic\ProductLine.hbm.xml" /> <EmbeddedResource Include="DynamicEntity\Tuplizer\Customer.hbm.xml" /> </ItemGroup> <ItemGroup> Modified: trunk/nhibernate/src/NHibernate.Test/TestCase.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/TestCase.cs 2008-07-21 05:23:55 UTC (rev 3643) +++ trunk/nhibernate/src/NHibernate.Test/TestCase.cs 2008-07-21 15:21:34 UTC (rev 3644) @@ -253,7 +253,7 @@ protected ISessionFactoryImplementor Sfi { - get { return (ISessionFactoryImplementor) sessions; } + get { return sessions; } } protected virtual ISession OpenSession() @@ -278,11 +278,11 @@ foreach (PersistentClass clazz in configuration.ClassMappings) { bool hasLob = false; - foreach (Mapping.Property prop in clazz.PropertyClosureIterator) + foreach (Property prop in clazz.PropertyClosureIterator) { if (prop.Value.IsSimpleValue) { - IType type = ((SimpleValue) prop.Value).Type; + IType type = ((SimpleValue)prop.Value).Type; if (type == NHibernateUtil.BinaryBlob) { hasLob = true; @@ -291,13 +291,13 @@ } if (!hasLob && !clazz.IsInherited) { - configuration.SetCacheConcurrencyStrategy(clazz.MappedClass, CacheConcurrencyStrategy); + configuration.SetCacheConcurrencyStrategy(clazz.EntityName, CacheConcurrencyStrategy); } } foreach (Mapping.Collection coll in configuration.CollectionMappings) { - configuration.SetCacheConcurrencyStrategy(coll.Role, CacheConcurrencyStrategy); + configuration.SetCollectionCacheConcurrencyStrategy(coll.Role, CacheConcurrencyStrategy); } } @@ -320,4 +320,4 @@ #endregion } -} \ No newline at end of file +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-07-22 18:55:10
|
Revision: 3645 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3645&view=rev Author: fabiomaulo Date: 2008-07-22 18:55:18 +0000 (Tue, 22 Jul 2008) Log Message: ----------- Fix NH-1253 (thanks to Jakob Andersen) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/IMultiQuery.cs trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs trunk/nhibernate/src/NHibernate/Util/StringHelper.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-3.5.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1253/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1253/Car.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1253/Mappings.hbm.xml Modified: trunk/nhibernate/src/NHibernate/IMultiQuery.cs =================================================================== --- trunk/nhibernate/src/NHibernate/IMultiQuery.cs 2008-07-21 15:21:34 UTC (rev 3644) +++ trunk/nhibernate/src/NHibernate/IMultiQuery.cs 2008-07-22 18:55:18 UTC (rev 3645) @@ -61,9 +61,9 @@ IMultiQuery SetCacheable(bool cacheable); /// Set the name of the cache region. - /// <param name="cacheRegion">The name of a query cache region, or <see langword="null" /> + /// <param name="region">The name of a query cache region, or <see langword="null" /> /// for the default query cache</param> - IMultiQuery SetCacheRegion(string cacheRegion); + IMultiQuery SetCacheRegion(string region); /// Should the query force a refresh of the specified query cache region? /// This is particularly useful in cases where underlying data may have been @@ -261,7 +261,7 @@ /// <summary> /// Override the current session flush mode, just for this query. /// </summary> - IMultiQuery SetFlushMode(FlushMode flushMode); + IMultiQuery SetFlushMode(FlushMode mode); /// <summary> /// Set a strategy for handling the query results. This can be used to change Modified: trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs 2008-07-21 15:21:34 UTC (rev 3644) +++ trunk/nhibernate/src/NHibernate/Impl/AbstractQueryImpl.cs 2008-07-22 18:55:18 UTC (rev 3645) @@ -267,12 +267,12 @@ if (i > 0) list.Append(StringHelper.CommaSpace); - string alias = (isJpaPositionalParam ? 'x' + name : name) + i++ + StringHelper.Underscore; + string alias = (isJpaPositionalParam ? 'x' + name : name + StringHelper.Underscore) + i++ + StringHelper.Underscore; namedParamsCopy[alias] = new TypedValue(type, obj, session.EntityMode); list.Append(ParserHelper.HqlVariablePrefix).Append(alias); } string paramPrefix = isJpaPositionalParam ? StringHelper.SqlParameter : ParserHelper.HqlVariablePrefix; - return StringHelper.Replace(query, paramPrefix + name, list.ToString()); + return StringHelper.Replace(query, paramPrefix + name, list.ToString(), true); } #region Parameters Modified: trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs 2008-07-21 15:21:34 UTC (rev 3644) +++ trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs 2008-07-22 18:55:18 UTC (rev 3645) @@ -26,21 +26,21 @@ private readonly List<QueryTranslator> translators = new List<QueryTranslator>(); private readonly List<QueryParameters> parameters = new List<QueryParameters>(); private IList criteriaResults; - private Dictionary<string, int> criteriaResultPositions = new Dictionary<string, int>(); + private readonly Dictionary<string, int> criteriaResultPositions = new Dictionary<string, int>(); private string cacheRegion; private int commandTimeout = RowSelection.NoValue; - private bool isCacheable = false; + private bool isCacheable; private readonly ISessionImplementor session; private IResultTransformer resultTransformer; private readonly List<SqlType> types = new List<SqlType>(); - private SqlString sqlString = null; + private SqlString sqlString; private readonly Dialect.Dialect dialect; private bool forceCacheRefresh; private QueryParameters combinedParameters; private readonly List<string> namedParametersThatAreSafeToDuplicate = new List<string>(); private FlushMode flushMode = FlushMode.Unspecified; private FlushMode sessionFlushMode = FlushMode.Unspecified; - private static readonly Regex parseParameterListOrignialName = new Regex(@"(.*?)\d+_", RegexOptions.Compiled); + private static readonly Regex parseParameterListOrignialName = new Regex(@"(?<orgname>.*?)_\d+_", RegexOptions.Compiled); public MultiQueryImpl(ISessionImplementor session) { @@ -334,9 +334,9 @@ return this; } - public IMultiQuery SetCacheRegion(string cacheRegion) + public IMultiQuery SetCacheRegion(string region) { - this.cacheRegion = cacheRegion; + cacheRegion = region; return this; } @@ -361,14 +361,7 @@ { Before(); - if (cacheable) - { - criteriaResults = ListUsingQueryCache(); - } - else - { - criteriaResults = ListIgnoreQueryCache(); - } + criteriaResults = cacheable ? ListUsingQueryCache() : ListIgnoreQueryCache(); return criteriaResults; } finally @@ -377,9 +370,9 @@ } } - public IMultiQuery SetFlushMode(FlushMode flushMode) + public IMultiQuery SetFlushMode(FlushMode mode) { - this.flushMode = flushMode; + flushMode = mode; return this; } @@ -757,7 +750,7 @@ Match match = parseParameterListOrignialName.Match(name); if (match != null) { - string originalName = match.Groups[1].Value; + string originalName = match.Groups["orgname"].Value; return namedParametersThatAreSafeToDuplicate.Contains(originalName); } return false; Modified: trunk/nhibernate/src/NHibernate/Util/StringHelper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Util/StringHelper.cs 2008-07-21 15:21:34 UTC (rev 3644) +++ trunk/nhibernate/src/NHibernate/Util/StringHelper.cs 2008-07-22 18:55:18 UTC (rev 3645) @@ -109,15 +109,13 @@ return buf.ToString(); } - /// <summary> - /// - /// </summary> - /// <param name="template"></param> - /// <param name="placeholder"></param> - /// <param name="replacement"></param> - /// <returns></returns> public static string Replace(string template, string placeholder, string replacement) { + return Replace(template, placeholder, replacement, false); + } + + public static string Replace(string template, string placeholder, string replacement, bool wholeWords) + { // sometimes a null value will get passed in here -> SqlWhereStrings are a good example if (template == null) { @@ -131,13 +129,22 @@ } else { - return new StringBuilder(template.Substring(0, loc)) - .Append(replacement) - .Append(Replace( - template.Substring(loc + placeholder.Length), - placeholder, - replacement - )).ToString(); + // NH different implementation (NH-1253) + string replaceWith = replacement; + if(loc + placeholder.Length < template.Length) + { + string afterPlaceholder = template[loc + placeholder.Length].ToString(); + //After a token in HQL there can be whitespace, closedparen or comma.. + if(wholeWords && !(WhiteSpace.Contains(afterPlaceholder) || ClosedParen.Equals(afterPlaceholder) || Comma.Equals(afterPlaceholder))) + { + //If this is not a full token we don't want to touch it + replaceWith = placeholder; + } + } + + return + new StringBuilder(template.Substring(0, loc)).Append(replaceWith).Append( + Replace(template.Substring(loc + placeholder.Length), placeholder, replacement, wholeWords)).ToString(); } } Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1253/Car.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1253/Car.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1253/Car.cs 2008-07-22 18:55:18 UTC (rev 3645) @@ -0,0 +1,27 @@ +namespace NHibernate.Test.NHSpecificTest.NH1253 +{ + public class Car + { + private int _Id; + private string _Make; + private string _Model; + + public virtual int Id + { + get { return _Id; } + set { _Id = value; } + } + + public virtual string Model + { + get { return _Model; } + set { _Model = value; } + } + + public virtual string Make + { + get { return _Make; } + set { _Make = value; } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs 2008-07-22 18:55:18 UTC (rev 3645) @@ -0,0 +1,82 @@ +using System.Collections; +using System.Collections.Generic; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH1253 +{ + [TestFixture] + public class Fixture : BugTestCase + { + // The test only check that there are no lost parameter set (no exception) + [Test] + public void TestParametersWithTrailingNumbersSingleInList() + { + using (ISession s = OpenSession()) + { + using (ITransaction tx = s.BeginTransaction()) + { + IQuery q = s.CreateQuery("from Car c where c.Make in (:param1) or c.Model in (:param11)"); + q.SetParameterList("param11", new string[] { "Model1", "Model2" }); + q.SetParameterList("param1", new string[] { "Make1", "Make2" }); + IList<Car> cars = q.List<Car>(); + + tx.Commit(); + } + } + } + + [Test] + public void TestParametersWithTrailingNumbersSingleInListReverse() + { + using (ISession s = OpenSession()) + { + using (ITransaction tx = s.BeginTransaction()) + { + IQuery q = s.CreateQuery("from Car c where c.Make in (:param1) or c.Model in (:param11)"); + q.SetParameterList("param1", new string[] { "Model1", "Model2" }); + q.SetParameterList("param11", new string[] { "Make1", "Make2" }); + IList<Car> cars = q.List<Car>(); + + tx.Commit(); + } + } + } + + [Test] + public void TestParametersWithTrailingNumbersMultipleInList() + { + using (ISession s = OpenSession()) + { + using (ITransaction tx = s.BeginTransaction()) + { + IQuery q = s.CreateQuery("from Car c where c.Make in (:param11) or c.Model in (:param1)"); + q.SetParameterList("param11", new string[] { "One", "Two" }); + q.SetParameterList("param1", new string[] { "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve" }); + IList cars = q.List(); + + tx.Commit(); + } + } + } + + [Test] + public void MultiQuerySingleInList() + { + using (ISession s = OpenSession()) + { + using (ITransaction tx = s.BeginTransaction()) + { + IList results = s.CreateMultiQuery() + .Add("from Car c where c.Make in (:param1) or c.Model in (:param11)") + .Add("from Car c where c.Make in (:param1) or c.Model in (:param11)") + .SetParameterList("param11",new string[]{"Model1", "Model2"}) + .SetParameterList("param1", new string[] {"Make1", "Make2"}) + .List(); + + tx.Commit(); + } + } + } + + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1253/Mappings.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1253/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1253/Mappings.hbm.xml 2008-07-22 18:55:18 UTC (rev 3645) @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="NHibernate.Test.NHSpecificTest.NH1253" assembly="NHibernate.Test"> + <class name="Car" table="Cars"> + <id name="Id" column="CarID" type="Int32"> + <generator class="native" /> + </id> + <property name="Make" type="string" /> + <property name="Model" type="string" /> + </class> +</hibernate-mapping> Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-21 15:21:34 UTC (rev 3644) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-22 18:55:18 UTC (rev 3645) @@ -355,6 +355,8 @@ <Compile Include="NHSpecificTest\NH1230\PreSaveDoVeto.cs" /> <Compile Include="NHSpecificTest\NH1250\Model.cs" /> <Compile Include="NHSpecificTest\NH1250\PolymorphicJoinFetchFixture.cs" /> + <Compile Include="NHSpecificTest\NH1253\Car.cs" /> + <Compile Include="NHSpecificTest\NH1253\Fixture.cs" /> <Compile Include="NHSpecificTest\NH1275\A.cs" /> <Compile Include="NHSpecificTest\NH1275\Fixture.cs" /> <Compile Include="NHSpecificTest\NH1284\Fixture.cs" /> @@ -1361,6 +1363,7 @@ <ItemGroup> <EmbeddedResource Include="DynamicEntity\Interceptor\Customer.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="NHSpecificTest\NH1253\Mappings.hbm.xml" /> <EmbeddedResource Include="EntityModeTest\Map\Basic\ProductLine.hbm.xml" /> <EmbeddedResource Include="DynamicEntity\Tuplizer\Customer.hbm.xml" /> </ItemGroup> Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-3.5.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-3.5.csproj 2008-07-21 15:21:34 UTC (rev 3644) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-3.5.csproj 2008-07-22 18:55:18 UTC (rev 3645) @@ -294,6 +294,8 @@ <Compile Include="NHSpecificTest\NH1144\Fixture.cs" /> <Compile Include="NHSpecificTest\CriteriaFromHql\Person.cs" /> <Compile Include="NHSpecificTest\CriteriaFromHql\Fixture.cs" /> + <Compile Include="NHSpecificTest\NH1253\Car.cs" /> + <Compile Include="NHSpecificTest\NH1253\Fixture.cs" /> <Compile Include="NHSpecificTest\NH1284\Fixture.cs"> <SubType>Code</SubType> </Compile> @@ -1321,6 +1323,9 @@ <EmbeddedResource Include="NHSpecificTest\NH1359\Mappings.hbm.xml" /> </ItemGroup> <ItemGroup> + <EmbeddedResource Include="NHSpecificTest\NH1253\Mappings.hbm.xml" /> + </ItemGroup> + <ItemGroup> <Folder Include="Properties\" /> <Folder Include="Unionsubclass2\" /> </ItemGroup> @@ -1340,4 +1345,4 @@ if exist "$(ProjectDir)hibernate.cfg.xml" (copy "$(ProjectDir)hibernate.cfg.xml" "hibernate.cfg.xml") copy /y "..\..\..\NHibernate.DomainModel\ABC.hbm.xml" "ABC.hbm.xml"</PostBuildEvent> </PropertyGroup> -</Project> \ No newline at end of file +</Project> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-07-22 19:16:43
|
Revision: 3647 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3647&view=rev Author: fabiomaulo Date: 2008-07-22 19:16:52 +0000 (Tue, 22 Jul 2008) Log Message: ----------- re-fix NH-1254 to support the two drivers Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Dialect/SybaseAnywhereDialect.cs trunk/nhibernate/src/NHibernate/Driver/ASAClientDriver.cs trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Driver/ASA10ClientDriver.cs Modified: trunk/nhibernate/src/NHibernate/Dialect/SybaseAnywhereDialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/SybaseAnywhereDialect.cs 2008-07-22 19:12:25 UTC (rev 3646) +++ trunk/nhibernate/src/NHibernate/Dialect/SybaseAnywhereDialect.cs 2008-07-22 19:16:52 UTC (rev 3647) @@ -3,14 +3,14 @@ namespace NHibernate.Dialect { /// <summary> - /// An SQL dialect for Sybase Adaptive Server Anywhere 10.0 + /// An SQL dialect for Sybase Adaptive Server Anywhere 9.0/10.0 /// </summary> /// <remarks> /// <p> /// This dialect probably will not work with schema-export. If anyone out there /// can fill in the ctor with DbTypes to Strings that would be helpful. /// </p> - /// The SybaseAnywhere10Dialect defaults the following configuration properties: + /// The SybaseAnywhereDialect defaults the following configuration properties: /// <list type="table"> /// <listheader> /// <term>Property</term> Added: trunk/nhibernate/src/NHibernate/Driver/ASA10ClientDriver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Driver/ASA10ClientDriver.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Driver/ASA10ClientDriver.cs 2008-07-22 19:16:52 UTC (rev 3647) @@ -0,0 +1,41 @@ +namespace NHibernate.Driver +{ + /// <summary> + /// The ASAClientDriver Driver provides a database driver for Adaptive Server Anywhere 10.0. + /// </summary> + public class ASA10ClientDriver : ReflectionBasedDriver + { + /// <summary> + /// Initializes a new instance of the <see cref="ASAClientDriver"/> class. + /// </summary> + /// <exception cref="HibernateException"> + /// Thrown when the iAnywhere.Data.SQLAnywhere assembly is not and can not be loaded. + /// </exception> + public ASA10ClientDriver() + : base("iAnywhere.Data.SQLAnywhere", "iAnywhere.Data.SQLAnywhere.SAConnection", "iAnywhere.Data.SQLAnywhere.SACommand") + { + } + + /// <summary> + /// iAnywhere.Data.SQLAnywhere uses named parameters in the sql. + /// </summary> + /// <value><see langword="true" /> - Sybase uses <c>String.Empty</c> in the sql.</value> + public override bool UseNamedPrefixInSql + { + get { return false; } + } + + public override bool UseNamedPrefixInParameter + { + get { return false; } + } + + /// <summary> + /// iAnywhere.Data.SQLAnywhere use the <c>string.Empty</c> to locate parameters in sql. + /// </summary> + public override string NamedPrefix + { + get { return string.Empty; } + } + } +} Modified: trunk/nhibernate/src/NHibernate/Driver/ASAClientDriver.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Driver/ASAClientDriver.cs 2008-07-22 19:12:25 UTC (rev 3646) +++ trunk/nhibernate/src/NHibernate/Driver/ASAClientDriver.cs 2008-07-22 19:16:52 UTC (rev 3647) @@ -1,5 +1,3 @@ -using System; - namespace NHibernate.Driver { /// <summary> @@ -11,15 +9,15 @@ /// Initializes a new instance of the <see cref="ASAClientDriver"/> class. /// </summary> /// <exception cref="HibernateException"> - /// Thrown when the iAnywhere.Data.SQLAnywhere assembly is not and can not be loaded. + /// Thrown when the ASA.Data.AsaClient assembly is not and can not be loaded. /// </exception> public ASAClientDriver() - : base("iAnywhere.Data.SQLAnywhere", "iAnywhere.Data.SQLAnywhere.SAConnection", "iAnywhere.Data.SQLAnywhere.SACommand") + : base("iAnywhere.Data.AsaClient", "iAnywhere.Data.AsaClient.AsaConnection", "iAnywhere.Data.AsaClient.AsaCommand") { } /// <summary> - /// iAnywhere.Data.SQLAnywhere uses named parameters in the sql. + /// iAnywhere.Data.AsaClient uses named parameters in the sql. /// </summary> /// <value><see langword="true" /> - Sybase uses <c>String.Empty</c> in the sql.</value> public override bool UseNamedPrefixInSql @@ -33,7 +31,7 @@ } /// <summary> - /// iAnywhere.Data.SQLAnywhere use the <c>string.Empty</c> to locate parameters in sql. + /// iAnywhere.Data.AsaClient use the <c>string.Empty</c> to locate parameters in sql. /// </summary> public override string NamedPrefix { Modified: trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj 2008-07-22 19:12:25 UTC (rev 3646) +++ trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj 2008-07-22 19:16:52 UTC (rev 3647) @@ -593,6 +593,7 @@ <Compile Include="Dialect\Schema\MsSqlMetaData.cs" /> <Compile Include="Dialect\Schema\OracleMetaData.cs" /> <Compile Include="Dialect\Sybase11Dialect.cs" /> + <Compile Include="Driver\ASA10ClientDriver.cs" /> <Compile Include="Driver\ISqlParameterFormatter.cs" /> <Compile Include="Driver\SqlStringFormatter.cs" /> <Compile Include="Criterion\SubqueryProjection.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-07-22 22:05:30
|
Revision: 3649 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3649&view=rev Author: fabiomaulo Date: 2008-07-22 22:05:35 +0000 (Tue, 22 Jul 2008) Log Message: ----------- Merge r3648 (fix NH-1399) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/Table.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1399/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1399/Fixture.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/Table.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/Table.cs 2008-07-22 21:34:20 UTC (rev 3648) +++ trunk/nhibernate/src/NHibernate/Mapping/Table.cs 2008-07-22 22:05:35 UTC (rev 3649) @@ -709,20 +709,14 @@ public string UniqueColumnString(IEnumerable iterator, string referencedEntityName) { - int result = 0; + // NH Different implementation (NH-1339) + int result = 37; if (referencedEntityName != null) - result += referencedEntityName.GetHashCode(); + result ^= referencedEntityName.GetHashCode(); foreach (object o in iterator) { - // this is marked as unchecked because the GetHashCode could potentially - // cause an integer overflow. This way if there is an overflow it will - // just roll back over - since we are not doing any computations based - // on this number then a rollover is no big deal. - unchecked - { - result += o.GetHashCode(); - } + result ^= o.GetHashCode(); } return (name.GetHashCode().ToString("X") + result.GetHashCode().ToString("X")); } Copied: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1399/Fixture.cs (from rev 3648, branches/2.0.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1399/Fixture.cs) =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1399/Fixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1399/Fixture.cs 2008-07-22 22:05:35 UTC (rev 3649) @@ -0,0 +1,21 @@ +using NHibernate.Mapping; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH1399 +{ + [TestFixture] + public class Fixture + { + [Test] + public void Bug() + { + Table table1 = new Table("ATABLE"); + + Column table1ITestManyA = new Column("itestmanyaid"); + Column table1ITestManyB = new Column("itestmanybid"); + string t1Fk = table1.UniqueColumnString(new object[] { table1ITestManyA }, "BluewireTechnologies.Core.Framework.DynamicTypes2.Albatross.ITestManyA"); + string t2Fk = table1.UniqueColumnString(new object[] { table1ITestManyB }, "BluewireTechnologies.Core.Framework.DynamicTypes2.Albatross.ITestManyB"); + Assert.AreNotEqual(t1Fk, t2Fk, "Different columns in differents tables create the same FK name."); + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1399/Fixture.cs ___________________________________________________________________ Added: svn:mergeinfo + Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-22 21:34:20 UTC (rev 3648) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-22 22:05:35 UTC (rev 3649) @@ -387,6 +387,7 @@ <Compile Include="NHSpecificTest\NH1355\Category.cs" /> <Compile Include="NHSpecificTest\NH1355\CustomVersionType.cs" /> <Compile Include="NHSpecificTest\NH1355\UserTypeTimestamp.cs" /> + <Compile Include="NHSpecificTest\NH1399\Fixture.cs" /> <Compile Include="NHSpecificTest\NH280\Fixture.cs" /> <Compile Include="NHSpecificTest\NH280\Foo.cs" /> <Compile Include="NHSpecificTest\NH1018\Employee.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-07-23 03:36:07
|
Revision: 3653 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3653&view=rev Author: fabiomaulo Date: 2008-07-23 03:36:16 +0000 (Wed, 23 Jul 2008) Log Message: ----------- Fix NH-1361 (thanks to Carsten Hess) Possible Breaking Change: The ProxyTypeValidator make a more accurate check so your may not pass the validation Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Proxy/ProxyTypeValidator.cs trunk/nhibernate/src/NHibernate.DomainModel/Qux.cs trunk/nhibernate/src/NHibernate.Test/Classic/Video.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs Modified: trunk/nhibernate/src/NHibernate/Proxy/ProxyTypeValidator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Proxy/ProxyTypeValidator.cs 2008-07-23 03:24:41 UTC (rev 3652) +++ trunk/nhibernate/src/NHibernate/Proxy/ProxyTypeValidator.cs 2008-07-23 03:36:16 UTC (rev 3653) @@ -94,7 +94,7 @@ if (method.DeclaringType != typeof(object) && (method.IsPublic || method.IsAssembly || method.IsFamilyOrAssembly)) { - if (!method.IsVirtual) + if (!method.IsVirtual || method.IsFinal) { Error(errors, type, "method " + method.Name + " should be virtual"); } Modified: trunk/nhibernate/src/NHibernate.DomainModel/Qux.cs =================================================================== --- trunk/nhibernate/src/NHibernate.DomainModel/Qux.cs 2008-07-23 03:24:41 UTC (rev 3652) +++ trunk/nhibernate/src/NHibernate.DomainModel/Qux.cs 2008-07-23 03:36:16 UTC (rev 3653) @@ -36,7 +36,7 @@ #region ILifecycle members - public LifecycleVeto OnSave(ISession session) + public virtual LifecycleVeto OnSave(ISession session) { _created = true; try @@ -52,7 +52,7 @@ return LifecycleVeto.NoVeto; } - public LifecycleVeto OnDelete(ISession session) + public virtual LifecycleVeto OnDelete(ISession session) { _deleted = true; try @@ -67,13 +67,13 @@ return LifecycleVeto.NoVeto; } - public void OnLoad(ISession session, object id) + public virtual void OnLoad(ISession session, object id) { _loaded = true; _session = session; } - public LifecycleVeto OnUpdate(ISession s) + public virtual LifecycleVeto OnUpdate(ISession s) { return LifecycleVeto.NoVeto; } @@ -197,4 +197,4 @@ set { _holder = value; } } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate.Test/Classic/Video.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Classic/Video.cs 2008-07-23 03:24:41 UTC (rev 3652) +++ trunk/nhibernate/src/NHibernate.Test/Classic/Video.cs 2008-07-23 03:36:16 UTC (rev 3653) @@ -63,7 +63,7 @@ /// throw a <see cref="ValidationFailure" />. This method must not change the state of the object /// by side-effect. /// </summary> - public void Validate() + public virtual void Validate() { IList<string> br = GetBrokenRules(); if (br != null && br.Count > 0) Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs 2008-07-23 03:24:41 UTC (rev 3652) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs 2008-07-23 03:36:16 UTC (rev 3653) @@ -227,5 +227,25 @@ { Validate(typeof(InvalidNonVirtualProtectedInternalProperty)); } + + interface INonVirtualPublicImplementsInterface + { + int NonVirtualMethodImplementsInterface { get; } + } + + public class NonVirtualPublicImplementsInterface : ValidClass, INonVirtualPublicImplementsInterface + { + public int NonVirtualMethodImplementsInterface + { + get { return 0; } + } + } + + [Test] + [ExpectedException(typeof(InvalidProxyTypeException))] + public void VirtualPublicImplementsInterface() + { + Validate(typeof(NonVirtualPublicImplementsInterface)); + } } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-07-23 16:39:20
|
Revision: 3655 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3655&view=rev Author: fabiomaulo Date: 2008-07-23 16:39:27 +0000 (Wed, 23 Jul 2008) Log Message: ----------- Merge r3654 (fix NH-1403) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs trunk/nhibernate/src/NHibernate/Mapping/Any.cs trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj trunk/nhibernate/src/NHibernate/NHibernateUtil.cs trunk/nhibernate/src/NHibernate/Type/TypeType.cs trunk/nhibernate/src/NHibernate.DomainModel/FooBar.hbm.xml trunk/nhibernate/src/NHibernate.Test/Legacy/FooBarTest.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Type/ClassMetaType.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Female.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Hobby.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Male.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Person.cs Modified: trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs 2008-07-23 15:38:48 UTC (rev 3654) +++ trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs 2008-07-23 16:39:27 UTC (rev 3655) @@ -819,40 +819,33 @@ XmlAttribute metaAttribute = node.Attributes["meta-type"]; if (metaAttribute != null) { - IType metaType = TypeFactory.HeuristicType(metaAttribute.Value); - if (metaType == null) - throw new MappingException("could not interpret meta-type"); - model.MetaType = metaType.Name; - - IDictionary<object, string> values = new Dictionary<object, string>(); - foreach (XmlNode metaValue in node.SelectNodes(HbmConstants.nsMetaValue, namespaceManager)) - try - { - object value = ((IDiscriminatorType) metaType).StringToObject(metaValue.Attributes["value"].Value); - string entityName = GetClassName(metaValue.Attributes["class"].Value, mappings); - values[value] = entityName; - } - catch (InvalidCastException) - { - throw new MappingException("meta-type was not an IDiscriminatorType: " + metaType.Name); - } - catch (HibernateException he) - { - throw new MappingException("could not interpret meta-value", he); - } - catch (TypeLoadException cnfe) - { - throw new MappingException("meta-value class not found", cnfe); - } - - if (values.Count > 0) + model.MetaType = metaAttribute.Value; + XmlNodeList metaValues = node.SelectNodes(HbmConstants.nsMetaValue, namespaceManager); + if (metaValues != null && metaValues.Count > 0) { - model.MetaValues = values; + IDictionary<object, string> values = new Dictionary<object, string>(); + IType metaType = TypeFactory.HeuristicType(model.MetaType); + foreach (XmlNode metaValue in metaValues) + try + { + object value = ((IDiscriminatorType)metaType).StringToObject(metaValue.Attributes["value"].Value); + string entityName = GetClassName(metaValue.Attributes["class"].Value, mappings); + values[value] = entityName; + } + catch (InvalidCastException) + { + throw new MappingException("meta-type was not an IDiscriminatorType: " + metaType.Name); + } + catch (HibernateException he) + { + throw new MappingException("could not interpret meta-value", he); + } + catch (TypeLoadException cnfe) + { + throw new MappingException("meta-value class not found", cnfe); + } + model.MetaValues = values.Count > 0 ? values : null; } - else - { - model.MetaValues = null; - } } BindColumns(node, model, isNullable, false, null); Modified: trunk/nhibernate/src/NHibernate/Mapping/Any.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/Any.cs 2008-07-23 15:38:48 UTC (rev 3654) +++ trunk/nhibernate/src/NHibernate/Mapping/Any.cs 2008-07-23 16:39:27 UTC (rev 3655) @@ -40,7 +40,7 @@ type = new AnyType( metaValues == null - ? TypeFactory.HeuristicType(metaTypeName) + ? ("class".Equals(metaTypeName) ? new ClassMetaType(): TypeFactory.HeuristicType(metaTypeName)) : new MetaType(metaValues, TypeFactory.HeuristicType(metaTypeName)), TypeFactory.HeuristicType(identifierTypeName)); } @@ -70,4 +70,4 @@ set { metaValues = value; } } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj 2008-07-23 15:38:48 UTC (rev 3654) +++ trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj 2008-07-23 16:39:27 UTC (rev 3655) @@ -1028,6 +1028,7 @@ <Compile Include="Type\AnsiCharType.cs" /> <Compile Include="Type\AnyType.cs" /> <Compile Include="Type\AbstractCharType.cs" /> + <Compile Include="Type\ClassMetaType.cs" /> <Compile Include="Type\CollectionType.cs" /> <Compile Include="Type\CustomCollectionType.cs" /> <Compile Include="Type\EmbeddedComponentType.cs" /> Modified: trunk/nhibernate/src/NHibernate/NHibernateUtil.cs =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernateUtil.cs 2008-07-23 15:38:48 UTC (rev 3654) +++ trunk/nhibernate/src/NHibernate/NHibernateUtil.cs 2008-07-23 16:39:27 UTC (rev 3655) @@ -221,6 +221,12 @@ public static readonly NullableType Class = new TypeType(); /// <summary> + /// NHibernate class meta type for associtiation of kind <code>any</code>. + /// </summary> + /// <seealso cref="AnyType"/> + public static readonly IType ClassMetaType = new ClassMetaType(); + + /// <summary> /// NHibernate serializable type /// </summary> public static readonly NullableType Serializable = new SerializableType(); @@ -526,4 +532,4 @@ } } } -} \ No newline at end of file +} Added: trunk/nhibernate/src/NHibernate/Type/ClassMetaType.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Type/ClassMetaType.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Type/ClassMetaType.cs 2008-07-23 16:39:27 UTC (rev 3655) @@ -0,0 +1,125 @@ +using System; +using System.Data; +using System.Xml; +using NHibernate.Engine; +using NHibernate.SqlTypes; + +namespace NHibernate.Type +{ + /// <summary> + /// ClassMetaType is a NH specif type to support "any" with meta-type="class" + /// </summary> + /// <remarks> + /// It work like a MetaType where the key is the entity-name it self + /// </remarks> + [Serializable] + public class ClassMetaType : AbstractType + { + public override SqlType[] SqlTypes(IMapping mapping) + { + return new SqlType[] { NHibernateUtil.String.SqlType }; + } + + public override int GetColumnSpan(IMapping mapping) + { + return 1; + } + + public override System.Type ReturnedClass + { + get { return typeof (string); } + } + + public override object NullSafeGet(IDataReader rs, string[] names, ISessionImplementor session, object owner) + { + return NullSafeGet(rs, names[0], session, owner); + } + + public override object NullSafeGet(IDataReader rs,string name,ISessionImplementor session,object owner) + { + int index = rs.GetOrdinal(name); + + if (rs.IsDBNull(index)) + { + return null; + } + else + { + string str = (string) NHibernateUtil.String.Get(rs, index); + return string.IsNullOrEmpty(str) ? null : str; + } + } + + public override void NullSafeSet(IDbCommand st, object value, int index, bool[] settable, ISessionImplementor session) + { + if (settable[0]) NullSafeSet(st, value, index, session); + } + + public override void NullSafeSet(IDbCommand st,object value,int index,ISessionImplementor session) + { + if (value == null) + { + ((IDataParameter)st.Parameters[index]).Value = DBNull.Value; + } + else + { + NHibernateUtil.String.Set(st, value, index); + } + } + + public override string ToLoggableString(object value, ISessionFactoryImplementor factory) + { + return ToXMLString(value, factory); + } + + public override string Name + { + get { return "ClassMetaType"; } + } + + public override object DeepCopy(object value, EntityMode entityMode, ISessionFactoryImplementor factory) + { + return value; + } + + public override bool IsMutable + { + get { return false; } + } + + public override bool IsDirty(object old, object current, bool[] checkable, ISessionImplementor session) + { + return checkable[0] && IsDirty(old, current, session); + } + + public override object FromXMLNode(XmlNode xml, IMapping factory) + { + return FromXMLString(xml.Value, factory); + } + + public object FromXMLString(string xml, IMapping factory) + { + return xml; //xml is the entity name + } + + public override object Replace(object original, object current, ISessionImplementor session, object owner, System.Collections.IDictionary copiedAlready) + { + return original; + } + + public override void SetToXMLNode(XmlNode node, object value, ISessionFactoryImplementor factory) + { + node.Value = ToXMLString(value, factory); + } + + public override bool[] ToColumnNullness(object value, IMapping mapping) + { + throw new NotSupportedException(); + } + + public string ToXMLString(object value, ISessionFactoryImplementor factory) + { + return (string)value; //value is the entity name + } + } +} Modified: trunk/nhibernate/src/NHibernate/Type/TypeType.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Type/TypeType.cs 2008-07-23 15:38:48 UTC (rev 3654) +++ trunk/nhibernate/src/NHibernate/Type/TypeType.cs 2008-07-23 16:39:27 UTC (rev 3655) @@ -90,7 +90,7 @@ /// </remarks> public override void Set(IDbCommand cmd, object value, int index) { - NHibernateUtil.String.Set(cmd, ((System.Type)value).FullName, index); + NHibernateUtil.String.Set(cmd, ((System.Type)value).AssemblyQualifiedName, index); } /// <summary> @@ -101,7 +101,7 @@ /// <returns>An Xml formatted string that contains the Assembly Qualified Name.</returns> public override string ToString(object value) { - return ((System.Type)value).FullName; + return ((System.Type)value).AssemblyQualifiedName; } /// <summary> @@ -134,4 +134,4 @@ } } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate.DomainModel/FooBar.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.DomainModel/FooBar.hbm.xml 2008-07-23 15:38:48 UTC (rev 3654) +++ trunk/nhibernate/src/NHibernate.DomainModel/FooBar.hbm.xml 2008-07-23 16:39:27 UTC (rev 3655) @@ -197,7 +197,7 @@ <element column="date_" type="DateTime"/> </array> </component> - <any name="Object" id-type="Int64" cascade="all"> + <any name="Object" meta-type="class" id-type="Int64" cascade="all"> <!-- made clazz 200 instead of 100 because of all the extra info stored such as assembly, key, culture Modified: trunk/nhibernate/src/NHibernate.Test/Legacy/FooBarTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Legacy/FooBarTest.cs 2008-07-23 15:38:48 UTC (rev 3654) +++ trunk/nhibernate/src/NHibernate.Test/Legacy/FooBarTest.cs 2008-07-23 16:39:27 UTC (rev 3655) @@ -5129,7 +5129,7 @@ s = OpenSession(); IList list = s.CreateQuery("from Bar bar where bar.Object.id = ? and bar.Object.class = ?") - .SetParameter(0, oid, NHibernateUtil.Int64).SetParameter(1, typeof(One), NHibernateUtil.Class).List(); + .SetParameter(0, oid, NHibernateUtil.Int64).SetParameter(1, typeof(One).FullName, NHibernateUtil.ClassMetaType).List(); Assert.AreEqual(1, list.Count); // this is a little different from h2.0.3 because the full type is stored, not Copied: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Female.cs (from rev 3654, branches/2.0.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Female.cs) =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Female.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Female.cs 2008-07-23 16:39:27 UTC (rev 3655) @@ -0,0 +1,9 @@ +namespace NHibernate.Test.NHSpecificTest.NH1403 +{ + public class Female : Person + { + public Female() {} + + public Female(string name) : base(name) {} + } +} \ No newline at end of file Copied: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Fixture.cs (from rev 3654, branches/2.0.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Fixture.cs) =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Fixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Fixture.cs 2008-07-23 16:39:27 UTC (rev 3655) @@ -0,0 +1,40 @@ +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH1403 +{ + [TestFixture] + public class Fixture : BugTestCase + { + [Test] + public void Bug() + { + Hobby h = new Hobby("Develop software"); + Person p = new Male("Diego"); + h.Person = p; + Hobby h1 = new Hobby("Drive Car"); + Person p1 = new Female("Luciana"); + h1.Person = p1; + object savedIdMale; + object saveIdFemale; + using (ISession s = OpenSession()) + using(ITransaction t = s.BeginTransaction()) + { + savedIdMale = s.Save(h); + saveIdFemale = s.Save(h1); + t.Commit(); + } + + using (ISession s = OpenSession()) + using (ITransaction t = s.BeginTransaction()) + { + h = s.Get<Hobby>(savedIdMale); + h1 = s.Get<Hobby>(saveIdFemale); + Assert.IsTrue(h.Person is Male); + Assert.IsTrue(h1.Person is Female); + s.Delete(h); + s.Delete(h1); + t.Commit(); + } + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Fixture.cs ___________________________________________________________________ Added: svn:mergeinfo + Copied: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Hobby.cs (from rev 3654, branches/2.0.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Hobby.cs) =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Hobby.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Hobby.cs 2008-07-23 16:39:27 UTC (rev 3655) @@ -0,0 +1,34 @@ +namespace NHibernate.Test.NHSpecificTest.NH1403 +{ + public class Hobby + { + private int id; + private string name; + private Person person; + + public Hobby() {} + + public Hobby(string name) : this() + { + this.name = name; + } + + public virtual int Id + { + get { return id; } + set { id = value; } + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual Person Person + { + get { return person; } + set { person = value; } + } + } +} \ No newline at end of file Copied: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Male.cs (from rev 3654, branches/2.0.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Male.cs) =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Male.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Male.cs 2008-07-23 16:39:27 UTC (rev 3655) @@ -0,0 +1,9 @@ +namespace NHibernate.Test.NHSpecificTest.NH1403 +{ + public class Male : Person + { + public Male() {} + + public Male(string name) : base(name) {} + } +} \ No newline at end of file Copied: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Mappings.hbm.xml (from rev 3654, branches/2.0.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Mappings.hbm.xml) =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Mappings.hbm.xml 2008-07-23 16:39:27 UTC (rev 3655) @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.NHSpecificTest.NH1403"> + + <class name="Person"> + <id name="Id"> + <generator class="native" /> + </id> + + <discriminator column="Gender" type="String" /> + + <property name="Name" /> + + <subclass name="Female" discriminator-value="Female"> + </subclass> + + <subclass name="Male" discriminator-value="Male"> + </subclass> + </class> + + <class name="Hobby"> + <id name="Id"> + <generator class="native" /> + </id> + + <property name="Name" /> + <any name="Person" meta-type="class" id-type="int" cascade="all"> + <column name="ORIGINAL_CLASS"/> + <column name="ORIGINAL_ID"/> + </any> + </class> +</hibernate-mapping> Copied: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Person.cs (from rev 3654, branches/2.0.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Person.cs) =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Person.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1403/Person.cs 2008-07-23 16:39:27 UTC (rev 3655) @@ -0,0 +1,27 @@ +namespace NHibernate.Test.NHSpecificTest.NH1403 +{ + public class Person + { + private int id; + private string name; + + public Person() {} + + public Person(string name) : this() + { + this.name = name; + } + + public virtual int Id + { + get { return id; } + set { id = value; } + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-23 15:38:48 UTC (rev 3654) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-23 16:39:27 UTC (rev 3655) @@ -388,6 +388,11 @@ <Compile Include="NHSpecificTest\NH1355\CustomVersionType.cs" /> <Compile Include="NHSpecificTest\NH1355\UserTypeTimestamp.cs" /> <Compile Include="NHSpecificTest\NH1399\Fixture.cs" /> + <Compile Include="NHSpecificTest\NH1403\Female.cs" /> + <Compile Include="NHSpecificTest\NH1403\Fixture.cs" /> + <Compile Include="NHSpecificTest\NH1403\Hobby.cs" /> + <Compile Include="NHSpecificTest\NH1403\Male.cs" /> + <Compile Include="NHSpecificTest\NH1403\Person.cs" /> <Compile Include="NHSpecificTest\NH280\Fixture.cs" /> <Compile Include="NHSpecificTest\NH280\Foo.cs" /> <Compile Include="NHSpecificTest\NH1018\Employee.cs" /> @@ -1364,6 +1369,7 @@ <ItemGroup> <EmbeddedResource Include="DynamicEntity\Interceptor\Customer.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="NHSpecificTest\NH1403\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1253\Mappings.hbm.xml" /> <EmbeddedResource Include="EntityModeTest\Map\Basic\ProductLine.hbm.xml" /> <EmbeddedResource Include="DynamicEntity\Tuplizer\Customer.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-07-25 04:52:46
|
Revision: 3661 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3661&view=rev Author: fabiomaulo Date: 2008-07-25 04:52:55 +0000 (Fri, 25 Jul 2008) Log Message: ----------- Fix NH-1405 in a different way than 2.0 branch Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Type/EmbeddedComponentType.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Column.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Mappings.hbm.xml Modified: trunk/nhibernate/src/NHibernate/Type/EmbeddedComponentType.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Type/EmbeddedComponentType.cs 2008-07-23 23:19:37 UTC (rev 3660) +++ trunk/nhibernate/src/NHibernate/Type/EmbeddedComponentType.cs 2008-07-25 04:52:55 UTC (rev 3661) @@ -19,7 +19,9 @@ public override object Instantiate(object parent, ISessionImplementor session) { - bool useParent = parent != null && base.ReturnedClass.IsInstanceOfType(parent); + bool useParent= false; + // NH Different implemetation : since we are not sure about why H3.2 use the "parent" + //useParent = parent != null && base.ReturnedClass.IsInstanceOfType(parent); return useParent ? parent : base.Instantiate(parent, session); } Copied: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Column.cs (from rev 3659, branches/2.0.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Column.cs) =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Column.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Column.cs 2008-07-25 04:52:55 UTC (rev 3661) @@ -0,0 +1,124 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.NH1405 +{ + public class Column + { + /// <summary> + /// The column name. Part 3 of 3 of the primary key. + /// </summary> + private String _columnName; + + /// <summary> + /// Another column in the same table. + /// </summary> + private Column _controlColumn; + + /// <summary> + /// The system ID. Part 1 of 3 of the primary key. + /// </summary> + private String _systemId; + + /// <summary> + /// The table name. Part 2 of 3 of the primary key. + /// </summary> + private String _tableName; + + /// <summary> + /// The column name. Part 3 of 3 of the primary key. + /// </summary> + public virtual String ColumnName + { + get { return _columnName; } + set { _columnName = value; } + } + + /// <summary> + /// Another column in the same table. + /// </summary> + public virtual Column ControlColumn + { + get { return _controlColumn; } + set { _controlColumn = value; } + } + + /// <summary> + /// The system ID. Part 1 of 3 of the primary key. + /// </summary> + public virtual String SystemId + { + get { return _systemId; } + set { _systemId = value; } + } + + /// <summary> + /// The table name. Part 2 of 3 of the primary key. + /// </summary> + public virtual String TableName + { + get { return _tableName; } + set { _tableName = value; } + } + + public override bool Equals(object obj) + { + if (this == obj) + { + return true; + } + if (obj == null) + { + return false; + } + if (GetType() != obj.GetType()) + { + return false; + } + Column other = (Column) obj; + if (null == _systemId) + { + if (null != other._systemId) + { + return false; + } + } + else if (!_systemId.Equals(other._systemId)) + { + return false; + } + if (null == _tableName) + { + if (null != other._tableName) + { + return false; + } + } + else if (!_tableName.Equals(other._tableName)) + { + return false; + } + if (null == _columnName) + { + if (null != other._columnName) + { + return false; + } + } + else if (!_columnName.Equals(other._columnName)) + { + return false; + } + return true; + } + + public override int GetHashCode() + { + const int PRIME = 31; + int result = 1; + result = PRIME * result + ((null == _systemId) ? 0 : _systemId.GetHashCode()); + result = PRIME * result + ((null == _tableName) ? 0 : _tableName.GetHashCode()); + result = PRIME * result + ((null == _columnName) ? 0 : _columnName.GetHashCode()); + return result; + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Column.cs ___________________________________________________________________ Added: svn:mergeinfo + Copied: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Fixture.cs (from rev 3660, branches/2.0.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Fixture.cs) =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Fixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Fixture.cs 2008-07-25 04:52:55 UTC (rev 3661) @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.Data; +using NUnit.Framework; +namespace NHibernate.Test.NHSpecificTest.NH1405 +{ + [TestFixture] + public class Fixture : BugTestCase + { + [Test] + public void Bug() + { + string[] populate = new string[] + { + "insert into PPDM_COLUMN ( SYSTEM_ID, TABLE_NAME, COLUMN_NAME, CONTROL_COLUMN ) values ( 'SYSTEM', 'TABLE', 'COLUMN1', null )", + "insert into PPDM_COLUMN ( SYSTEM_ID, TABLE_NAME, COLUMN_NAME, CONTROL_COLUMN ) values ( 'SYSTEM', 'TABLE', 'COLUMN2', 'COLUMN1' )", + "insert into PPDM_COLUMN ( SYSTEM_ID, TABLE_NAME, COLUMN_NAME, CONTROL_COLUMN ) values ( 'SYSTEM', 'TABLE', 'COLUMN3', 'COLUMN2' )" + }; + + using (ISession session = OpenSession()) + using (ITransaction tx = session.BeginTransaction()) + { + foreach (string sql in populate) + { + IDbCommand cmd = session.Connection.CreateCommand(); + cmd.CommandText = sql; + tx.Enlist(cmd); + cmd.ExecuteNonQuery(); + } + tx.Commit(); + } + + using (ISession session = OpenSession()) + using (ITransaction tx = session.BeginTransaction()) + { + IQuery query = session.CreateQuery("from Column"); + IList<Column> columns = query.List<Column>(); + Assert.AreEqual(3, columns.Count); + foreach (Column column in columns) + { + Assert.IsNotNull(column.ColumnName, "Column.ColumnName should not be null."); + Assert.IsFalse((null != column.ControlColumn) && (null == column.ControlColumn.ColumnName), + "Column's control column's ColumnName should not be null."); + } + tx.Commit(); + } + + using (ISession session = OpenSession()) + using (ITransaction tx = session.BeginTransaction()) + { + IDbCommand cmd = session.Connection.CreateCommand(); + cmd.CommandText = "DELETE FROM PPDM_COLUMN"; + tx.Enlist(cmd); + cmd.ExecuteNonQuery(); + tx.Commit(); + } + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Fixture.cs ___________________________________________________________________ Added: svn:mergeinfo + Copied: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Mappings.hbm.xml (from rev 3659, branches/2.0.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Mappings.hbm.xml) =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Mappings.hbm.xml 2008-07-25 04:52:55 UTC (rev 3661) @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.NHSpecificTest.NH1405" + default-lazy="false"> + + <class name="Column" table="PPDM_COLUMN"> + <composite-id> + <key-property name="SystemId" type="String" column="SYSTEM_ID" length="20" /> + <key-property name="TableName" type="String" column="TABLE_NAME" length="30" /> + <key-property name="ColumnName" type="String" column="COLUMN_NAME" length="30" /> + </composite-id> + <!-- + Remove this many-to-one mapping and ColumnName will be retrieved correctly - + keep it and ColumnName will be null. + ControlColumn is never fetched correctly. + --> + <many-to-one name="ControlColumn" class="Column" update="false" insert="false" not-found="ignore"> + <column name="SYSTEM_ID" /> + <column name="TABLE_NAME" /> + <column name="CONTROL_COLUMN" length="30" /> + </many-to-one> + </class> +</hibernate-mapping> + \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1405/Mappings.hbm.xml ___________________________________________________________________ Added: svn:mergeinfo + Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-23 23:19:37 UTC (rev 3660) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-25 04:52:55 UTC (rev 3661) @@ -401,6 +401,8 @@ <Compile Include="NHSpecificTest\NH1403\Hobby.cs" /> <Compile Include="NHSpecificTest\NH1403\Male.cs" /> <Compile Include="NHSpecificTest\NH1403\Person.cs" /> + <Compile Include="NHSpecificTest\NH1405\Column.cs" /> + <Compile Include="NHSpecificTest\NH1405\Fixture.cs" /> <Compile Include="NHSpecificTest\NH280\Fixture.cs" /> <Compile Include="NHSpecificTest\NH280\Foo.cs" /> <Compile Include="NHSpecificTest\NH1018\Employee.cs" /> @@ -1379,6 +1381,7 @@ <EmbeddedResource Include="Any\Person.hbm.xml" /> <EmbeddedResource Include="Any\Properties.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="NHSpecificTest\NH1405\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1403\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1253\Mappings.hbm.xml" /> <EmbeddedResource Include="EntityModeTest\Map\Basic\ProductLine.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-07-25 05:09:13
|
Revision: 3662 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3662&view=rev Author: fabiomaulo Date: 2008-07-25 05:09:20 +0000 (Fri, 25 Jul 2008) Log Message: ----------- Fix NH-1393 and NH-1394 (by Tuna Toksoz) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/AggregateProjection.cs trunk/nhibernate/src/NHibernate/Criterion/AvgProjection.cs trunk/nhibernate/src/NHibernate/Criterion/CountProjection.cs trunk/nhibernate/src/NHibernate/Criterion/Order.cs trunk/nhibernate/src/NHibernate/Criterion/Projections.cs trunk/nhibernate/src/NHibernate.Test/ExpressionTest/Projection/ProjectionFixture.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1393/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1393/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1393/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1393/Person.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1394/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1394/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1394/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1394/Person.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/AggregateProjection.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/AggregateProjection.cs 2008-07-25 04:52:55 UTC (rev 3661) +++ trunk/nhibernate/src/NHibernate/Criterion/AggregateProjection.cs 2008-07-25 05:09:20 UTC (rev 3662) @@ -1,26 +1,33 @@ using System; +using System.Collections.Generic; using NHibernate.SqlCommand; using NHibernate.Type; +using NHibernate.Util; namespace NHibernate.Criterion { - using System.Collections.Generic; - /// <summary> /// An Aggregation /// </summary> [Serializable] public class AggregateProjection : SimpleProjection { + protected readonly string aggregate; + protected readonly IProjection projection; protected readonly string propertyName; - protected readonly string aggregate; protected internal AggregateProjection(string aggregate, string propertyName) { + this.propertyName = propertyName; this.aggregate = aggregate; - this.propertyName = propertyName; } + protected internal AggregateProjection(string aggregate, IProjection projection) + { + this.aggregate = aggregate; + this.projection = projection; + } + public override bool IsAggregate { get { return true; } @@ -28,25 +35,38 @@ public override string ToString() { - return aggregate + "(" + propertyName + ')'; + return aggregate + "(" + (projection != null ? projection.ToString() : propertyName) + ')'; } public override IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery) { + if (projection != null) + { + return projection.GetTypes(criteria, criteriaQuery); + } return new IType[] {criteriaQuery.GetType(criteria, propertyName)}; } - public override SqlString ToSqlString(ICriteria criteria, int loc, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters) + public override SqlString ToSqlString(ICriteria criteria, int loc, ICriteriaQuery criteriaQuery, + IDictionary<string, IFilter> enabledFilters) { - return new SqlString(new object[] - { - aggregate, - "(", - criteriaQuery.GetColumn(criteria, propertyName), - ") as y", - loc.ToString(), - "_" - }); + if (projection != null) + { + return + new SqlString(new object[] + { + aggregate, "(", + StringHelper.RemoveAsAliasesFromSql(projection.ToSqlString(criteria, loc, criteriaQuery, + enabledFilters)).ToString(), ") as y", + loc.ToString(), "_" + }); + } + else + { + return + new SqlString(new object[] + {aggregate, "(", criteriaQuery.GetColumn(criteria, propertyName), ") as y", loc.ToString(), "_"}); + } } public override bool IsGrouped @@ -60,4 +80,4 @@ throw new InvalidOperationException("not a grouping projection"); } } -} +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Criterion/AvgProjection.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/AvgProjection.cs 2008-07-25 04:52:55 UTC (rev 3661) +++ trunk/nhibernate/src/NHibernate/Criterion/AvgProjection.cs 2008-07-25 05:09:20 UTC (rev 3662) @@ -1,14 +1,38 @@ using System; +using System.Collections.Generic; +using NHibernate.Engine; +using NHibernate.SqlCommand; +using NHibernate.SqlTypes; using NHibernate.Type; +using NHibernate.Util; namespace NHibernate.Criterion { [Serializable] public class AvgProjection : AggregateProjection { - public AvgProjection(String propertyName) - : base("avg", propertyName) + public AvgProjection(IProjection projection) : base("avg", projection) {} + public AvgProjection(String propertyName) : base("avg", propertyName) {} + + public override SqlString ToSqlString(ICriteria criteria, int loc, ICriteriaQuery criteriaQuery, + IDictionary<string, IFilter> enabledFilters) { + ISessionFactoryImplementor factory = criteriaQuery.Factory; + SqlType[] sqlTypeCodes = NHibernateUtil.Double.SqlTypes(factory); + string sqlType = factory.Dialect.GetCastTypeName(sqlTypeCodes[0]); + string parameter; + if (projection != null) + { + parameter = + StringHelper.RemoveAsAliasesFromSql(projection.ToSqlString(criteria, loc, criteriaQuery, enabledFilters)).ToString(); + } + else + { + parameter = criteriaQuery.GetColumn(criteria, propertyName); + } + string expression = string.Format("{0}(cast({1} as {2})) as {3}", aggregate, parameter, sqlType, + GetColumnAliases(loc)[0]); + return new SqlString(expression); } public override IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery) Modified: trunk/nhibernate/src/NHibernate/Criterion/CountProjection.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/CountProjection.cs 2008-07-25 04:52:55 UTC (rev 3661) +++ trunk/nhibernate/src/NHibernate/Criterion/CountProjection.cs 2008-07-25 05:09:20 UTC (rev 3662) @@ -1,11 +1,10 @@ using System; +using System.Collections.Generic; using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Criterion { - using System.Collections.Generic; - /// <summary> /// A Count /// </summary> @@ -14,10 +13,8 @@ { private bool distinct; - protected internal CountProjection(String prop) - : base("count", prop) - { - } + protected internal CountProjection(String prop) : base("count", prop) {} + protected internal CountProjection(IProjection projection) : base("count", projection) {} public override IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery) { @@ -29,18 +26,15 @@ return (distinct) ? "distinct " + base.ToString() : base.ToString(); } - public override SqlString ToSqlString(ICriteria criteria, int position, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters) + public override SqlString ToSqlString(ICriteria criteria, int position, ICriteriaQuery criteriaQuery, + IDictionary<string, IFilter> enabledFilters) { - SqlStringBuilder buf = new SqlStringBuilder() - .Add("count("); + SqlStringBuilder buf = new SqlStringBuilder().Add("count("); if (distinct) { buf.Add("distinct "); } - buf.Add(criteriaQuery.GetColumn(criteria, propertyName)) - .Add(") as y") - .Add(position.ToString()) - .Add("_"); + buf.Add(criteriaQuery.GetColumn(criteria, propertyName)).Add(") as y").Add(position.ToString()).Add("_"); return buf.ToSqlString(); } Modified: trunk/nhibernate/src/NHibernate/Criterion/Order.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Order.cs 2008-07-25 04:52:55 UTC (rev 3661) +++ trunk/nhibernate/src/NHibernate/Criterion/Order.cs 2008-07-25 05:09:20 UTC (rev 3662) @@ -1,6 +1,9 @@ using System; +using System.Collections.Generic; using System.Text; using NHibernate.Engine; +using NHibernate.Criterion; +using NHibernate.SqlCommand; namespace NHibernate.Criterion { @@ -13,6 +16,17 @@ { protected bool ascending; protected string propertyName; + protected IProjection projection; + /// <summary> + /// Constructor for Order. + /// </summary> + /// <param name="projection"></param> + /// <param name="ascending"></param> + public Order(IProjection projection, bool ascending) + { + this.projection = projection; + this.ascending = ascending; + } /// <summary> /// Constructor for Order. @@ -31,6 +45,16 @@ /// </summary> public virtual string ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery) { + if(projection!=null) + { + SqlString sb=new SqlString(); + SqlString produced = this.projection.ToSqlString(criteria, 0, criteriaQuery, new Dictionary<string, IFilter>()); + SqlString truncated = NHibernate.Util.StringHelper.RemoveAsAliasesFromSql(produced); + sb = sb.Append(truncated); + sb = sb.Append(ascending ? " asc" : " desc"); + return sb.ToString(); + } + string[] columns = criteriaQuery.GetColumnAliasesUsingProjection(criteria, propertyName); StringBuilder fragment = new StringBuilder(); @@ -65,7 +89,7 @@ public override string ToString() { - return propertyName + (ascending ? " asc" : " desc"); + return (projection!=null?projection.ToString():propertyName) + (ascending ? " asc" : " desc"); } /// <summary> @@ -79,8 +103,28 @@ } /// <summary> + /// Ascending order + /// </summary> + /// <param name="projection"></param> + /// <returns></returns> + public static Order Asc(IProjection projection) + { + return new Order(projection, true); + } + + /// <summary> /// Descending order /// </summary> + /// <param name="projection"></param> + /// <returns></returns> + public static Order Desc(IProjection projection) + { + return new Order(projection, false); + } + + /// <summary> + /// Descending order + /// </summary> /// <param name="propertyName"></param> /// <returns></returns> public static Order Desc(string propertyName) @@ -88,4 +132,4 @@ return new Order(propertyName, false); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Criterion/Projections.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Projections.cs 2008-07-25 04:52:55 UTC (rev 3661) +++ trunk/nhibernate/src/NHibernate/Criterion/Projections.cs 2008-07-25 05:09:20 UTC (rev 3662) @@ -56,10 +56,18 @@ { return new RowCountInt64Projection(); } - /// <summary> /// A property value count /// </summary> + /// <param name="projection"></param> + /// <returns></returns> + public static CountProjection Count(IProjection projection) + { + return new CountProjection(projection); + } + /// <summary> + /// A property value count + /// </summary> /// <param name="propertyName"></param> /// <returns></returns> public static CountProjection Count(string propertyName) @@ -88,6 +96,17 @@ } /// <summary> + /// A projection maximum value + /// </summary> + /// <param name="projection"></param> + /// <returns></returns> + public static AggregateProjection Max(IProjection projection) + { + return new AggregateProjection("max", projection); + } + + + /// <summary> /// A property minimum value /// </summary> /// <param name="propertyName"></param> @@ -98,6 +117,16 @@ } /// <summary> + /// A projection minimum value + /// </summary> + /// <param name="projection"></param> + /// <returns></returns> + public static AggregateProjection Min(IProjection projection) + { + return new AggregateProjection("min", projection); + } + + /// <summary> /// A property average value /// </summary> /// <param name="propertyName"></param> @@ -108,6 +137,16 @@ } /// <summary> + /// A property average value + /// </summary> + /// <param name="projection"></param> + /// <returns></returns> + public static AggregateProjection Avg(IProjection projection) + { + return new AvgProjection(projection); + } + + /// <summary> /// A property value sum /// </summary> /// <param name="propertyName"></param> @@ -118,6 +157,16 @@ } /// <summary> + /// A property value sum + /// </summary> + /// <param name="projection"></param> + /// <returns></returns> + public static AggregateProjection Sum(IProjection projection) + { + return new AggregateProjection("sum", projection); + } + + /// <summary> /// A SQL projection, a typed select clause fragment /// </summary> /// <param name="sql"></param> Modified: trunk/nhibernate/src/NHibernate.Test/ExpressionTest/Projection/ProjectionFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/ExpressionTest/Projection/ProjectionFixture.cs 2008-07-25 04:52:55 UTC (rev 3661) +++ trunk/nhibernate/src/NHibernate.Test/ExpressionTest/Projection/ProjectionFixture.cs 2008-07-25 05:09:20 UTC (rev 3662) @@ -1,6 +1,7 @@ using NHibernate.DomainModel; using NHibernate.Criterion; using NHibernate.SqlCommand; +using NHibernate.SqlTypes; using NHibernate.Type; using NUnit.Framework; @@ -29,8 +30,11 @@ ISession session = factory.OpenSession(); IProjection expression = Projections.Avg("Pay"); CreateObjects(typeof(Simple), session); + IType nhType = NHibernateUtil.GuessType(typeof (double)); + SqlType[] sqlTypes = nhType.SqlTypes(this.factoryImpl); + string sqlTypeString = factoryImpl.Dialect.GetCastTypeName(sqlTypes[0]); SqlString sqlString = expression.ToSqlString(criteria, 0, criteriaQuery, new CollectionHelper.EmptyMapClass<string, IFilter>()); - string expectedSql = "avg(sql_alias.Pay) as y0_"; + string expectedSql = string.Format("avg(cast(sql_alias.Pay as {0})) as y0_",sqlTypeString); CompareSqlStrings(sqlString, expectedSql, 0); session.Close(); } @@ -175,4 +179,4 @@ session.Close(); } } -} \ No newline at end of file +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1393/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1393/Fixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1393/Fixture.cs 2008-07-25 05:09:20 UTC (rev 3662) @@ -0,0 +1,105 @@ +using System.Collections; +using NHibernate.Criterion; +using NHibernate.Dialect.Function; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH1393 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnTearDown() + { + base.OnTearDown(); + using (ISession session = OpenSession()) + { + using (ITransaction tx = session.BeginTransaction()) + { + session.Delete("from Person"); + tx.Commit(); + } + } + } + + protected override void OnSetUp() + { + using (ISession s = OpenSession()) + { + using (ITransaction tx = s.BeginTransaction()) + { + Person e1 = new Person("Joe", 10, 9); + Person e2 = new Person("Sally", 100, 8); + Person e3 = new Person("Tim", 20, 7); //20 + Person e4 = new Person("Fred", 40, 40); + Person e5 = new Person("Mike", 50, 50); + s.Save(e1); + s.Save(e2); + s.Save(e3); + s.Save(e4); + s.Save(e5); + tx.Commit(); + } + } + } + + [Test] + public void CanSumProjectionOnSqlFunction() + { + using (ISession s = OpenSession()) + { + ISQLFunction arithmaticAddition = new VarArgsSQLFunction("(", "+", ")"); + ICriteria c = + s.CreateCriteria(typeof (Person)).SetProjection( + Projections.Sum(Projections.SqlFunction(arithmaticAddition, NHibernateUtil.GuessType(typeof (double)), + Projections.Property("IQ"), Projections.Property("ShoeSize")))); + IList list = c.List(); + Assert.AreEqual(334, list[0]); + } + } + + [Test] + public void CanAvgProjectionOnSqlFunction() + { + using (ISession s = OpenSession()) + { + ISQLFunction arithmaticAddition = new VarArgsSQLFunction("(", "+", ")"); + ICriteria c = + s.CreateCriteria(typeof (Person)).SetProjection( + Projections.Avg(Projections.SqlFunction(arithmaticAddition, NHibernateUtil.GuessType(typeof (double)), + Projections.Property("IQ"), Projections.Property("ShoeSize")))); + IList list = c.List(); + Assert.AreEqual(((double) 334) / 5, list[0]); + } + } + + [Test] + public void CanMinProjectionOnIdentityProjection() + { + using (ISession s = OpenSession()) + { + ISQLFunction arithmaticAddition = new VarArgsSQLFunction("(", "+", ")"); + ICriteria c = + s.CreateCriteria(typeof (Person)).SetProjection( + Projections.Min(Projections.SqlFunction(arithmaticAddition, NHibernateUtil.GuessType(typeof (double)), + Projections.Property("IQ"), Projections.Property("ShoeSize")))); + IList list = c.List(); + Assert.AreEqual(19, list[0]); + } + } + + [Test] + public void CanMaxProjectionOnIdentityProjection() + { + using (ISession s = OpenSession()) + { + ISQLFunction arithmaticAddition = new VarArgsSQLFunction("(", "+", ")"); + ICriteria c = + s.CreateCriteria(typeof (Person)).SetProjection( + Projections.Max(Projections.SqlFunction(arithmaticAddition, NHibernateUtil.GuessType(typeof (double)), + Projections.Property("IQ"), Projections.Property("ShoeSize")))); + IList list = c.List(); + Assert.AreEqual(108, list[0]); + } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1393/Mappings.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1393/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1393/Mappings.hbm.xml 2008-07-25 05:09:20 UTC (rev 3662) @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.NHSpecificTest.NH1393"> + + <class name="Person" lazy="false"> + <id name="Id"> + <generator class="native" /> + </id> + <bag name="Pets" inverse="true" lazy="false" cascade="all-delete-orphan"> + <key column="PersonId" /> + <one-to-many class="Pet"/> + <filter name="ExampleFilter" condition=":WeightVal >= Weight" /> + </bag> + <property name="Name"/> + <property name="IQ"/> + <property name="ShoeSize"/> + </class> + + <class name="Pet" lazy="false"> + <id name="Id"> + <generator class="native" /> + </id> + <many-to-one name="Owner" column="PersonId" not-null="true"/> + <property name="Name"/> + <property name="Species"/> + <property name="Weight"/> + </class> + + <filter-def name="ExampleFilter"> + <filter-param name="WeightVal" type="int"/> + </filter-def> + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1393/Person.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1393/Person.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1393/Person.cs 2008-07-25 05:09:20 UTC (rev 3662) @@ -0,0 +1,105 @@ +using System.Collections; + +namespace NHibernate.Test.NHSpecificTest.NH1393 +{ + public class Person + { + private int id; + private int iq; + private string name; + private IList pets; + private int shoeSize; + + public Person() + { + pets = new ArrayList(); + } + + public Person(string name, int iq, int shoeSize) + { + this.name = name; + this.iq = iq; + this.shoeSize = shoeSize; + pets = new ArrayList(); + } + + public virtual int Id + { + get { return id; } + set { id = value; } + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual int IQ + { + get { return iq; } + set { iq = value; } + } + + public virtual int ShoeSize + { + get { return shoeSize; } + set { shoeSize = value; } + } + + public virtual IList Pets + { + get { return pets; } + protected set { pets = value; } + } + } + + public class Pet + { + private int id; + private string name; + private Person owner; + private string species; + private double weight; + + public Pet() {} + + public Pet(string name, string species, int weight, Person owner) + { + this.name = name; + this.species = species; + this.weight = weight; + this.owner = owner; + } + + public virtual int Id + { + get { return id; } + set { id = value; } + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual string Species + { + get { return species; } + set { species = value; } + } + + public virtual double Weight + { + get { return weight; } + set { weight = value; } + } + + public virtual Person Owner + { + get { return owner; } + set { owner = value; } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1394/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1394/Fixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1394/Fixture.cs 2008-07-25 05:09:20 UTC (rev 3662) @@ -0,0 +1,146 @@ +using System.Collections.Generic; +using NHibernate.Criterion; +using NHibernate.Dialect.Function; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH1394 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnTearDown() + { + base.OnTearDown(); + using (ISession session = OpenSession()) + { + using (ITransaction tx = session.BeginTransaction()) + { + session.Delete("from Person"); + tx.Commit(); + } + } + } + + protected override void OnSetUp() + { + using (ISession s = OpenSession()) + { + using (ITransaction tx = s.BeginTransaction()) + { + Person e1 = new Person("Joe", 10, 9); + Person e2 = new Person("Sally", 100, 8); + Person e3 = new Person("Tim", 20, 7); //20 + Person e4 = new Person("Fred", 40, 40); + Person e5 = new Person("Mike", 50, 50); + s.Save(e1); + s.Save(e2); + s.Save(e3); + s.Save(e4); + s.Save(e5); + Pet p0 = new Pet("Fido", "Dog", 25, e1); + Pet p1 = new Pet("Biff", "Dog", 9, e1); + Pet p2 = new Pet("Pasha", "Dog", 25, e2); + Pet p3 = new Pet("Lord", "Dog", 10, e2); + Pet p4 = new Pet("Max", "Dog", 25, e3); + Pet p5 = new Pet("Min", "Dog", 8, e3); + s.Save(p0); + s.Save(p1); + s.Save(p2); + s.Save(p3); + s.Save(p4); + s.Save(p5); + tx.Commit(); + } + } + } + + [Test] + public void CanOrderByPropertyProjection() + { + using (ISession s = OpenSession()) + { + ICriteria c = s.CreateCriteria(typeof (Person)).AddOrder(Order.Desc(Projections.Property("IQ"))); + IList<Person> list = c.List<Person>(); + + for (int i = 0; i < list.Count - 1; i++) + { + Assert.IsTrue(list[i].IQ >= list[i + 1].IQ); + } + } + } + + [Test] + public void CanOrderBySubqueryProjection() + { + using (ISession s = OpenSession()) + { + DetachedCriteria dc = DetachedCriteria.For<Person>("sub"); + dc.CreateCriteria("Pets", "pets").SetProjection(Projections.Min("pets.Weight")).Add( + Restrictions.EqProperty("this.Id", "sub.Id")); + + ICriteria c = s.CreateCriteria(typeof (Person)).AddOrder(Order.Asc(Projections.SubQuery(dc))); + IList<Person> list = c.List<Person>(); + + Assert.AreEqual(list[2].Name, "Tim"); + Assert.AreEqual(list[3].Name, "Joe"); + Assert.AreEqual(list[4].Name, "Sally"); + } + } + + [Test] + public void CanOrderBySubqueryProjectionDesc() + { + using (ISession s = OpenSession()) + { + DetachedCriteria dc = DetachedCriteria.For<Person>("sub"); + dc.CreateCriteria("Pets", "pets").SetProjection(Projections.Min("pets.Weight")).Add( + Restrictions.EqProperty("this.Id", "sub.Id")); + + ICriteria c = s.CreateCriteria(typeof (Person)).AddOrder(Order.Desc(Projections.SubQuery(dc))); + IList<Person> list = c.List<Person>(); + + Assert.AreEqual(list[2].Name, "Tim"); + Assert.AreEqual(list[1].Name, "Joe"); + Assert.AreEqual(list[0].Name, "Sally"); + } + } + + [Test] + public void CanOrderBySqlProjectionAsc() + { + using (ISession s = OpenSession()) + { + ISQLFunction arithmaticAddition = new VarArgsSQLFunction("(", "+", ")"); + ICriteria c = + s.CreateCriteria(typeof (Person)).AddOrder( + Order.Asc(Projections.SqlFunction(arithmaticAddition, NHibernateUtil.GuessType(typeof (double)), + Projections.Property("IQ"), Projections.Property("ShoeSize")))); + IList<Person> list = c.List<Person>(); + + for (int i = 0; i < list.Count - 1; i++) + { + Assert.IsTrue(list[i].IQ + list[i].ShoeSize <= list[i + 1].IQ + list[i + 1].ShoeSize); + } + } + } + + [Test] + public void CanOrderBySqlProjectionDesc() + { + using (ISession s = OpenSession()) + { + ISQLFunction arithmaticAddition = new VarArgsSQLFunction("(", "+", ")"); + ICriteria c = + s.CreateCriteria(typeof (Person)).AddOrder( + Order.Desc(Projections.SqlFunction(arithmaticAddition, NHibernateUtil.GuessType(typeof (double)), + Projections.Property("IQ"), Projections.Property("ShoeSize")))); + IList<Person> list = c.List<Person>(); + + for (int i = 0; i < list.Count - 1; i++) + { + Assert.IsTrue(list[i].IQ + list[i].ShoeSize >= list[i + 1].IQ + list[i + 1].ShoeSize); + } + } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1394/Mappings.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1394/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1394/Mappings.hbm.xml 2008-07-25 05:09:20 UTC (rev 3662) @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.NHSpecificTest.NH1394"> + + <class name="Person" lazy="false"> + <id name="Id"> + <generator class="native" /> + </id> + <bag name="Pets" inverse="true" lazy="false" cascade="all-delete-orphan"> + <key column="PersonId" /> + <one-to-many class="Pet"/> + <filter name="ExampleFilter" condition=":WeightVal >= Weight" /> + </bag> + <property name="Name"/> + <property name="IQ"/> + <property name="ShoeSize"/> + </class> + + <class name="Pet" lazy="false"> + <id name="Id"> + <generator class="native" /> + </id> + <many-to-one name="Owner" column="PersonId" not-null="true"/> + <property name="Name"/> + <property name="Species"/> + <property name="Weight"/> + </class> + + <filter-def name="ExampleFilter"> + <filter-param name="WeightVal" type="int"/> + </filter-def> + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1394/Person.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1394/Person.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1394/Person.cs 2008-07-25 05:09:20 UTC (rev 3662) @@ -0,0 +1,105 @@ +using System.Collections; + +namespace NHibernate.Test.NHSpecificTest.NH1394 +{ + public class Person + { + private int id; + private int iq; + private string name; + private IList pets; + private int shoeSize; + + public Person() + { + pets = new ArrayList(); + } + + public Person(string name, int iq, int shoeSize) + { + this.name = name; + this.iq = iq; + this.shoeSize = shoeSize; + pets = new ArrayList(); + } + + public virtual int Id + { + get { return id; } + set { id = value; } + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual int IQ + { + get { return iq; } + set { iq = value; } + } + + public virtual int ShoeSize + { + get { return shoeSize; } + set { shoeSize = value; } + } + + public virtual IList Pets + { + get { return pets; } + protected set { pets = value; } + } + } + + public class Pet + { + private int id; + private string name; + private Person owner; + private string species; + private double weight; + + public Pet() {} + + public Pet(string name, string species, int weight, Person owner) + { + this.name = name; + this.species = species; + this.weight = weight; + this.owner = owner; + } + + public virtual int Id + { + get { return id; } + set { id = value; } + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual string Species + { + get { return species; } + set { species = value; } + } + + public virtual double Weight + { + get { return weight; } + set { weight = value; } + } + + public virtual Person Owner + { + get { return owner; } + set { owner = value; } + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-25 04:52:55 UTC (rev 3661) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-25 05:09:20 UTC (rev 3662) @@ -395,6 +395,10 @@ <Compile Include="NHSpecificTest\NH1355\Category.cs" /> <Compile Include="NHSpecificTest\NH1355\CustomVersionType.cs" /> <Compile Include="NHSpecificTest\NH1355\UserTypeTimestamp.cs" /> + <Compile Include="NHSpecificTest\NH1393\Fixture.cs" /> + <Compile Include="NHSpecificTest\NH1393\Person.cs" /> + <Compile Include="NHSpecificTest\NH1394\Fixture.cs" /> + <Compile Include="NHSpecificTest\NH1394\Person.cs" /> <Compile Include="NHSpecificTest\NH1399\Fixture.cs" /> <Compile Include="NHSpecificTest\NH1403\Female.cs" /> <Compile Include="NHSpecificTest\NH1403\Fixture.cs" /> @@ -1381,6 +1385,8 @@ <EmbeddedResource Include="Any\Person.hbm.xml" /> <EmbeddedResource Include="Any\Properties.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="NHSpecificTest\NH1393\Mappings.hbm.xml" /> + <EmbeddedResource Include="NHSpecificTest\NH1394\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1405\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1403\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1253\Mappings.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-07-25 19:38:20
|
Revision: 3667 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3667&view=rev Author: fabiomaulo Date: 2008-07-25 19:38:27 +0000 (Fri, 25 Jul 2008) Log Message: ----------- Merge r3666 (fix NH-1412- Fix NH-1304) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/Property.cs trunk/nhibernate/src/NHibernate/Properties/BackrefPropertyAccessor.cs trunk/nhibernate/src/NHibernate/Properties/BasicPropertyAccessor.cs trunk/nhibernate/src/NHibernate/Properties/ChainedPropertyAccessor.cs trunk/nhibernate/src/NHibernate/Properties/EmbeddedPropertyAccessor.cs trunk/nhibernate/src/NHibernate/Properties/FieldAccessor.cs trunk/nhibernate/src/NHibernate/Properties/IPropertyAccessor.cs trunk/nhibernate/src/NHibernate/Properties/IndexPropertyAccessor.cs trunk/nhibernate/src/NHibernate/Properties/MapAccessor.cs trunk/nhibernate/src/NHibernate/Properties/NoSetterAccessor.cs trunk/nhibernate/src/NHibernate/Properties/NoopAccessor.cs trunk/nhibernate/src/NHibernate/Tuple/Component/AbstractComponentTuplizer.cs trunk/nhibernate/src/NHibernate/Tuple/Entity/AbstractEntityTuplizer.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH251/CustomAccessDO.cs Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1304/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1304/Funny.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/Property.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/Property.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate/Mapping/Property.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -189,7 +189,8 @@ public virtual bool IsBasicPropertyAccessor { - get { return propertyAccessorName == null || propertyAccessorName.Equals("property"); } + // NH Different behavior : see IPropertyAccessor.CanAccessTroughReflectionOptimizer (ref. NH-1304) + get { return PropertyAccessor.CanAccessTroughReflectionOptimizer; } } public IDictionary<string, MetaAttribute> MetaAttributes Modified: trunk/nhibernate/src/NHibernate/Properties/BackrefPropertyAccessor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Properties/BackrefPropertyAccessor.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate/Properties/BackrefPropertyAccessor.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -30,6 +30,11 @@ return new BackrefSetter(); } + public bool CanAccessTroughReflectionOptimizer + { + get { return false; } + } + #endregion /// <summary> The Setter implementation for id backrefs.</summary> Modified: trunk/nhibernate/src/NHibernate/Properties/BasicPropertyAccessor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Properties/BasicPropertyAccessor.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate/Properties/BasicPropertyAccessor.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -60,6 +60,11 @@ return result; } + public bool CanAccessTroughReflectionOptimizer + { + get { return true; } + } + #endregion /// <summary> @@ -346,4 +351,4 @@ } } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Properties/ChainedPropertyAccessor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Properties/ChainedPropertyAccessor.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate/Properties/ChainedPropertyAccessor.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -48,6 +48,11 @@ throw new PropertyNotFoundException(theClass, propertyName, "setter"); } + public bool CanAccessTroughReflectionOptimizer + { + get { return false; } + } + #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Properties/EmbeddedPropertyAccessor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Properties/EmbeddedPropertyAccessor.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate/Properties/EmbeddedPropertyAccessor.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -19,6 +19,11 @@ return new EmbeddedSetter(theClass); } + public bool CanAccessTroughReflectionOptimizer + { + get { return false; } + } + #endregion [Serializable] Modified: trunk/nhibernate/src/NHibernate/Properties/FieldAccessor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Properties/FieldAccessor.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate/Properties/FieldAccessor.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -86,6 +86,11 @@ return new FieldSetter(GetField(theClass, fieldName), theClass, fieldName); } + public bool CanAccessTroughReflectionOptimizer + { + get { return true; } + } + #endregion private static FieldInfo GetField(System.Type type, string fieldName, System.Type originalType) @@ -315,4 +320,4 @@ } } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Properties/IPropertyAccessor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Properties/IPropertyAccessor.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate/Properties/IPropertyAccessor.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -1,5 +1,3 @@ -using System; - namespace NHibernate.Properties { /// <summary> @@ -36,5 +34,12 @@ /// be found in the <see cref="System.Type"/>. /// </exception> ISetter GetSetter(System.Type theClass, string propertyName); + + #region NH specific + /// <summary> + /// Allow embedded and custom accessors to define if the ReflectionOptimizer can be used. + /// </summary> + bool CanAccessTroughReflectionOptimizer { get;} + #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Properties/IndexPropertyAccessor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Properties/IndexPropertyAccessor.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate/Properties/IndexPropertyAccessor.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -32,6 +32,11 @@ throw new NotImplementedException(); } + public bool CanAccessTroughReflectionOptimizer + { + get { return false; } + } + #endregion /// <summary> The Setter implementation for index backrefs.</summary> Modified: trunk/nhibernate/src/NHibernate/Properties/MapAccessor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Properties/MapAccessor.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate/Properties/MapAccessor.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -18,6 +18,11 @@ return new MapSetter(propertyName); } + public bool CanAccessTroughReflectionOptimizer + { + get { return false; } + } + #endregion public sealed class MapSetter : ISetter Modified: trunk/nhibernate/src/NHibernate/Properties/NoSetterAccessor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Properties/NoSetterAccessor.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate/Properties/NoSetterAccessor.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -66,6 +66,11 @@ return new FieldAccessor.FieldSetter(FieldAccessor.GetField(type, fieldName), type, fieldName); } + public bool CanAccessTroughReflectionOptimizer + { + get { return true; } + } + #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Properties/NoopAccessor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Properties/NoopAccessor.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate/Properties/NoopAccessor.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -19,6 +19,11 @@ return new NoopSetter(); } + public bool CanAccessTroughReflectionOptimizer + { + get { return false; } + } + #endregion /// <summary> A Getter which will always return null. It should not be called anyway.</summary> Modified: trunk/nhibernate/src/NHibernate/Tuple/Component/AbstractComponentTuplizer.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Tuple/Component/AbstractComponentTuplizer.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate/Tuple/Component/AbstractComponentTuplizer.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -1,4 +1,5 @@ using System; +using log4net; using NHibernate.Engine; using NHibernate.Properties; @@ -8,6 +9,8 @@ [Serializable] public abstract class AbstractComponentTuplizer : IComponentTuplizer { + private static readonly ILog log = LogManager.GetLogger(typeof(AbstractComponentTuplizer)); + protected internal int propertySpan; protected internal IGetter[] getters; protected internal ISetter[] setters; @@ -32,6 +35,11 @@ } i++; } + if (log.IsDebugEnabled) + { + log.DebugFormat("{0} accessors found for component: {1}", foundCustomAccessor ? "Custom" : "No custom", + component.ComponentClassName); + } hasCustomAccessors = foundCustomAccessor; // Only to be secure that we can access to every things Modified: trunk/nhibernate/src/NHibernate/Tuple/Entity/AbstractEntityTuplizer.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Tuple/Entity/AbstractEntityTuplizer.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate/Tuple/Entity/AbstractEntityTuplizer.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -1,5 +1,6 @@ using System.Collections; using Iesi.Collections.Generic; +using log4net; using NHibernate.Engine; using NHibernate.Id; using NHibernate.Intercept; @@ -13,6 +14,7 @@ /// <summary> Support for tuplizers relating to entities. </summary> public abstract class AbstractEntityTuplizer : IEntityTuplizer { + private static readonly ILog log = LogManager.GetLogger(typeof(AbstractEntityTuplizer)); private readonly EntityMetamodel entityMetamodel; private readonly IGetter idGetter; private readonly ISetter idSetter; @@ -58,6 +60,11 @@ foundCustomAccessor = true; i++; } + if (log.IsDebugEnabled) + { + log.DebugFormat("{0} accessors found for entity: {1}", foundCustomAccessor ? "Custom" : "No custom", + mappingInfo.EntityName); + } hasCustomAccessors = foundCustomAccessor; instantiator = BuildInstantiator(mappingInfo); Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1304/Funny.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1304/Funny.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1304/Funny.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -0,0 +1,113 @@ +namespace NHibernate.Test.NHSpecificTest.NH1304 +{ + public class Funny + { + private int id; + private string field; + private string fieldCamelcase; + private string _fieldCamelcaseUnderscore; + private string fieldlowercase; + private string _fieldlowercaseunderscore; + private string _FieldPascalcaseUnderscore; + private string m_FieldPascalcaseMUnderscore; + private string mFieldPascalcaseM; +#pragma warning disable 649 + private string nosetterCamelcase; + private string _nosetterCamelcaseUnderscore; + private string nosetterlowercase; + private string _nosetterlowercaseunderscore; + private string _NosetterPascalcaseUnderscore; + private string m_NosetterPascalcaseMUnderscore; + private string mNosetterPascalcase; +#pragma warning restore 649 + + public virtual int Id + { + get { return id; } + set { id = value; } + } + + public virtual string Field + { + get { return field; } + set { field = value; } + } + + public virtual string FieldCamelcase + { + get { return fieldCamelcase; } + set { fieldCamelcase = value; } + } + + public virtual string FieldCamelcaseUnderscore + { + get { return _fieldCamelcaseUnderscore; } + set { _fieldCamelcaseUnderscore = value; } + } + + public virtual string FieldLowercase + { + get { return fieldlowercase; } + set { fieldlowercase = value; } + } + + public virtual string FieldLowercaseUnderscore + { + get { return _fieldlowercaseunderscore; } + set { _fieldlowercaseunderscore = value; } + } + + public virtual string FieldPascalcaseUnderscore + { + get { return _FieldPascalcaseUnderscore; } + set { _FieldPascalcaseUnderscore = value; } + } + + public virtual string FieldPascalcaseMUnderscore + { + get { return m_FieldPascalcaseMUnderscore; } + set { m_FieldPascalcaseMUnderscore = value; } + } + + public virtual string FieldPascalcaseM + { + get { return mFieldPascalcaseM; } + set { mFieldPascalcaseM = value; } + } + + public virtual string NosetterCamelcase + { + get { return nosetterCamelcase; } + } + + public virtual string NosetterCamelcaseUnderscore + { + get { return _nosetterCamelcaseUnderscore; } + } + + public virtual string NosetterLowercase + { + get { return nosetterlowercase; } + } + + public virtual string NosetterLowercaseUnderscore + { + get { return _nosetterlowercaseunderscore; } + } + + public virtual string NosetterPascalcaseUnderscore + { + get { return _NosetterPascalcaseUnderscore; } + } + + public virtual string NosetterPascalcaseMUnderscore + { + get { return m_NosetterPascalcaseMUnderscore; } + } + + public virtual string NosetterPascalcase + { + get { return mNosetterPascalcase; } + } + } +} Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH251/CustomAccessDO.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH251/CustomAccessDO.cs 2008-07-25 19:08:39 UTC (rev 3666) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH251/CustomAccessDO.cs 2008-07-25 19:38:27 UTC (rev 3667) @@ -53,6 +53,11 @@ return new CustomSetter(propertyName); } + public bool CanAccessTroughReflectionOptimizer + { + get { return false; } + } + public class CustomGetter : IGetter { private System.Type theClass; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-07-25 19:46:10
|
Revision: 3669 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3669&view=rev Author: fabiomaulo Date: 2008-07-25 19:46:18 +0000 (Fri, 25 Jul 2008) Log Message: ----------- Merge r3668 (minor) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs trunk/nhibernate/src/NHibernate/Mapping/RootClass.cs trunk/nhibernate/src/NHibernate/WrongClassException.cs trunk/nhibernate/src/NHibernate.Test/JoinedSubclass/JoinedSubclassFixture.cs trunk/nhibernate/src/NHibernate.Test/Subclass/SubclassFixture.cs Modified: trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2008-07-25 19:43:07 UTC (rev 3668) +++ trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2008-07-25 19:46:18 UTC (rev 3669) @@ -22,7 +22,7 @@ namespace NHibernate.Dialect { /// <summary> - /// Represents a dialect of SQL implemented by a particular RDBMS. Sublcasses + /// Represents a dialect of SQL implemented by a particular RDBMS. Subclasses /// implement NHibernate compatibility with different systems. /// </summary> /// <remarks> Modified: trunk/nhibernate/src/NHibernate/Mapping/RootClass.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/RootClass.cs 2008-07-25 19:43:07 UTC (rev 3668) +++ trunk/nhibernate/src/NHibernate/Mapping/RootClass.cs 2008-07-25 19:46:18 UTC (rev 3669) @@ -10,7 +10,7 @@ { /// <summary> /// Declaration of a System.Type mapped with the <c><class></c> element that - /// is the root class of a table-per-sublcass, or table-per-concrete-class + /// is the root class of a table-per-subclass, or table-per-concrete-class /// inheritance heirarchy. /// </summary> [Serializable] Modified: trunk/nhibernate/src/NHibernate/WrongClassException.cs =================================================================== --- trunk/nhibernate/src/NHibernate/WrongClassException.cs 2008-07-25 19:43:07 UTC (rev 3668) +++ trunk/nhibernate/src/NHibernate/WrongClassException.cs 2008-07-25 19:46:18 UTC (rev 3669) @@ -51,7 +51,7 @@ { get { - return string.Format("Object with id: {0} was not of the specified sublcass: {1} ({2})", identifier, entityName, base.Message); + return string.Format("Object with id: {0} was not of the specified subclass: {1} ({2})", identifier, entityName, base.Message); } } @@ -96,4 +96,4 @@ #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate.Test/JoinedSubclass/JoinedSubclassFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/JoinedSubclass/JoinedSubclassFixture.cs 2008-07-25 19:43:07 UTC (rev 3668) +++ trunk/nhibernate/src/NHibernate.Test/JoinedSubclass/JoinedSubclassFixture.cs 2008-07-25 19:46:18 UTC (rev 3669) @@ -210,7 +210,7 @@ person = (Person) s.Load(typeof(Person), personId); // the object with id=2 was loaded using the base class - lets make sure it actually loaded - // the sublcass + // the subclass Assert.AreEqual(typeof(Employee), empAsPerson.GetType(), "even though person was queried, should have returned correct subclass."); emp = (Employee) s.Load(typeof(Employee), empId); @@ -266,4 +266,4 @@ s.Close(); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate.Test/Subclass/SubclassFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Subclass/SubclassFixture.cs 2008-07-25 19:43:07 UTC (rev 3668) +++ trunk/nhibernate/src/NHibernate.Test/Subclass/SubclassFixture.cs 2008-07-25 19:46:18 UTC (rev 3669) @@ -64,7 +64,7 @@ SubclassAssert.AreEqual(base1, base2); // the object with id=2 was loaded using the base class - lets make sure it actually loaded - // the sublcass + // the subclass SubclassOne one2 = oneBase2 as SubclassOne; Assert.IsNotNull(one2); @@ -160,4 +160,4 @@ s.Close(); } } -} \ No newline at end of file +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-07-25 23:55:37
|
Revision: 3672 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3672&view=rev Author: fabiomaulo Date: 2008-07-25 23:55:46 +0000 (Fri, 25 Jul 2008) Log Message: ----------- Fix NH-1413 Note: Thanks to Ciprian Sabolovits for let us know that we are releasing a dialect with more bugs than trunk version, before NH2.0.0RC1; Thanks again. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/Foo.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs Modified: trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs 2008-07-25 23:37:55 UTC (rev 3671) +++ trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs 2008-07-25 23:55:46 UTC (rev 3672) @@ -1,15 +1,15 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Text; +using System.Text.RegularExpressions; +using NHibernate.Mapping; +using NHibernate.SqlCommand; +using NHibernate.Util; + namespace NHibernate.Dialect { - using System; - using System.Collections; - using System.Collections.Generic; - using System.Data; - using System.Text.RegularExpressions; - using System.Text; - using Mapping; - using SqlCommand; - using Util; - public class MsSql2005Dialect : MsSql2000Dialect { public MsSql2005Dialect() @@ -66,14 +66,11 @@ sortExpressions = new string[] { "CURRENT_TIMESTAMP" }; } - SqlStringBuilder result = new SqlStringBuilder() - .Add("SELECT TOP ") - .Add(last.ToString()) - .Add(" ") - .Add(StringHelper.Join(", ", columnsOrAliases)) - .Add(" FROM (SELECT ROW_NUMBER() OVER(ORDER BY "); + SqlStringBuilder result = + new SqlStringBuilder().Add("SELECT TOP ").Add(last.ToString()).Add(" ").Add(StringHelper.Join(", ", columnsOrAliases)) + .Add(" FROM (SELECT ROW_NUMBER() OVER(ORDER BY "); - AppendSortExpressions(columnsOrAliases, sortExpressions, result); + AppendSortExpressions(columnsOrAliases, sortExpressions, result); result.Add(") as row, "); @@ -82,44 +79,39 @@ result.Add("query.").Add(columnsOrAliases[i]); bool notLastColumn = i != columnsOrAliases.Count - 1; if (notLastColumn) + { result.Add(", "); + } } for (int i = 0; i < sortExpressions.Length; i++) { string sortExpression = RemoveSortOrderDirection(sortExpressions[i]); - if(!columnsOrAliases.Contains(sortExpression)) + if (!columnsOrAliases.Contains(sortExpression)) { - result.Add(", query.__hibernate_sort_expr_") - .Add(i.ToString()) - .Add("__"); + result.Add(", query.__hibernate_sort_expr_").Add(i.ToString()).Add("__"); } } - result.Add(" FROM (") - .Add(select); + result.Add(" FROM (").Add(select); for (int i = 0; i < sortExpressions.Length; i++) { string sortExpression = RemoveSortOrderDirection(sortExpressions[i]); - if(columnsOrAliases.Contains(sortExpression)) + if (columnsOrAliases.Contains(sortExpression)) + { continue; - + } + if (aliasToColumn.ContainsKey(sortExpression)) + { sortExpression = aliasToColumn[sortExpression]; + } - result.Add(", ") - .Add(sortExpression) - .Add(" as __hibernate_sort_expr_") - .Add(i.ToString()) - .Add("__"); + result.Add(", ").Add(sortExpression).Add(" as __hibernate_sort_expr_").Add(i.ToString()).Add("__"); } - result.Add(" ") - .Add(from) - .Add(") query ) page WHERE page.row > ") - .Add(offset.ToString()) - .Add(" ORDER BY "); + result.Add(" ").Add(from).Add(") query ) page WHERE page.row > ").Add(offset.ToString()).Add(" ORDER BY "); AppendSortExpressions(columnsOrAliases, sortExpressions, result); @@ -132,26 +124,29 @@ return Regex.Replace(sortExpression.Trim(), @"(\)|\s)(?i:asc|desc)$", "$1").Trim(); } - private static void AppendSortExpressions(ICollection<string> columnsOrAliases, string[] sortExpressions, SqlStringBuilder result) + private static void AppendSortExpressions(ICollection<string> columnsOrAliases, string[] sortExpressions, + SqlStringBuilder result) { for (int i = 0; i < sortExpressions.Length; i++) { - if(i > 1) + if (i > 0) + { result.Add(", "); + } string sortExpression = RemoveSortOrderDirection(sortExpressions[i]); - if(columnsOrAliases.Contains(sortExpression)) + if (columnsOrAliases.Contains(sortExpression)) { result.Add(sortExpression); } else { - result.Add("__hibernate_sort_expr_") - .Add(i.ToString()) - .Add("__"); + result.Add("__hibernate_sort_expr_").Add(i.ToString()).Add("__"); } if (sortExpressions[i].Trim().ToLower().EndsWith("desc")) + { result.Add(" DESC"); + } } } @@ -166,9 +161,8 @@ return fromIndex; } - private static void ExtractColumnOrAliasNames(SqlString select, - out List<string> columnsOrAliases, - out Dictionary<string, string> aliasToColumn) + private static void ExtractColumnOrAliasNames(SqlString select, out List<string> columnsOrAliases, + out Dictionary<string, string> aliasToColumn) { columnsOrAliases = new List<string>(); aliasToColumn = new Dictionary<string, string>(); @@ -181,19 +175,26 @@ index += 1; if ("select".Equals(token, StringComparison.InvariantCultureIgnoreCase)) + { continue; + } if ("distinct".Equals(token, StringComparison.InvariantCultureIgnoreCase)) + { continue; + } if ("," == token) + { continue; + } if ("from".Equals(token, StringComparison.InvariantCultureIgnoreCase)) + { break; + } //handle composite expressions like 2 * 4 as foo - while (index < tokens.Count && - "as".Equals(tokens[index], StringComparison.InvariantCultureIgnoreCase) == false && - "," != tokens[index]) + while (index < tokens.Count && "as".Equals(tokens[index], StringComparison.InvariantCultureIgnoreCase) == false + && "," != tokens[index]) { token = token + " " + tokens[index]; index += 1; @@ -208,13 +209,14 @@ { int dot = token.IndexOf('.'); if (dot != -1) + { alias = token.Substring(dot + 1); + } } // notice! we are checking here the existence of "as" "alias", two // tokens from the current one - if (index + 1 < tokens.Count && - "as".Equals(tokens[index], StringComparison.InvariantCultureIgnoreCase)) + if (index + 1 < tokens.Count && "as".Equals(tokens[index], StringComparison.InvariantCultureIgnoreCase)) { alias = tokens[index + 1]; index += 2; //skip the "as" and the alias \ @@ -232,10 +234,7 @@ /// <value><c>true</c></value> public override bool SupportsLimit { - get - { - return true; - } + get { return true; } } /// <summary> @@ -245,23 +244,24 @@ /// <value><c>true</c></value> public override bool SupportsLimitOffset { - get - { - return true; - } + get { return true; } } protected override string GetSelectExistingObject(string name, Table table) { string schema = table.GetQuotedSchemaName(this); - if (schema != null) schema += "."; + if (schema != null) + { + schema += "."; + } string objName = string.Format("{0}{1}", schema, Quote(name)); string parentName = string.Format("{0}{1}", schema, table.GetQuotedName(this)); - return string.Format("select 1 from sys.objects where object_id = OBJECT_ID(N'{0}') AND parent_object_id = OBJECT_ID('{1}')", - objName, parentName); + return + string.Format( + "select 1 from sys.objects where object_id = OBJECT_ID(N'{0}') AND parent_object_id = OBJECT_ID('{1}')", objName, + parentName); } - /// <summary> /// Sql Server 2005 supports a query statement that provides <c>LIMIT</c> /// functionality with an offset. @@ -269,10 +269,7 @@ /// <value><c>false</c></value> public override bool UseMaxForLimit { - get - { - return false; - } + get { return false; } } /// <summary> @@ -376,7 +373,7 @@ currentToken.Length = 0; state = TokenizerState.WhiteSpace; } - else if (ch == ',')// stop current token, and send the , as well + else if (ch == ',') // stop current token, and send the , as well { yield return currentToken.ToString(); currentToken.Length = 0; @@ -404,7 +401,9 @@ } } if (currentToken.Length > 0) + { yield return currentToken.ToString(); + } } public IEnumerator GetEnumerator() @@ -426,4 +425,4 @@ } } } -} +} \ No newline at end of file Copied: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/Foo.cs (from rev 3671, branches/2.0.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/Foo.cs) =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/Foo.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/Foo.cs 2008-07-25 23:55:46 UTC (rev 3672) @@ -0,0 +1,44 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.NH1413 +{ + public class Foo + { + private DateTime birthDate; + private string name; + private long oid; + private int version; + + public Foo() {} + + public Foo(string name, DateTime birthDate) + { + this.name = name; + this.birthDate = birthDate; + } + + public virtual long Oid + { + get { return oid; } + set { oid = value; } + } + + public virtual int Version + { + get { return version; } + set { version = value; } + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual DateTime BirthDate + { + get { return birthDate; } + set { birthDate = value; } + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/Foo.cs ___________________________________________________________________ Added: svn:mergeinfo + Copied: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/Mappings.hbm.xml (from rev 3671, branches/2.0.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/Mappings.hbm.xml) =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/Mappings.hbm.xml 2008-07-25 23:55:46 UTC (rev 3672) @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.NHSpecificTest.NH1413"> + + <class name="Foo" table="XFoos"> + <id name="Oid" column="ID"> + <generator class="identity"/> + </id> + + <version name="Version" column="Version" /> + + <property name="Name" column="Name" type="String(25)" /> + <property name="BirthDate" column="BirthDate" /> + + </class> + +</hibernate-mapping> Property changes on: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/Mappings.hbm.xml ___________________________________________________________________ Added: svn:mergeinfo + Copied: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs (from rev 3671, branches/2.0.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs) =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs 2008-07-25 23:55:46 UTC (rev 3672) @@ -0,0 +1,43 @@ +using System; +using NHibernate.Criterion; +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; + +namespace NHibernate.Test.NHSpecificTest.NH1413 +{ + [TestFixture] + public class PagingTest : BugTestCase + { + [Test] + public void Bug() + { + using(ISession session = OpenSession()) + using(ITransaction t = session.BeginTransaction()) + { + session.Persist(new Foo("Foo1", DateTime.Today.AddDays(5))); + session.Persist(new Foo("Foo2", DateTime.Today.AddDays(1))); + session.Persist(new Foo("Foo3", DateTime.Today.AddDays(3))); + t.Commit(); + } + + DetachedCriteria criteria = DetachedCriteria.For(typeof (Foo)); + criteria.Add(Restrictions.Like("Name", "Foo", MatchMode.Start)); + criteria.AddOrder(Order.Desc("Name")); + criteria.AddOrder(Order.Asc("BirthDate")); + using (ISession session = OpenSession()) + { + ICriteria icriteria = criteria.GetExecutableCriteria(session); + icriteria.SetFirstResult(0); + icriteria.SetMaxResults(2); + Assert.That(2, Is.EqualTo(icriteria.List<Foo>().Count)); + } + + using (ISession session = OpenSession()) + using (ITransaction t = session.BeginTransaction()) + { + session.Delete("from Foo"); + t.Commit(); + } + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs ___________________________________________________________________ Added: svn:mergeinfo + Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-25 23:37:55 UTC (rev 3671) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-25 23:55:46 UTC (rev 3672) @@ -413,6 +413,8 @@ <Compile Include="NHSpecificTest\NH1408\DbResourceKey.cs" /> <Compile Include="NHSpecificTest\NH1408\DetachedSubCriteriaTest.cs" /> <Compile Include="NHSpecificTest\NH1408\Entity.cs" /> + <Compile Include="NHSpecificTest\NH1413\Foo.cs" /> + <Compile Include="NHSpecificTest\NH1413\PagingTest.cs" /> <Compile Include="NHSpecificTest\NH280\Fixture.cs" /> <Compile Include="NHSpecificTest\NH280\Foo.cs" /> <Compile Include="NHSpecificTest\NH1018\Employee.cs" /> @@ -1391,6 +1393,7 @@ <EmbeddedResource Include="Any\Person.hbm.xml" /> <EmbeddedResource Include="Any\Properties.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="NHSpecificTest\NH1413\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1304\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1408\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1393\Mappings.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dar...@us...> - 2008-08-06 17:44:37
|
Revision: 3696 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3696&view=rev Author: darioquintana Date: 2008-08-06 17:44:45 +0000 (Wed, 06 Aug 2008) Log Message: ----------- -3.5 sln can build with some supress warnings (618,612) at NHibernate.Test-3.5.csproj -missed file added. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/NHibernate-3.5.csproj trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-3.5.csproj Modified: trunk/nhibernate/src/NHibernate/NHibernate-3.5.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate-3.5.csproj 2008-08-02 04:50:33 UTC (rev 3695) +++ trunk/nhibernate/src/NHibernate/NHibernate-3.5.csproj 2008-08-06 17:44:45 UTC (rev 3696) @@ -2,7 +2,7 @@ <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProductVersion>9.0.21022</ProductVersion> + <ProductVersion>9.0.30428</ProductVersion> <SchemaVersion>2.0</SchemaVersion> <ProjectGuid>{5909BFE7-93CF-4E5F-BE22-6293368AF01D}</ProjectGuid> <OutputType>Library</OutputType> @@ -1033,6 +1033,7 @@ <Compile Include="Type\AnsiCharType.cs" /> <Compile Include="Type\AnyType.cs" /> <Compile Include="Type\AbstractCharType.cs" /> + <Compile Include="Type\ClassMetaType.cs" /> <Compile Include="Type\CollectionType.cs" /> <Compile Include="Type\CustomCollectionType.cs" /> <Compile Include="Type\EmbeddedComponentType.cs" /> Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-3.5.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-3.5.csproj 2008-08-02 04:50:33 UTC (rev 3695) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-3.5.csproj 2008-08-06 17:44:45 UTC (rev 3696) @@ -2,7 +2,7 @@ <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProductVersion>9.0.21022</ProductVersion> + <ProductVersion>9.0.30428</ProductVersion> <SchemaVersion>2.0</SchemaVersion> <ProjectGuid>{7AEE5B37-C552-4E59-9B6F-88755BCB5070}</ProjectGuid> <OutputType>Library</OutputType> @@ -27,6 +27,7 @@ <WarningLevel>4</WarningLevel> <UseVSHostingProcess>false</UseVSHostingProcess> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> + <NoWarn>618,612</NoWarn> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <DebugType>pdbonly</DebugType> @@ -1345,4 +1346,4 @@ if exist "$(ProjectDir)hibernate.cfg.xml" (copy "$(ProjectDir)hibernate.cfg.xml" "hibernate.cfg.xml") copy /y "..\..\..\NHibernate.DomainModel\ABC.hbm.xml" "ABC.hbm.xml"</PostBuildEvent> </PropertyGroup> -</Project> +</Project> \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-08-13 14:59:15
|
Revision: 3701 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3701&view=rev Author: fabiomaulo Date: 2008-08-13 14:59:18 +0000 (Wed, 13 Aug 2008) Log Message: ----------- Support of parametrs in HQLFunctions (by Ricardo Stuven) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Criterion/SqlFunctionProjection.cs trunk/nhibernate/src/NHibernate/Dialect/FirebirdDialect.cs trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiSubstringFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiTrimEmulationFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/CharIndexFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/ClassicAggregateFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/ISQLFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/NoArgSQLFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/NvlFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/PositionSubstringFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/SQLFunctionTemplate.cs trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSQLFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSafeSQLFunction.cs trunk/nhibernate/src/NHibernate/Dialect/Function/VarArgsSQLFunction.cs trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs trunk/nhibernate/src/NHibernate/Hql/Classic/GroupByParser.cs trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs trunk/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs trunk/nhibernate/src/NHibernate/SqlCommand/ISqlStringVisitor.cs trunk/nhibernate/src/NHibernate/SqlCommand/QuerySelect.cs trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs trunk/nhibernate/src/NHibernate/SqlCommand/SqlStringBuilder.cs trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/HQLFunctions.cs trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SQLFunctionTemplateTest.cs trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SimpleFunctionsTest.cs Modified: trunk/nhibernate/src/NHibernate/Criterion/SqlFunctionProjection.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/SqlFunctionProjection.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Criterion/SqlFunctionProjection.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -78,7 +78,7 @@ { tokens.Add(replacemenToken); } - string functionStatement = sqlFunction.Render(tokens, criteriaQuery.Factory); + string functionStatement = sqlFunction.Render(tokens, criteriaQuery.Factory).ToString(); string[] splitted = functionStatement.Split(new string[] {replacemenToken}, StringSplitOptions.RemoveEmptyEntries); SqlStringBuilder sb = new SqlStringBuilder(); @@ -138,4 +138,4 @@ return types.ToArray(); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/FirebirdDialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/FirebirdDialect.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/FirebirdDialect.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -221,10 +221,15 @@ { } - public override string Render(IList args, ISessionFactoryImplementor factory) + public override SqlString Render(IList args, ISessionFactoryImplementor factory) { - base.Render(args, factory); - return string.Format("cast('{0}' as {1})", Name, FunctionReturnType.SqlTypes(factory)[0]); + return new SqlStringBuilder() + .Add("cast('") + .Add(name) + .Add("' as ") + .Add(returnType.SqlTypes(factory)[0].ToString()) + .Add(")") + .ToSqlString(); } } @@ -234,9 +239,9 @@ : base("current_timestamp", NHibernateUtil.DateTime, true) { } - public override string Render(IList args, ISessionFactoryImplementor factory) + public override SqlString Render(IList args, ISessionFactoryImplementor factory) { - return Name; + return new SqlString(name); } } @@ -245,4 +250,4 @@ return new FirebirdDataBaseSchema(connection); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiSubstringFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiSubstringFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiSubstringFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -2,6 +2,7 @@ using System.Collections; using System.Text; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -39,26 +40,26 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { if (args.Count < 2 || args.Count > 3) { throw new QueryException("substring(): Incorrect number of parameters (expected 2 or 3, got " + args.Count + ")"); } - StringBuilder cmd = new StringBuilder(); - cmd.Append("substring(") - .Append(args[0]) - .Append(" from ") - .Append(args[1]); + SqlStringBuilder cmd = new SqlStringBuilder(); + cmd.Add("substring(") + .AddObject(args[0]) + .Add(" from ") + .AddObject(args[1]); if (args.Count > 2) { - cmd.Append(" for ") - .Append(args[2]); + cmd.Add(" for ") + .AddObject(args[2]); } - cmd.Append(')'); - return cmd.ToString(); + cmd.Add(")"); + return cmd.ToSqlString(); } #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiTrimEmulationFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiTrimEmulationFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/AnsiTrimEmulationFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,6 +1,7 @@ using System; using System.Collections; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; using NHibernate.Util; using System.Text.RegularExpressions; @@ -79,14 +80,14 @@ /// If only trim specification is omitted, BOTH is assumed; /// if trim character is omitted, space is assumed /// </remarks> - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { if (args.Count < 1 || args.Count > 4) { throw new QueryException("function takes between 1 and 4 arguments"); } - string firstArg = (string) args[0]; + string firstArg = args[0].ToString(); if (args.Count == 1) { @@ -108,7 +109,7 @@ bool leading = true; // should leading trim-characters be trimmed? bool trailing = true; // should trailing trim-characters be trimmed? string trimCharacter = null; // the trim-character - string trimSource = null; // the trim-source + object trimSource = null; // the trim-source // potentialTrimCharacterArgIndex = 1 assumes that a // trim-specification has been specified. we handle the @@ -130,11 +131,11 @@ potentialTrimCharacterArgIndex = 0; } - string potentialTrimCharacter = (string) args[potentialTrimCharacterArgIndex]; - if (StringHelper.EqualsCaseInsensitive("from", potentialTrimCharacter)) + object potentialTrimCharacter = args[potentialTrimCharacterArgIndex]; + if (StringHelper.EqualsCaseInsensitive("from", potentialTrimCharacter.ToString())) { trimCharacter = "' '"; - trimSource = (string) args[potentialTrimCharacterArgIndex + 1]; + trimSource = args[potentialTrimCharacterArgIndex + 1]; } else if (potentialTrimCharacterArgIndex + 1 >= args.Count) { @@ -143,14 +144,14 @@ } else { - trimCharacter = potentialTrimCharacter; - if (StringHelper.EqualsCaseInsensitive("from", (string) args[potentialTrimCharacterArgIndex + 1])) + trimCharacter = potentialTrimCharacter.ToString(); + if (StringHelper.EqualsCaseInsensitive("from", args[potentialTrimCharacterArgIndex + 1].ToString())) { - trimSource = (string) args[potentialTrimCharacterArgIndex + 2]; + trimSource = args[potentialTrimCharacterArgIndex + 2]; } else { - trimSource = (string) args[potentialTrimCharacterArgIndex + 1]; + trimSource = args[potentialTrimCharacterArgIndex + 1]; } } @@ -208,4 +209,4 @@ #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/CastFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,6 +1,7 @@ using System; using System.Collections; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.SqlTypes; using NHibernate.Type; @@ -34,13 +35,13 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { if (args.Count != 2) { throw new QueryException("cast() requires two arguments"); } - string typeName = (string) args[1]; + string typeName = args[1].ToString(); string sqlType = string.Empty; IType hqlType = TypeFactory.HeuristicType(typeName); if (hqlType != null) @@ -70,7 +71,13 @@ { throw new QueryException(string.Format("invalid Hibernate type for cast(): type {0} not found", typeName)); } - return String.Format("cast({0} as {1})", args[0], sqlType); + return new SqlStringBuilder() + .Add("cast(") + .AddObject(args[0]) + .Add(" as ") + .Add(sqlType) + .Add(")") + .ToSqlString(); } #endregion @@ -89,4 +96,4 @@ #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/CharIndexFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/CharIndexFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/CharIndexFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -2,6 +2,7 @@ using System.Collections; using System.Text; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -32,7 +33,7 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { // TODO: QueryException if args.Count<2 (not present in H3.2) bool threeArgs = args.Count > 2; @@ -40,27 +41,27 @@ object orgString = args[1]; object start = threeArgs ? args[2] : null; - StringBuilder buf = new StringBuilder(); - buf.Append("charindex(") - .Append(pattern) - .Append(", "); + SqlStringBuilder buf = new SqlStringBuilder(); + buf.Add("charindex(") + .AddObject(pattern) + .Add(", "); if (threeArgs) { - buf.Append("right("); + buf.Add("right("); } - buf.Append(orgString); + buf.AddObject(orgString); if (threeArgs) { - buf.Append(", char_length(") - .Append(orgString) - .Append(")-(") - .Append(start) - .Append("-1))"); + buf.Add(", char_length(") + .AddObject(orgString) + .Add(")-(") + .AddObject(start) + .Add("-1))"); } - buf.Append(')'); - return buf.ToString(); + buf.Add(")"); + return buf.ToSqlString(); } #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/ClassicAggregateFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/ClassicAggregateFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/ClassicAggregateFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -2,6 +2,7 @@ using System.Collections; using System.Text; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; using NHibernate.Util; @@ -53,7 +54,7 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { //ANSI-SQL92 definition //<general set function> ::= @@ -69,22 +70,22 @@ { throw new QueryException(string.Format("Aggregate {0}(): invalid argument '*'.", name)); } - StringBuilder cmd = new StringBuilder(); - cmd.Append(name) - .Append("("); + SqlStringBuilder cmd = new SqlStringBuilder(); + cmd.Add(name) + .Add("("); if (args.Count > 1) { - string firstArg = args[0].ToString(); - if (!StringHelper.EqualsCaseInsensitive("distinct", firstArg) && - !StringHelper.EqualsCaseInsensitive("all", firstArg)) + object firstArg = args[0]; + if (!StringHelper.EqualsCaseInsensitive("distinct", firstArg.ToString()) && + !StringHelper.EqualsCaseInsensitive("all", firstArg.ToString())) { throw new QueryException(string.Format("Aggregate {0}(): token unknow {1}.", name, firstArg)); } - cmd.Append(firstArg).Append(' '); + cmd.AddObject(firstArg).Add(" "); } - cmd.Append(args[args.Count - 1]) - .Append(')'); - return cmd.ToString(); + cmd.AddObject(args[args.Count - 1]) + .Add(")"); + return cmd.ToSqlString(); } #endregion Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/ISQLFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/ISQLFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/ISQLFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,5 +1,6 @@ using System.Collections; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -38,6 +39,6 @@ /// <param name="args">List of arguments</param> /// <param name="factory"></param> /// <returns>SQL fragment for the fuction.</returns> - string Render(IList args, ISessionFactoryImplementor factory); + SqlString Render(IList args, ISessionFactoryImplementor factory); } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/NoArgSQLFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/NoArgSQLFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/NoArgSQLFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,5 +1,6 @@ using System.Collections; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -9,8 +10,8 @@ /// </summary> public class NoArgSQLFunction : ISQLFunction { - private readonly IType returnType = null; - private readonly string name; + protected readonly IType returnType = null; + protected readonly string name; private readonly bool hasParenthesesIfNoArguments; public NoArgSQLFunction(string name, IType returnType) : this(name, returnType, true) @@ -51,15 +52,21 @@ get { return hasParenthesesIfNoArguments; } } - public virtual string Render(IList args, ISessionFactoryImplementor factory) + public virtual SqlString Render(IList args, ISessionFactoryImplementor factory) { if (args.Count > 0) { throw new QueryException("function takes no arguments: " + name); } - return hasParenthesesIfNoArguments ? name + "()" : name; + SqlStringBuilder buf = new SqlStringBuilder(2); + buf.Add(name); + if (hasParenthesesIfNoArguments) + { + buf.Add("()"); + } + return buf.ToSqlString(); } #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/NvlFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/NvlFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/NvlFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,6 +1,7 @@ using System; using System.Collections; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -31,7 +32,7 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { // DONE: QueryException if args.Count==0 (not present in H3.2) if (args.Count == 0) @@ -43,14 +44,19 @@ args.RemoveAt(lastIndex); if (lastIndex == 0) { - return last.ToString(); + return new SqlString(last); } object secondLast = args[lastIndex - 1]; - string nvl = "nvl(" + secondLast + ", " + last + ")"; - args[lastIndex - 1] = nvl; + SqlStringBuilder nvl = new SqlStringBuilder(5) + .Add("nvl(") + .AddObject(secondLast) + .Add(", ") + .AddObject(last) + .Add(")"); + args[lastIndex - 1] = nvl.ToSqlString(); return Render(args, factory); } #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/PositionSubstringFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/PositionSubstringFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/PositionSubstringFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -2,6 +2,7 @@ using System.Collections; using System.Text; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -32,7 +33,7 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { // DONE: QueryException if args.Count<2 (not present in H3.2) if (args.Count < 2) @@ -44,35 +45,35 @@ object orgString = args[1]; object start = threeArgs ? args[2] : null; - StringBuilder buf = new StringBuilder(); + SqlStringBuilder buf = new SqlStringBuilder(); if (threeArgs) { - buf.Append('('); + buf.Add("("); } - buf.Append("position(") - .Append(pattern) - .Append(" in "); + buf.Add("position(") + .AddObject(pattern) + .Add(" in "); if (threeArgs) { - buf.Append("substring("); + buf.Add("substring("); } - buf.Append(orgString); + buf.AddObject(orgString); if (threeArgs) { - buf.Append(", ") - .Append(start) - .Append(')'); + buf.Add(", ") + .AddObject(start) + .Add(")"); } - buf.Append(')'); + buf.Add(")"); if (threeArgs) { - buf.Append('+') - .Append(start) - .Append("-1)"); + buf.Add("+") + .AddObject(start) + .Add("-1)"); } - return buf.ToString(); + return buf.ToSqlString(); } #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/SQLFunctionTemplate.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/SQLFunctionTemplate.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/SQLFunctionTemplate.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -3,6 +3,7 @@ using System.Text; using System.Text.RegularExpressions; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -98,9 +99,9 @@ /// <param name="args">args function arguments</param> /// <param name="factory">generated SQL function call</param> /// <returns></returns> - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { - StringBuilder buf = new StringBuilder(); + SqlStringBuilder buf = new SqlStringBuilder(); foreach (TemplateChunk tc in chunks) { if (tc.ArgumentIndex != InvalidArgumentIndex) @@ -110,15 +111,22 @@ // TODO: if (arg == null) QueryException is better ? if (arg != null) { - buf.Append(arg); + if (arg is Parameter || arg is SqlString) + { + buf.AddObject(arg); + } + else + { + buf.Add(arg.ToString()); + } } } else { - buf.Append(tc.Text); + buf.Add(tc.Text); } } - return buf.ToString(); + return buf.ToSqlString(); } #endregion @@ -128,4 +136,4 @@ return template; } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSQLFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSQLFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSQLFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,6 +1,7 @@ using System.Collections; using System.Text; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -55,17 +56,25 @@ get { return true; } } - public virtual string Render(IList args, ISessionFactoryImplementor factory) + public virtual SqlString Render(IList args, ISessionFactoryImplementor factory) { - StringBuilder buf = new StringBuilder(); - buf.Append(name) - .Append('('); + SqlStringBuilder buf = new SqlStringBuilder(); + buf.Add(name) + .Add("("); for (int i = 0; i < args.Count; i++) { - buf.Append(args[i]); - if (i < (args.Count - 1)) buf.Append(", "); + object arg = args[i]; + if (arg is Parameter || arg is SqlString) + { + buf.AddObject(arg); + } + else + { + buf.Add(arg.ToString()); + } + if (i < (args.Count - 1)) buf.Add(", "); } - return buf.Append(')').ToString(); + return buf.Add(")").ToSqlString(); } #endregion @@ -75,4 +84,4 @@ return name; } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSafeSQLFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSafeSQLFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/StandardSafeSQLFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -39,7 +40,7 @@ this.allowedArgsCount = allowedArgsCount; } - public override string Render(System.Collections.IList args, NHibernate.Engine.ISessionFactoryImplementor factory) + public override SqlString Render(System.Collections.IList args, NHibernate.Engine.ISessionFactoryImplementor factory) { if (args.Count!= allowedArgsCount) { Modified: trunk/nhibernate/src/NHibernate/Dialect/Function/VarArgsSQLFunction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Function/VarArgsSQLFunction.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Dialect/Function/VarArgsSQLFunction.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -2,6 +2,7 @@ using System.Collections; using System.Text; using NHibernate.Engine; +using NHibernate.SqlCommand; using NHibernate.Type; namespace NHibernate.Dialect.Function @@ -47,17 +48,17 @@ get { return true; } } - public string Render(IList args, ISessionFactoryImplementor factory) + public SqlString Render(IList args, ISessionFactoryImplementor factory) { - StringBuilder buf = new StringBuilder().Append(begin); + SqlStringBuilder buf = new SqlStringBuilder().Add(begin); for (int i = 0; i < args.Count; i++) { - buf.Append(args[i]); - if (i < args.Count - 1) buf.Append(sep); + buf.AddObject(args[i]); + if (i < args.Count - 1) buf.Add(sep); } - return buf.Append(end).ToString(); + return buf.Add(end).ToSqlString(); } #endregion } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -30,6 +30,11 @@ result.Append(text); } + void ISqlStringVisitor.String(SqlString sqlString) + { + result.Append(sqlString.ToString()); + } + void ISqlStringVisitor.Parameter() { string name = formatter.GetParameterName(parameterIndex); @@ -37,4 +42,4 @@ result.Append(name); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/GroupByParser.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/GroupByParser.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/GroupByParser.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -27,6 +27,11 @@ q.AppendGroupByToken(pathExpressionParser.WhereColumn); pathExpressionParser.AddAssociation(q); } + else if (token.StartsWith(ParserHelper.HqlVariablePrefix)) + { + q.AddNamedParameter(token.Substring(1)); + q.AppendGroupByParameter(); + } else { q.AppendGroupByToken(token); @@ -46,4 +51,4 @@ pathExpressionParser.UseThetaStyleJoin = true; } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -45,7 +45,7 @@ private readonly IDictionary<string, IAssociationType> uniqueKeyOwnerReferences = new Dictionary<string, IAssociationType>(); private readonly IDictionary<string, IPropertyMapping> decoratedPropertyMappings = new Dictionary<string, IPropertyMapping>(); - private readonly IList scalarSelectTokens = new ArrayList(); // contains a List of strings + private readonly IList<SqlString> scalarSelectTokens = new List<SqlString>(); private readonly IList<SqlString> whereTokens = new List<SqlString>(); private readonly IList<SqlString> havingTokens = new List<SqlString>(); private readonly IDictionary<string, JoinSequence> joins = new LinkedHashMap<string, JoinSequence>(); @@ -174,7 +174,9 @@ for (int i = 0; i < count; i++) { - sql.AddSelectFragmentString(((IQueryableCollection) persisters[i]).SelectFragment(names[i], suffixes[i])); + sql.AddSelectFragmentString(new SqlString( + ((IQueryableCollection) persisters[i]).SelectFragment( + (string) names[i], (string) suffixes[i]))); } } @@ -632,16 +634,26 @@ groupByTokens.Add(new SqlString(token)); } + internal void AppendGroupByParameter() + { + groupByTokens.Add(SqlString.Parameter); + } + internal void AppendScalarSelectToken(string token) { - scalarSelectTokens.Add(token); + scalarSelectTokens.Add(new SqlString(token)); } internal void AppendScalarSelectTokens(string[] tokens) { - scalarSelectTokens.Add(tokens); + scalarSelectTokens.Add(new SqlString(tokens)); } + internal void AppendScalarSelectParameter() + { + scalarSelectTokens.Add(SqlString.Parameter); + } + internal void AddJoin(string name, JoinSequence joinSequence) { if (!joins.ContainsKey(name)) @@ -747,7 +759,7 @@ owners = null; } - string scalarSelect = RenderScalarSelect(); //Must be done here because of side-effect! yuck... + SqlString scalarSelect = RenderScalarSelect(); //Must be done here because of side-effect! yuck... int scalarSize = scalarTypes.Count; hasScalars = scalarTypes.Count != rtsize; @@ -846,7 +858,7 @@ { string name = returnedTypes[k]; string suffix = size == 1 ? String.Empty : k.ToString() + StringHelper.Underscore; - sql.AddSelectFragmentString(persisters[k].IdentifierSelectFragment(name, suffix)); + sql.AddSelectFragmentString(new SqlString(persisters[k].IdentifierSelectFragment(name, suffix))); } } @@ -856,19 +868,19 @@ for (int k = 0; k < size; k++) { string suffix = (size == 1) ? String.Empty : k.ToString() + StringHelper.Underscore; - string name = returnedTypes[k]; - sql.AddSelectFragmentString(persisters[k].PropertySelectFragment(name, suffix, false)); + string name = (string) returnedTypes[k]; + sql.AddSelectFragmentString(new SqlString(persisters[k].PropertySelectFragment(name, suffix, false))); } } /// <summary> /// WARNING: side-effecty /// </summary> - private string RenderScalarSelect() + private SqlString RenderScalarSelect() { bool isSubselect = superQuery != null; - StringBuilder buf = new StringBuilder(20); + SqlStringBuilder buf = new SqlStringBuilder(); if (scalarTypes.Count == 0) { @@ -881,14 +893,14 @@ string[] _names = persisters[k].IdentifierColumnNames; for (int i = 0; i < _names.Length; i++) { - buf.Append(returnedTypes[k]).Append(StringHelper.Dot).Append(_names[i]); + buf.Add(returnedTypes[k].ToString()).Add(StringHelper.Dot.ToString()).Add(_names[i]); if (!isSubselect) { - buf.Append(" as ").Append(ScalarName(k, i)); + buf.Add(" as ").Add(ScalarName(k, i)); } if (i != _names.Length - 1 || k != size - 1) { - buf.Append(StringHelper.CommaSpace); + buf.Add(StringHelper.CommaSpace); } } } @@ -901,17 +913,17 @@ int parenCount = 0; // used to count the nesting of parentheses for (int tokenIdx = 0; tokenIdx < scalarSelectTokens.Count; tokenIdx++) { - object next = scalarSelectTokens[tokenIdx]; - if (next is string) + SqlString next = scalarSelectTokens[tokenIdx]; + if (next.Count == 1) { - string token = (string)next; + string token = next.ToString(); string lc = token.ToLowerInvariant(); ISQLFunction func = Factory.SQLFunctionRegistry.FindSQLFunction(lc); if (func != null) { // Render the HQL function - string renderedFunction = RenderFunctionClause(func, scalarSelectTokens, ref tokenIdx); - buf.Append(renderedFunction); + SqlString renderedFunction = RenderFunctionClause(func, scalarSelectTokens, ref tokenIdx); + buf.Add(renderedFunction); } else { @@ -933,47 +945,47 @@ { if (!isSubselect && parenCount == 0) { - buf.Append(" as ").Append(ScalarName(c++, 0)); + buf.Add(" as ").Add(ScalarName(c++, 0)); } } } - buf.Append(token); + buf.Add(token); if (lc.Equals("distinct") || lc.Equals("all")) { - buf.Append(' '); + buf.Add(" "); } } } else { nolast = true; - string[] tokens = (string[])next; - for (int i = 0; i < tokens.Length; i++) + int i = 0; + foreach (object token in next.Parts) { - buf.Append(tokens[i]); + buf.AddObject(token); if (!isSubselect) { - buf.Append(" as ").Append(ScalarName(c, i)); + buf.Add(" as ").Add(ScalarName(c, i)); } - if (i != tokens.Length - 1) + if (i != next.Count - 1) { - buf.Append(StringHelper.CommaSpace); + buf.Add(StringHelper.CommaSpace); } + i++; } c++; } } if (!isSubselect && !nolast) { - buf.Append(" as ").Append(ScalarName(c, 0)); + buf.Add(" as ").Add(ScalarName(c++, 0)); } } - return buf.ToString(); + return buf.ToSqlString(); } - // Parameters inside function are not supported private void RenderFunctions(IList<SqlString> tokens) { for (int tokenIdx = 0; tokenIdx < tokens.Count; tokenIdx++) @@ -983,10 +995,10 @@ if (func != null) { int flTokenIdx = tokenIdx; - string renderedFunction = RenderFunctionClause(func, (IList)tokens, ref flTokenIdx); - // At this point we have the trunk that represent the function with it's parameters enclosed - // in paren. Now all token in the tokens list can be removed from original list because they must - // be replased with the rendered function. + SqlString renderedFunction = RenderFunctionClause(func, tokens, ref flTokenIdx); + // At this point we have the trunk that represents the function with its + // arguments enclosed in parens. Now all token in the tokens list will be + // removed from the original list and replaced with the rendered function. for (int i = 0; i < flTokenIdx - tokenIdx; i++) { tokens.RemoveAt(tokenIdx + 1); @@ -1003,30 +1015,32 @@ /// <param name="tokenIdx">The index of the list that represent the founded function.</param> /// <returns>String trepresentation of each token.</returns> /// <remarks>Each token can be string or SqlString </remarks> - private StringCollection ExtractFunctionClause(IList tokens, ref int tokenIdx) + private IList<SqlString> ExtractFunctionClause(IList<SqlString> tokens, ref int tokenIdx) { - string funcName = tokens[tokenIdx].ToString(); - StringCollection functionTokens = new StringCollection(); + SqlString funcName = tokens[tokenIdx]; + IList<SqlString> functionTokens = new List<SqlString>(); functionTokens.Add(funcName); tokenIdx++; if (tokenIdx >= tokens.Count || !StringHelper.OpenParen.Equals(tokens[tokenIdx].ToString())) { - // All function with parameters have the syntax - // <function name> <left paren> <parameters> <right paren> + // All function with arguments have the syntax + // <function name> <left paren> <arguments> <right paren> throw new QueryException("'(' expected after function " + funcName); } - functionTokens.Add(StringHelper.OpenParen); + functionTokens.Add(new SqlString(StringHelper.OpenParen)); tokenIdx++; int parenCount = 1; for (; tokenIdx < tokens.Count && parenCount > 0; tokenIdx++) { - if (tokens[tokenIdx].ToString().StartsWith(ParserHelper.HqlVariablePrefix) || tokens[tokenIdx].ToString().Equals(StringHelper.SqlParameter)) + if (tokens[tokenIdx].StartsWithCaseInsensitive(ParserHelper.HqlVariablePrefix) || tokens[tokenIdx].ToString().Equals(StringHelper.SqlParameter)) { - throw new QueryException(string.Format("Parameters inside function are not supported (function '{0}').", funcName), - new NotSupportedException()); + functionTokens.Add(SqlString.Parameter); } - functionTokens.Add(tokens[tokenIdx].ToString()); + else + { + functionTokens.Add(tokens[tokenIdx]); + } if (StringHelper.OpenParen.Equals(tokens[tokenIdx].ToString())) { parenCount++; @@ -1044,17 +1058,17 @@ return functionTokens; } - private string RenderFunctionClause(ISQLFunction func, IList tokens, ref int tokenIdx) + private SqlString RenderFunctionClause(ISQLFunction func, IList<SqlString> tokens, ref int tokenIdx) { - StringCollection functionTokens; + IList<SqlString> functionTokens; if (!func.HasArguments) { - // The function don't work with arguments. + // The function doesn't work with arguments. if (func.HasParenthesesIfNoArguments) ExtractFunctionClause(tokens, ref tokenIdx); - // The function render simply translate is't name for a specific dialect. - return func.Render(CollectionHelper.EmptyList, Factory); + // The function render simply translate its name for a specific dialect. + return func.Render(new ArrayList(), Factory); } functionTokens = ExtractFunctionClause(tokens, ref tokenIdx); @@ -1062,8 +1076,8 @@ if (fg == null) fg = new CommonGrammar(); - StringCollection args = new StringCollection(); - StringBuilder argBuf = new StringBuilder(20); + IList args = new ArrayList(); + SqlStringBuilder argBuf = new SqlStringBuilder(); // Extract args spliting first 2 token because are: FuncName( // last token is ')' // To allow expressions like arg (ex:5+5) all tokens between 'argument separator' or @@ -1073,44 +1087,44 @@ // Ex: sum(a.Prop+10), cast(yesterday-1 as date) for (int argIdx = 2; argIdx < functionTokens.Count - 1; argIdx++) { - string token = functionTokens[argIdx]; - if(fg.IsKnownArgument(token)) + object token = functionTokens[argIdx]; + if (fg.IsKnownArgument(token.ToString())) { - if (argBuf.Length > 0) + if (argBuf.Count > 0) { // end of the previous argument - args.Add(argBuf.ToString()); - argBuf = new StringBuilder(20); + args.Add(argBuf.ToSqlString()); + argBuf = new SqlStringBuilder(); } args.Add(token); } - else if (fg.IsSeparator(token)) + else if (fg.IsSeparator(token.ToString())) { // argument end - if (argBuf.Length > 0) + if (argBuf.Count > 0) { - args.Add(argBuf.ToString()); - argBuf = new StringBuilder(20); + args.Add(argBuf.ToSqlString()); + argBuf = new SqlStringBuilder(); } } else { - ISQLFunction nfunc = Factory.SQLFunctionRegistry.FindSQLFunction(token.ToLowerInvariant()); + ISQLFunction nfunc = Factory.SQLFunctionRegistry.FindSQLFunction(token.ToString().ToLowerInvariant()); if (nfunc != null) { // the token is a nested function call - argBuf.Append(RenderFunctionClause(nfunc, functionTokens, ref argIdx)); + argBuf.Add(RenderFunctionClause(nfunc, functionTokens, ref argIdx)); } else { // the token is a part of an argument (every thing else) - argBuf.Append(token); + argBuf.AddObject(token); } } } // Add the last arg - if (argBuf.Length > 0) - args.Add(argBuf.ToString()); + if (argBuf.Count > 0) + args.Add(argBuf.ToSqlString()); return func.Render(args, Factory); } Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -166,8 +166,13 @@ constantToken = true; } - if (constantToken) + if (token.StartsWith(ParserHelper.HqlVariablePrefix)) { + q.AddNamedParameter(token.Substring(1)); + q.AppendScalarSelectParameter(); + } + else if (constantToken) + { q.AppendScalarSelectToken(token); } else @@ -228,11 +233,10 @@ q.AppendScalarSelectToken(token); q.AddSelectScalar(GetFloatingPointConstantType()); } - else if (IsParameter(token)) + else if (token.StartsWith(ParserHelper.HqlVariablePrefix)) { - //q.AddNamedParameter(token.Substring(1)); - //q.AppendScalarSelectToken(token); - throw new QueryException("parameters are not supported in SELECT.", new NotSupportedException()); + q.AddNamedParameter(token.Substring(1)); + q.AppendScalarSelectParameter(); } else throw; @@ -244,9 +248,6 @@ #region RegExs private static readonly Regex pathExpressionRegEx = new Regex(@"\A[A-Za-z_][A-Za-z_0-9]*[.][A-Za-z_][A-Za-z_0-9]*\z", RegexOptions.Singleline | RegexOptions.Compiled); private static readonly Regex stringCostantRegEx = new Regex(@"\A'('{2})*([^'\r\n]*)('{2})*([^'\r\n]*)('{2})*'\z", RegexOptions.Singleline | RegexOptions.Compiled); - - private static readonly string paramMatcher = string.Format("\\A([{0}][A-Za-z_][A-Za-z_0-9]*)|[{1}]\\z", ParserHelper.HqlVariablePrefix, StringHelper.SqlParameter); - private static readonly Regex parameterRegEx = new Regex(paramMatcher, RegexOptions.Singleline | RegexOptions.Compiled); #endregion private static bool IsPathExpression(string token) @@ -271,11 +272,6 @@ return double.TryParse(token, NumberStyles.Number, CultureInfo.InvariantCulture, out d); } - private static bool IsParameter(string token) - { - return parameterRegEx.IsMatch(token); - } - private static IType GetIntegerConstantType(string token) { int i; @@ -322,4 +318,4 @@ } } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/SqlCommand/ISqlStringVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/ISqlStringVisitor.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/SqlCommand/ISqlStringVisitor.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -5,6 +5,7 @@ public interface ISqlStringVisitor { void String(string text); + void String(SqlString sqlString); void Parameter(); } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/SqlCommand/QuerySelect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/QuerySelect.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/SqlCommand/QuerySelect.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -12,7 +12,7 @@ { private readonly JoinFragment joins; - private readonly StringBuilder selectBuilder = new StringBuilder(); + private readonly SqlStringBuilder selectBuilder = new SqlStringBuilder(); private readonly SqlStringBuilder whereBuilder = new SqlStringBuilder(); // groupBy, orderBy, and having will for sure have no parameters. @@ -111,9 +111,9 @@ /// /// </summary> /// <param name="fragment"></param> - public void AddSelectFragmentString(string fragment) + public void AddSelectFragmentString(SqlString fragment) { - if (fragment.StartsWith(",")) + if (fragment.StartsWithCaseInsensitive(",")) { fragment = fragment.Substring(1); } @@ -122,12 +122,12 @@ if (fragment.Length > 0) { - if (selectBuilder.Length > 0) + if (selectBuilder.Count > 0) { - selectBuilder.Append(StringHelper.CommaSpace); + selectBuilder.Add(StringHelper.CommaSpace); } - selectBuilder.Append(fragment); + selectBuilder.Add(fragment); } } @@ -138,7 +138,7 @@ /// <param name="alias"></param> public void AddSelectColumn(string columnName, string alias) { - AddSelectFragmentString(columnName + ' ' + alias); + AddSelectFragmentString(new SqlString(columnName + ' ' + alias)); } /// <summary></summary> @@ -224,12 +224,12 @@ from = from.Substring(11); } - builder.Add(selectBuilder.ToString()) + builder.Add(selectBuilder.ToSqlString()) .Add(" from") .Add(from); SqlString part1 = joins.ToWhereFragmentString.Trim(); - SqlString part2 = whereBuilder.ToSqlString().Trim(); + SqlString part2 = whereBuilder.ToSqlString(); bool hasPart1 = part1.Count > 0; bool hasPart2 = part2.Count > 0; @@ -330,4 +330,4 @@ } } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/SqlCommand/SqlString.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -42,7 +42,7 @@ #if DEBUG foreach (object obj in sqlParts) { - Debug.Assert(obj is string || obj is Parameter); + Debug.Assert(obj is string || obj is SqlString || obj is Parameter); } #endif this.sqlParts = sqlParts; @@ -108,10 +108,14 @@ foreach (object part in sqlParts) { + SqlString sqlStringPart = part as SqlString; string stringPart = part as string; - - if (stringPart != null) + if (sqlStringPart != null) { + sqlBuilder.Add(sqlStringPart.Compact()); + } + else if (stringPart != null) + { builder.Append(stringPart); } else @@ -123,7 +127,7 @@ } builder.Length = 0; - sqlBuilder.Add((Parameter) part); + sqlBuilder.Add((Parameter)part); } } @@ -648,10 +652,15 @@ foreach (object part in sqlParts) { string partString = part as string; + SqlString partSqlString = part as SqlString; if (partString != null) { visitor.String(partString); } + else if (partSqlString != null && !SqlString.Parameter.Equals(partSqlString)) + { + visitor.String(partSqlString); + } else { visitor.Parameter(); @@ -726,4 +735,4 @@ return new SubselectClauseExtractor(Compact().sqlParts).GetSqlString(); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate/SqlCommand/SqlStringBuilder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/SqlStringBuilder.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate/SqlCommand/SqlStringBuilder.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -333,6 +333,11 @@ parent.Add(text); } + public void String(SqlString sqlString) + { + parent.Add(sqlString); + } + public void Parameter() { parent.AddParameter(); @@ -344,4 +349,4 @@ sqlParts.Clear(); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/HQLFunctions.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/HQLFunctions.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/HQLFunctions.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -1,3 +1,4 @@ +using System; using System.Collections; using NHibernate.Dialect; using NHibernate.Dialect.Function; @@ -17,7 +18,7 @@ static HQLFunctions() { notSupportedStandardFunction.Add("locate", - new System.Type[] { typeof(MsSql2000Dialect), typeof(MsSql2005Dialect), typeof(FirebirdDialect) }); + new System.Type[] { typeof(MsSql2000Dialect), typeof(MsSql2005Dialect), typeof(FirebirdDialect), typeof(PostgreSQLDialect) }); notSupportedStandardFunction.Add("bit_length", new System.Type[] { typeof(MsSql2000Dialect), typeof(MsSql2005Dialect) }); notSupportedStandardFunction.Add("extract", @@ -222,6 +223,36 @@ Animal result = (Animal) s.CreateQuery(hql).UniqueResult(); Assert.AreEqual("abcdef", result.Description); + hql = "from Animal a where substring(a.Description, 2, 3) = ?"; + result = (Animal)s.CreateQuery(hql) + .SetParameter(0, "bcd") + .UniqueResult(); + Assert.AreEqual("abcdef", result.Description); + + + hql = "from Animal a where substring(a.Description, 2, ?) = 'bcd'"; + result = (Animal)s.CreateQuery(hql) + .SetParameter(0, 3) + .UniqueResult(); + Assert.AreEqual("abcdef", result.Description); + + + hql = "from Animal a where substring(a.Description, ?, ?) = ?"; + result = (Animal)s.CreateQuery(hql) + .SetParameter(0, 2) + .SetParameter(1, 3) + .SetParameter(2, "bcd") + .UniqueResult(); + Assert.AreEqual("abcdef", result.Description); + + hql = "select substring(a.Description, ?, ?) from Animal a"; + IList results = s.CreateQuery(hql) + .SetParameter(0, 2) + .SetParameter(1, 3) + .List(); + Assert.AreEqual(1, results.Count); + Assert.AreEqual("bcd", results[0]); + if (twoArgSubstringSupported) { hql = "from Animal a where substring(a.Description, 4) = 'def'"; @@ -560,6 +591,13 @@ result = (Animal)s.CreateQuery(hql).UniqueResult(); Assert.AreEqual("abcdef", result.Description); + // Rendered in WHERE using a property and named param + hql = "from Animal a where cast(:aParam+a.BodyWeight as Double)>0"; + result = (Animal)s.CreateQuery(hql) + .SetDouble("aParam", 2D) + .UniqueResult(); + Assert.AreEqual("abcdef", result.Description); + // Rendered in WHERE using a property and nested functions hql = "from Animal a where cast(cast(cast(a.BodyWeight as string) as double) as int) = 1"; result = (Animal)s.CreateQuery(hql).UniqueResult(); @@ -595,6 +633,30 @@ Assert.AreEqual(1, l.Count); Assert.AreEqual(129, l[0]); + // Rendered in HAVING using a property and named param (NOT SUPPORTED) + try + { + hql = "select cast(:aParam+a.BodyWeight as int) from Animal a group by cast(:aParam+a.BodyWeight as int) having cast(:aParam+a.BodyWeight as int)>0"; + l = s.CreateQuery(hql).SetInt32("aParam", 10).List(); + Assert.AreEqual(1, l.Count); + Assert.AreEqual(11, l[0]); + } + catch (QueryException ex) + { + if (!(ex.InnerException is NotSupportedException)) + throw; + } + catch (ADOException ex) + { + // This test raises an exception in SQL Server because named + // parameters internally are always positional (@p0, @p1, etc.) + // and named differently hence they mismatch between GROUP BY and HAVING clauses. + if (!ex.InnerException.Message.Equals( + "Column 'Animal.BodyWeight' is invalid in the HAVING clause " + + "because it is not contained in either an aggregate function or the GROUP BY clause.")) + throw; + } + // Rendered in HAVING using a property and nested functions string castExpr = "cast(cast(cast(a.BodyWeight as string) as double) as int)"; hql = string.Format("select {0} from Animal a group by {0} having {0} = 1", castExpr); Modified: trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SQLFunctionTemplateTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SQLFunctionTemplateTest.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SQLFunctionTemplateTest.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -16,19 +16,19 @@ Assert.IsTrue(ft.HasArguments); IList args = new ArrayList(); args.Add("'abcd <'"); - Assert.AreEqual("ltrim( 'abcd <' )", ft.Render(args, factoryImpl)); + Assert.AreEqual("ltrim( 'abcd <' )", ft.Render(args, factoryImpl).ToString()); ft = new SQLFunctionTemplate(NHibernateUtil.String, "ltrim( Az?ab )"); Assert.IsFalse(ft.HasArguments); - Assert.AreEqual("ltrim( Az?ab )", ft.Render(args, factoryImpl)); + Assert.AreEqual("ltrim( Az?ab )", ft.Render(args, factoryImpl).ToString()); ft = new SQLFunctionTemplate(NHibernateUtil.String, "function( ?1 )? 5:6"); Assert.IsTrue(ft.HasArguments); - Assert.AreEqual("function( 'abcd <' )? 5:6", ft.Render(args, factoryImpl)); + Assert.AreEqual("function( 'abcd <' )? 5:6", ft.Render(args, factoryImpl).ToString()); ft = new SQLFunctionTemplate(NHibernateUtil.String, "????????1?"); Assert.IsTrue(ft.HasArguments); - Assert.AreEqual("???????'abcd <'?", ft.Render(args, factoryImpl)); + Assert.AreEqual("???????'abcd <'?", ft.Render(args, factoryImpl).ToString()); } [Test] @@ -44,14 +44,14 @@ args.Add("'param2 ab '"); Assert.AreEqual( "replace( replace( rtrim( replace( replace( 'param1 ', ' ', '${space}$' ), 'param2 ab ', ' ' ) ), ' ', 'param2 ab ' ), '${space}$', ' ' )", - ft.Render(args, factoryImpl)); + ft.Render(args, factoryImpl).ToString()); args.Clear(); ft = new SQLFunctionTemplate(NHibernateUtil.String, "?1 ?3 ?2 ?3 ?1"); args.Add(1); args.Add(2); args.Add(3); - Assert.AreEqual("1 3 2 3 1", ft.Render(args, factoryImpl)); + Assert.AreEqual("1 3 2 3 1", ft.Render(args, factoryImpl).ToString()); } //[Test] not required @@ -68,7 +68,7 @@ DateTime.Today.ToString(DateTimeFormatInfo.InvariantInfo), (125.6D).ToString(NumberFormatInfo.InvariantInfo), (0910.123456m).ToString(NumberFormatInfo.InvariantInfo)); - Assert.AreEqual(expected, ft.Render(args, factoryImpl)); + Assert.AreEqual(expected, ft.Render(args, factoryImpl).ToString()); } [Test] @@ -79,13 +79,13 @@ // No Args; 2 params ft = new SQLFunctionTemplate(NHibernateUtil.String, "func(?1,?2)"); - Assert.AreEqual("func(,)", ft.Render(args, factoryImpl)); + Assert.AreEqual("func(,)", ft.Render(args, factoryImpl).ToString()); // Args<params args.Clear(); ft = new SQLFunctionTemplate(NHibernateUtil.String, "func(?1,?2)"); args.Add(1); - Assert.AreEqual("func(1,)", ft.Render(args, factoryImpl)); + Assert.AreEqual("func(1,)", ft.Render(args, factoryImpl).ToString()); // Args>params args.Clear(); @@ -93,7 +93,7 @@ args.Add(1); args.Add(2); args.Add(3); - Assert.AreEqual("func(1,3)", ft.Render(args, factoryImpl)); + Assert.AreEqual("func(1,3)", ft.Render(args, factoryImpl).ToString()); } } -} \ No newline at end of file +} Modified: trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SimpleFunctionsTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SimpleFunctionsTest.cs 2008-08-12 19:50:39 UTC (rev 3700) +++ trunk/nhibernate/src/NHibernate.Test/HQLFunctionTest/SimpleFunctionsTest.cs 2008-08-13 14:59:18 UTC (rev 3701) @@ -3,6 +3,7 @@ using NHibernate.Dialect.Function; using NHibernate.SqlTypes; using NUnit.Framework; +using NHibernate.SqlCommand; namespace NHibernate.Test.HQLFunctionTest { @@ -15,16 +16,16 @@ IList args = new ArrayList(); NoArgSQLFunction nf = new NoArgSQLFunction("noArgs", NHibernateUtil.String); Assert.IsTrue(nf.HasParenthesesIfNoArguments); - Assert.AreEqual("noArgs()", nf.Render(args, factoryImpl)); + Assert.AreEqual("noArgs()", nf.Render(args, factoryImpl).ToString()); nf = new NoArgSQLFunction("noArgs", NHibernateUtil.String, false); Assert.IsFalse(nf.HasParenthesesIfNoArguments); - Assert.AreEqual("noArgs", nf.Render(args, factoryImpl)); + Assert.AreEqual("noArgs", nf.Render(args, factoryImpl).ToString()); args.Add("aparam"); try { - string t = nf.Render(args, factoryImpl); + SqlString t = nf.Render(args, factoryImpl); Assert.Fail("No exception if has argument"); } catch (QueryException) @@ -39,11 +40,11 @@ IList args = new ArrayList(); StandardSQLFunction sf = new StandardSQLFunction("fname"); - Assert.AreEqual("fname()", sf.Render(args, factoryImpl)); + Assert.AreEqual("fname()", sf.Render(args, factoryImpl).ToString()); args.Add(1); args.Add(2); - Assert.AreEqual("fname(1, 2)", sf.Render(args, factoryImpl)); + Assert.AreEqual("fname(1, 2)", sf.Render(args, factoryImpl).ToString()); } [Test] @@ -54,7 +55,7 @@ CastFunction cf = new CastFunction(); try { - string t = cf.Render(args, factoryImpl); + SqlString t = cf.Render(args, factoryImpl); Assert.Fail("No exception if no argument"); } catch (QueryException) @@ -66,14 +67,14 @@ args.Add("long"); string expected = string.Format("cast({0} as {1})", args[0], factoryImpl.Dialect.GetCastTypeName(SqlTypeFactory.Int64)); - Assert.AreEqual(expected, cf.Render(args, factoryImpl)); + Assert.AreEqual(expected, cf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("'123'"); args.Add("NO_TYPE"); try { - string t = cf.Render(args, factoryImpl); + SqlString t = cf.Render(args, factoryImpl); Assert.Fail("Ivalid type accepted"); } catch (QueryException) @@ -88,16 +89,16 @@ IList args = new ArrayList(); VarArgsSQLFunction vf = new VarArgsSQLFunction("(", " || ", ")"); - Assert.AreEqual("()", vf.Render(args, factoryImpl)); + Assert.AreEqual("()", vf.Render(args, factoryImpl).ToString()); args.Add("va1"); - Assert.AreEqual("(va1)", vf.Render(args, factoryImpl)); + Assert.AreEqual("(va1)", vf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("va1"); args.Add("va2"); args.Add("va3"); - Assert.AreEqual("(va1 || va2 || va3)", vf.Render(args, factoryImpl)); + Assert.AreEqual("(va1 || va2 || va3)", vf.Render(args, factoryImpl).ToString()); } [Test] @@ -107,13 +108,13 @@ NvlFunction nf = new NvlFunction(); args.Add("va1"); - Assert.AreEqual("va1", nf.Render(args, factoryImpl)); + Assert.AreEqual("va1", nf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("va1"); args.Add("va2"); args.Add("va3"); - Assert.AreEqual("nvl(va1, nvl(va2, va3))", nf.Render(args, factoryImpl)); + Assert.AreEqual("nvl(va1, nvl(va2, va3))", nf.Render(args, factoryImpl).ToString()); } [Test] @@ -124,13 +125,13 @@ PositionSubstringFunction psf = new PositionSubstringFunction(); args.Add("'a'"); args.Add("va2"); - Assert.AreEqual("position('a' in va2)", psf.Render(args, factoryImpl)); + Assert.AreEqual("position('a' in va2)", psf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("'a'"); args.Add("va2"); args.Add("2"); - Assert.AreEqual("(position('a' in substring(va2, 2))+2-1)", psf.Render(args, factoryImpl)); + Assert.AreEqual("(position('a' in substring(va2, 2))+2-1)", psf.Render(args, factoryImpl).ToString()); } [Test] @@ -145,19 +146,19 @@ ClassicSumFunction csf = new ClassicSumFunction(); args.Add("va1"); - Assert.AreEqual("sum(va1)", csf.Render(args, factoryImpl)); + Assert.AreEqual("sum(va1)", csf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("distinct"); args.Add("va2"); - Assert.AreEqual("sum(distinct va2)", csf.Render(args, factoryImpl)); + Assert.AreEqual("sum(distinct va2)", csf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("va1"); args.Add("va2"); try { - string t = csf.Render(args, factoryImpl); + SqlString t = csf.Render(args, factoryImpl); Assert.Fail("No exception 2 argument without <setquantifier>:" + t); } catch (QueryException) @@ -175,18 +176,18 @@ ClassicCountFunction ccf = new ClassicCountFunction(); args.Add("va1"); - Assert.AreEqual("count(va1)", ccf.Render(args, factoryImpl)); + Assert.AreEqual("count(va1)", ccf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("*"); - Assert.AreEqual("count(*)", ccf.Render(args, factoryImpl)); + Assert.AreEqual("count(*)", ccf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("va1"); args.Add("va2"); try { - string t = ccf.Render(args, factoryImpl); + SqlString t = ccf.Render(args, factoryImpl); Assert.Fail("No exception 2 argument without <setquantifier>:" + t); } catch (QueryException) @@ -207,19 +208,19 @@ ClassicAvgFunction caf = new ClassicAvgFunction(); args.Add("va1"); - Assert.AreEqual("avg(va1)", caf.Render(args, factoryImpl)); + Assert.AreEqual("avg(va1)", caf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("distinct"); args.Add("va2"); - Assert.AreEqual("avg(distinct va2)", caf.Render(args, factoryImpl)); + Assert.AreEqual("avg(distinct va2)", caf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("va1"); args.Add("va2"); try { - string t = caf.Render(args, factoryImpl); + SqlString t = caf.Render(args, factoryImpl); Assert.Fail("No exception 2 argument without <setquantifier>:" + t); } catch (QueryException) @@ -235,19 +236,19 @@ ClassicAggregateFunction caf = new ClassicAggregateFunction("max", false); args.Add("va1"); - Assert.AreEqual("max(va1)", caf.Render(args, factoryImpl)); + Assert.AreEqual("max(va1)", caf.Render(args, factoryImpl).ToString()); args.Clear(); args.Add("d... [truncated message content] |
From: <fab...@us...> - 2008-08-15 05:37:39
|
Revision: 3704 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3704&view=rev Author: fabiomaulo Date: 2008-08-15 05:37:47 +0000 (Fri, 15 Aug 2008) Log Message: ----------- - Ported test for composite-id from H3.2 - Aligned constraint for "join fetch", using <bag>, between HQL and Criteria (removed NH different behavior in BasicLoader) - Changed NH846 according the "new" behavior (the type of the collection was not the matter of the test) Possible Breaking change: - The alignment of constraint should break some Criteria Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs trunk/nhibernate/src/NHibernate/Loader/BasicLoader.cs trunk/nhibernate/src/NHibernate.Test/MultipleCollectionFetchTest/MultipleBagFetchFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH826/Entities.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH826/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH826/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/CompositeId/CompositeIdFixture.cs trunk/nhibernate/src/NHibernate.Test/CompositeId/Customer.cs trunk/nhibernate/src/NHibernate.Test/CompositeId/Customer.hbm.xml trunk/nhibernate/src/NHibernate.Test/CompositeId/LineItem.cs trunk/nhibernate/src/NHibernate.Test/CompositeId/LineItem.hbm.xml trunk/nhibernate/src/NHibernate.Test/CompositeId/Order.cs trunk/nhibernate/src/NHibernate.Test/CompositeId/Order.hbm.xml trunk/nhibernate/src/NHibernate.Test/CompositeId/Product.cs trunk/nhibernate/src/NHibernate.Test/CompositeId/Product.hbm.xml Modified: trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2008-08-14 17:33:32 UTC (rev 3703) +++ trunk/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2008-08-15 05:37:47 UTC (rev 3704) @@ -117,11 +117,14 @@ hasUnsafeCollection = hasUnsafeCollection || IsUnsafe(collectionPersister); - if (count > 1 && hasUnsafeCollection) - { - // The comment only mentions a bag since I don't want to confuse users. - throw new QueryException("Cannot fetch multiple collections in a single query if one of them is a bag"); - } + // NH : This constraint is present in BasicLoader.PostInstantiate + // The constraint here break some tests ported from H3.2 + // where is possible the use of "left join fetch" + //if (count > 1 && hasUnsafeCollection) + //{ + // // The comment only mentions a bag since I don't want to confuse users. + // throw new QueryException("Cannot fetch multiple collections in a single query if one of them is a bag"); + //} names.Add(name); persisters.Add(collectionPersister); Modified: trunk/nhibernate/src/NHibernate/Loader/BasicLoader.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Loader/BasicLoader.cs 2008-08-14 17:33:32 UTC (rev 3703) +++ trunk/nhibernate/src/NHibernate/Loader/BasicLoader.cs 2008-08-15 05:37:47 UTC (rev 3704) @@ -57,11 +57,13 @@ { collectionDescriptors = null; } - // NH Different behavior - //if (bagCount > 1) - //{ - // throw new HibernateException("cannot simultaneously fetch multiple bags"); - //} + // H3.2 : 14.3. Associations and joins + // Join fetching multiple collection roles also sometimes gives unexpected results for bag mappings, + // so be careful about how you formulate your queries in this case + if (bagCount > 1) + { + throw new QueryException("Cannot simultaneously fetch multiple bags."); + } } private static bool IsBag(ICollectionPersister collectionPersister) Added: trunk/nhibernate/src/NHibernate.Test/CompositeId/CompositeIdFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/CompositeId/CompositeIdFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/CompositeId/CompositeIdFixture.cs 2008-08-15 05:37:47 UTC (rev 3704) @@ -0,0 +1,283 @@ +using System; +using System.Collections; +using NUnit.Framework; + +namespace NHibernate.Test.CompositeId +{ + [TestFixture] + public class CompositeIdFixture : TestCase + { + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + protected override IList Mappings + { + get + { + return new string[] + { + "CompositeId.Customer.hbm.xml", "CompositeId.Order.hbm.xml", "CompositeId.LineItem.hbm.xml", + "CompositeId.Product.hbm.xml" + }; + } + } + + protected override string CacheConcurrencyStrategy + { + get { return null; } + } + + [Test] + public void CompositeIds() + { + ISession s; + ITransaction t; + Product p2; + using (s = OpenSession()) + { + t = s.BeginTransaction(); + + Product p = new Product(); + p.ProductId = "A123"; + p.Description = "nipple ring"; + p.Price = 1.0m; + p.NumberAvailable = 1004; + s.Persist(p); + + p2 = new Product(); + p2.ProductId = "X525"; + p2.Description = "nose stud"; + p2.Price = 3.0m; + p2.NumberAvailable = 105; + s.Persist(p2); + + Customer c = new Customer(); + c.Address = "St Kilda Rd, MEL, 3000"; + c.Name = "Virginia"; + c.CustomerId = "C111"; + s.Persist(c); + + Order o = new Order(c); + o.OrderDate = DateTime.Today; + LineItem li = new LineItem(o, p); + li.Quantity = 2; + + t.Commit(); + } + + using (s = OpenSession()) + { + t = s.BeginTransaction(); + Order o = s.Get<Order>(new Order.ID("C111", 0)); + Assert.That(o.Total == 2m); + t.Commit(); + } + + using(s = OpenSession()) + { + t = s.BeginTransaction(); + s.CreateQuery( + "from Customer c left join fetch c.Orders o left join fetch o.LineItems li left join fetch li.Product p").List(); + t.Commit(); + } + + using(s = OpenSession()) + { + t = s.BeginTransaction(); + s.CreateQuery("from Order o left join fetch o.LineItems li left join fetch li.Product p").List(); + t.Commit(); + } + + using(s = OpenSession()) + { + t = s.BeginTransaction(); + IEnumerable iter = s.CreateQuery("select o.id, li.id from Order o join o.LineItems li").List(); + foreach (object[] stuff in iter) + { + Assert.AreEqual(2, stuff.Length); + } + iter = s.CreateQuery("from Order o join o.LineItems li").Enumerable(); + foreach (object[] stuff in iter) + { + Assert.AreEqual(2, stuff.Length); + } + t.Commit(); + } + + using(s = OpenSession()) + { + t = s.BeginTransaction(); + Customer c = s.Get<Customer>("C111"); + Order o2 = new Order(c); + o2.OrderDate = DateTime.Today; + s.Flush(); + LineItem li2 = new LineItem(o2, p2); + li2.Quantity = 5; + IList bigOrders = s.CreateQuery("from Order o where o.Total>10.0").List(); + Assert.AreEqual(1, bigOrders.Count); + t.Commit(); + } + + + using (s = OpenSession()) + { + t = s.BeginTransaction(); + s.Delete("from LineItem"); + s.Delete("from Order"); + s.Delete("from Customer"); + s.Delete("from Product"); + t.Commit(); + } + } + + [Test] + public void MultipleCollectionFetch() + { + ISession s = OpenSession(); + ITransaction t = s.BeginTransaction(); + Product p = new Product(); + p.ProductId = "A123"; + p.Description = "nipple ring"; + p.Price = 1.0m; + p.NumberAvailable = 1004; + s.Persist(p); + + Product p2 = new Product(); + p2.ProductId = "X525"; + p2.Description = "nose stud"; + p2.Price = 3.0m; + p2.NumberAvailable = 105; + s.Persist(p2); + + Customer c = new Customer(); + c.Address = "St Kilda Rd, MEL, 3000"; + c.Name = "Virginia"; + c.CustomerId = "C111"; + s.Persist(c); + + Order o = new Order(c); + o.OrderDate = DateTime.Today; + LineItem li = new LineItem(o, p); + li.Quantity = 2; + LineItem li2 = new LineItem(o, p2); + li2.Quantity = 3; + + Order o2 = new Order(c); + o2.OrderDate = DateTime.Today; + LineItem li3 = new LineItem(o2, p); + li3.Quantity = 1; + LineItem li4 = new LineItem(o2, p2); + li4.Quantity = 1; + + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + c = + (Customer) + s.CreateQuery( + "from Customer c left join fetch c.Orders o left join fetch o.LineItems li left join fetch li.Product p"). + UniqueResult(); + Assert.IsTrue(NHibernateUtil.IsInitialized(c.Orders)); + Assert.AreEqual(2, c.Orders.Count); + Assert.IsTrue(NHibernateUtil.IsInitialized(((Order) c.Orders[0]).LineItems)); + Assert.IsTrue(NHibernateUtil.IsInitialized(((Order) c.Orders[1]).LineItems)); + Assert.AreEqual(((Order) c.Orders[0]).LineItems.Count, 2); + Assert.AreEqual(((Order) c.Orders[1]).LineItems.Count, 2); + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + s.Delete("from LineItem"); + s.Delete("from Order"); + s.Delete("from Customer"); + s.Delete("from Product"); + t.Commit(); + s.Close(); + } + + [Test] + public void NonLazyFetch() + { + ISession s = OpenSession(); + ITransaction t = s.BeginTransaction(); + Product p = new Product(); + p.ProductId = "A123"; + p.Description = "nipple ring"; + p.Price = 1.0m; + p.NumberAvailable = 1004; + s.Persist(p); + + Product p2 = new Product(); + p2.ProductId = "X525"; + p2.Description = "nose stud"; + p2.Price = 3.0m; + p2.NumberAvailable = 105; + s.Persist(p2); + + Customer c = new Customer(); + c.Address = "St Kilda Rd, MEL, 3000"; + c.Name = "Virginia"; + c.CustomerId = "C111"; + s.Persist(c); + + Order o = new Order(c); + o.OrderDate = DateTime.Today; + LineItem li = new LineItem(o, p); + li.Quantity = 2; + + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + o = s.Get<Order>(new Order.ID("C111", 0)); + Assert.AreEqual(2m, o.Total); + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + o = (Order) s.CreateQuery("from Order o left join fetch o.LineItems li left join fetch li.Product p").UniqueResult(); + Assert.IsTrue(NHibernateUtil.IsInitialized(o.LineItems)); + li = (LineItem) o.LineItems[0]; + Assert.IsTrue(NHibernateUtil.IsInitialized(li)); + Assert.IsTrue(NHibernateUtil.IsInitialized(li.Product)); + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + o = (Order) s.CreateQuery("from Order o").UniqueResult(); + Assert.IsTrue(NHibernateUtil.IsInitialized(o.LineItems)); + li = (LineItem) o.LineItems[0]; + Assert.IsTrue(NHibernateUtil.IsInitialized(li)); + Assert.IsFalse(NHibernateUtil.IsInitialized(li.Product)); + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + s.Delete("from LineItem"); + s.Delete("from Order"); + s.Delete("from Customer"); + s.Delete("from Product"); + t.Commit(); + s.Close(); + } + + [Test] + public void Query() + { + ISession s = OpenSession(); + ITransaction t = s.BeginTransaction(); + s.CreateQuery("from LineItem ol where ol.Order.Id.CustomerId = 'C111'").List(); + t.Commit(); + s.Close(); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/CompositeId/Customer.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/CompositeId/Customer.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/CompositeId/Customer.cs 2008-08-15 05:37:47 UTC (rev 3704) @@ -0,0 +1,46 @@ +using System.Collections; +using System; + +namespace NHibernate.Test.CompositeId +{ + public class Customer + { + private string customerId; + private string name; + private string address; + private IList orders = new ArrayList(); + + public virtual string CustomerId + { + get { return customerId; } + set { customerId = value; } + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual string Address + { + get { return address; } + set { address = value; } + } + + public virtual IList Orders + { + get { return orders; } + set { orders = value; } + } + + public virtual Order GenerateNewOrder(decimal total) + { + Order order = new Order(this); + order.OrderDate = DateTime.Today; + order.Total=total; + + return order; + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/CompositeId/Customer.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/CompositeId/Customer.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/CompositeId/Customer.hbm.xml 2008-08-15 05:37:47 UTC (rev 3704) @@ -0,0 +1,33 @@ +<?xml version="1.0"?> +<!-- + + This mapping demonstrates how to map a collection + <key> to one of the primary key columns of an + associated child class with a composite key. This + is very useful for legacy data! + +--> + +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + namespace="NHibernate.Test.CompositeId" + assembly="NHibernate.Test" + default-access="field.camelcase"> + + <class name="Customer"> + + <id name="CustomerId" + length="10"> + <generator class="assigned"/> + </id> + + <property name="Name" not-null="true" length="100"/> + <property name="Address" not-null="true" length="200"/> + + <list name="Orders" inverse="true" cascade="save-update"> + <key column="customerId"/> + <index column="orderNumber"/> + <one-to-many class="Order"/> + </list> + </class> + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/CompositeId/LineItem.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/CompositeId/LineItem.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/CompositeId/LineItem.cs 2008-08-15 05:37:47 UTC (rev 3704) @@ -0,0 +1,92 @@ +namespace NHibernate.Test.CompositeId +{ + public class LineItem + { + public class ID + { + private string customerId; + private int orderNumber; + private string productId; + public ID() {} + public ID(string customerId, int orderNumber, string productId) + { + this.customerId = customerId; + this.orderNumber = orderNumber; + this.productId = productId; + } + + public string CustomerId + { + get { return customerId; } + set { customerId = value; } + } + + public int OrderNumber + { + get { return orderNumber; } + set { orderNumber = value; } + } + + public string ProductId + { + get { return productId; } + set { productId = value; } + } + + public override bool Equals(object obj) + { + ID that = obj as ID; + if (that == null) + return false; + + return customerId == that.customerId && productId == that.productId && orderNumber == that.orderNumber; + } + + public override int GetHashCode() + { + return (customerId != null ? customerId.GetHashCode() : 37) ^ + (productId != null ? productId.GetHashCode() : 31) ^ + orderNumber.GetHashCode(); + } + } + private ID id = new ID(); + private int quantity; + private Order order; + private Product product; + + public LineItem() {} + public LineItem(Order order, Product product) + { + this.order = order; + this.product = product; + id.OrderNumber = order.Id.OrderNumber; + id.CustomerId = order.Id.CustomerId; + id.ProductId = product.ProductId; + order.LineItems.Add(this); + } + + public virtual ID Id + { + get { return id; } + set { id = value; } + } + + public virtual int Quantity + { + get { return quantity; } + set { quantity = value; } + } + + public virtual Order Order + { + get { return order; } + set { order = value; } + } + + public virtual Product Product + { + get { return product; } + set { product = value; } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/CompositeId/LineItem.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/CompositeId/LineItem.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/CompositeId/LineItem.hbm.xml 2008-08-15 05:37:47 UTC (rev 3704) @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<!-- + + This mapping demonstrates + + (1) composite keys and many-to-one associations on + composite keys + + (2) use of insert="false" update="false" on an + association mapping, when the foreign key is + also part of the primary key + +--> + +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + namespace="NHibernate.Test.CompositeId" + assembly="NHibernate.Test" + default-access="field.camelcase"> + + <class name="LineItem"> + + <composite-id name="Id" class="LineItem+ID"> + <key-property name="CustomerId" length="10"/> + <key-property name="OrderNumber"/> + <key-property name="ProductId" length="10"/> + </composite-id> + + <property name="Quantity"/> + + <many-to-one name="Order" insert="false" update="false" not-null="true"> + <column name="customerId"/> + <column name="orderNumber"/> + </many-to-one> + + <many-to-one name="Product" insert="false" update="false" not-null="true" column="productId"/> + </class> + + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/CompositeId/Order.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/CompositeId/Order.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/CompositeId/Order.cs 2008-08-15 05:37:47 UTC (rev 3704) @@ -0,0 +1,99 @@ +using System; +using System.Collections; + +namespace NHibernate.Test.CompositeId +{ + public class Order + { + public class ID + { + private string customerId; + private int orderNumber; + public ID() {} + + public ID(string customerId, int orderNumber) + { + this.customerId = customerId; + this.orderNumber = orderNumber; + } + + public string CustomerId + { + get { return customerId; } + set { customerId = value; } + } + + public int OrderNumber + { + get { return orderNumber; } + set { orderNumber = value; } + } + + public override bool Equals(object obj) + { + ID that = obj as ID; + if (that == null) + return false; + return customerId == that.customerId && orderNumber == that.orderNumber; + } + + public override int GetHashCode() + { + return (customerId != null ? customerId.GetHashCode() : 37) ^ orderNumber.GetHashCode(); + } + } + + private ID id = new ID(); + private DateTime orderDate; + private Customer customer; + private IList lineItems = new ArrayList(); + private decimal total; + + public Order() {} + public Order(Customer customer) + { + this.customer = customer; + id.CustomerId = customer.CustomerId; + id.OrderNumber = customer.Orders.Count; + customer.Orders.Add(this); + } + + public virtual ID Id + { + get { return id; } + set { id = value; } + } + + public virtual DateTime OrderDate + { + get { return orderDate; } + set { orderDate = value; } + } + + public virtual Customer Customer + { + get { return customer; } + set { customer = value; } + } + + public virtual IList LineItems + { + get { return lineItems; } + set { lineItems = value; } + } + + public virtual decimal Total + { + get { return total; } + set { total = value; } + } + + public virtual LineItem GenerateLineItem(Product product, int quantity) + { + LineItem li = new LineItem(this, product); + li.Quantity= quantity; + lineItems.Add(li); + return li; + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/CompositeId/Order.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/CompositeId/Order.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/CompositeId/Order.hbm.xml 2008-08-15 05:37:47 UTC (rev 3704) @@ -0,0 +1,61 @@ +<?xml version="1.0"?> +<!-- + + This mapping demonstrates + + (1) composite keys and one-to-many associations on + composite keys + + (2) use of insert="false" update="false" on an + association mapping, when the foreign key is + also part of the primary key + + (3) use of a derived property which performs a + subselect against associated tables + + (4) use of <synchronize/> to ensure that auto-flush + works correctly for an entity with a property + derived from other tables + + +--> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + namespace="NHibernate.Test.CompositeId" + assembly="NHibernate.Test" + default-access="field.camelcase"> + + <class name="Order" table="CustomerOrder"> + <synchronize table="LineItem"/> + <synchronize table="Product"/> + + <composite-id name="Id" class="Order+ID"> + <key-property name="CustomerId" length="10"/> + <key-property name="OrderNumber"/> + </composite-id> + + <property name="OrderDate" not-null="true"/> + + <property name="Total" + formula="( select sum(li.quantity*p.cost) from LineItem li, Product p where li.productId = p.productId and li.customerId = customerId and li.orderNumber = orderNumber )"/> + + <many-to-one name="Customer" + column="customerId" + insert="false" + update="false" + not-null="true"/> + + <bag name="LineItems" + fetch="join" + lazy="false" + inverse="true" + cascade="save-update"> + <key> + <column name="customerId"/> + <column name="orderNumber"/> + </key> + <one-to-many class="LineItem"/> + </bag> + + </class> + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/CompositeId/Product.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/CompositeId/Product.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/CompositeId/Product.cs 2008-08-15 05:37:47 UTC (rev 3704) @@ -0,0 +1,41 @@ +namespace NHibernate.Test.CompositeId +{ + public class Product + { + private string productId; + private string description; + private decimal price; + private int numberAvailable; + private int numberOrdered; + + public virtual string ProductId + { + get { return productId; } + set { productId = value; } + } + + public virtual string Description + { + get { return description; } + set { description = value; } + } + + public virtual decimal Price + { + get { return price; } + set { price = value; } + } + + public virtual int NumberAvailable + { + get { return numberAvailable; } + set { numberAvailable = value; } + } + + public virtual int NumberOrdered + { + get { return numberOrdered; } + set { numberOrdered = value; } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/CompositeId/Product.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/CompositeId/Product.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/CompositeId/Product.hbm.xml 2008-08-15 05:37:47 UTC (rev 3704) @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<!-- + + This mapping demonstrates + + (1) use of a derived property which performs a + subselect against an associated table + + (2) use of <synchronize/> to ensure that auto-flush + works correctly for an entity with a property + derived from another table + +--> + +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + namespace="NHibernate.Test.CompositeId" + assembly="NHibernate.Test" + default-access="field.camelcase"> + + <class name="Product"> + <synchronize table="LineItem"/> + + <id name="ProductId" length="10"> + <generator class="assigned"/> + </id> + + <property name="Description" not-null="true" length="200"/> + <property name="Price" length="3" column="cost"/> + <property name="NumberAvailable"/> + + <property name="NumberOrdered" + formula="( select sum(li.quantity) from LineItem li where li.productId = productId )"/> + </class> + +</hibernate-mapping> Modified: trunk/nhibernate/src/NHibernate.Test/MultipleCollectionFetchTest/MultipleBagFetchFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MultipleCollectionFetchTest/MultipleBagFetchFixture.cs 2008-08-14 17:33:32 UTC (rev 3703) +++ trunk/nhibernate/src/NHibernate.Test/MultipleCollectionFetchTest/MultipleBagFetchFixture.cs 2008-08-15 05:37:47 UTC (rev 3704) @@ -32,7 +32,7 @@ } catch (QueryException e) { - Assert.IsTrue(e.Message.IndexOf("multiple collections") >= 0); + Assert.IsTrue(e.Message.IndexOf("Cannot simultaneously fetch multiple bags") >= 0); } } @@ -45,7 +45,7 @@ } catch (QueryException e) { - Assert.IsTrue(e.Message.IndexOf("multiple collections") >= 0); + Assert.IsTrue(e.Message.IndexOf("Cannot simultaneously fetch multiple bags") >= 0); } } } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH826/Entities.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH826/Entities.cs 2008-08-14 17:33:32 UTC (rev 3703) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH826/Entities.cs 2008-08-15 05:37:47 UTC (rev 3704) @@ -1,5 +1,6 @@ using System; using System.Collections; +using Iesi.Collections; namespace NHibernate.Test.NHSpecificTest.NH826 { @@ -12,13 +13,26 @@ get { return _id; } set { _id = value; } } + + public override bool Equals(object obj) + { + Entity that = obj as Entity; + if(that == null) + return false; + return _id == that.Id; + } + + public override int GetHashCode() + { + return _id.GetHashCode(); + } } public class ActivitySet : Entity { - private IList _activities = new ArrayList(); + private ISet _activities = new HashedSet(); - public IList Activities + public ISet Activities { get { return _activities; } set { _activities = value; } @@ -31,9 +45,9 @@ public class EvaluationActivity : Activity { - private IList _questions; + private ISet _questions; - public IList Questions + public ISet Questions { get { return _questions; } set { _questions = value; } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH826/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH826/Fixture.cs 2008-08-14 17:33:32 UTC (rev 3703) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH826/Fixture.cs 2008-08-15 05:37:47 UTC (rev 3704) @@ -38,7 +38,10 @@ session.Flush(); - session.Delete(loadedActivitySet.Activities[0]); + foreach (object o in loadedActivitySet.Activities) + { + session.Delete(o); + } session.Delete(loadedActivitySet); transaction.Commit(); Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH826/Mappings.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH826/Mappings.hbm.xml 2008-08-14 17:33:32 UTC (rev 3703) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH826/Mappings.hbm.xml 2008-08-15 05:37:47 UTC (rev 3704) @@ -6,10 +6,10 @@ <generator class="native" /> </id> - <bag name="Activities" lazy="true" table="co_activity_set_membership" cascade="save-update" outer-join="true" inverse="false"> + <set name="Activities" lazy="true" table="co_activity_set_membership" cascade="save-update" outer-join="true" inverse="false"> <key column="ActivitySetId" /> <many-to-many column="ActivityId" class="Activity" /> - </bag> + </set> </class> <class name="Activity" table="co_activity" discriminator-value="0"> @@ -21,10 +21,10 @@ <discriminator column="ActivityType" type="String" /> <subclass name="EvaluationActivity" discriminator-value="3"> - <bag name="Questions" lazy="true" table="" cascade="all-delete-orphan" outer-join="true" inverse="false"> + <set name="Questions" lazy="true" table="" cascade="all-delete-orphan" outer-join="true" inverse="false"> <key column="EvaluationActivityId" /> <one-to-many class="Question" /> - </bag> + </set> </subclass> </class> Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-08-14 17:33:32 UTC (rev 3703) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-08-15 05:37:47 UTC (rev 3704) @@ -99,7 +99,12 @@ <Compile Include="CompositeCollection\CompositeCollection.cs" /> <Compile Include="CompositeId\ClassWithCompositeId.cs" /> <Compile Include="CompositeId\ClassWithCompositeIdFixture.cs" /> + <Compile Include="CompositeId\CompositeIdFixture.cs" /> + <Compile Include="CompositeId\Customer.cs" /> <Compile Include="CompositeId\Id.cs" /> + <Compile Include="CompositeId\LineItem.cs" /> + <Compile Include="CompositeId\Order.cs" /> + <Compile Include="CompositeId\Product.cs" /> <Compile Include="ConnectionStringTest\NamedConnectionStringFixture.cs" /> <Compile Include="ConnectionTest\AggressiveReleaseTest.cs" /> <Compile Include="ConnectionTest\ConnectionManagementTestCase.cs" /> @@ -1395,6 +1400,10 @@ <EmbeddedResource Include="DynamicEntity\Interceptor\Customer.hbm.xml" /> <EmbeddedResource Include="Any\Person.hbm.xml" /> <EmbeddedResource Include="Any\Properties.hbm.xml" /> + <EmbeddedResource Include="CompositeId\Customer.hbm.xml" /> + <EmbeddedResource Include="CompositeId\LineItem.hbm.xml" /> + <EmbeddedResource Include="CompositeId\Order.hbm.xml" /> + <EmbeddedResource Include="CompositeId\Product.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> <EmbeddedResource Include="NHSpecificTest\NH1419\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1413\Mappings.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-08-15 21:41:40
|
Revision: 3706 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3706&view=rev Author: fabiomaulo Date: 2008-08-15 21:41:48 +0000 (Fri, 15 Aug 2008) Log Message: ----------- Start port of enhanced Id generators. Possible breaking change: - IPersistentIdentifierGenerator Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs trunk/nhibernate/src/NHibernate/Dialect/MySQLDialect.cs trunk/nhibernate/src/NHibernate/Dialect/Oracle9Dialect.cs trunk/nhibernate/src/NHibernate/Dialect/PostgreSQL82Dialect.cs trunk/nhibernate/src/NHibernate/Dialect/PostgreSQLDialect.cs trunk/nhibernate/src/NHibernate/Dialect/SQLiteDialect.cs trunk/nhibernate/src/NHibernate/Id/Assigned.cs trunk/nhibernate/src/NHibernate/Id/ForeignGenerator.cs trunk/nhibernate/src/NHibernate/Id/IConfigurable.cs trunk/nhibernate/src/NHibernate/Id/IPersistentIdentifierGenerator.cs trunk/nhibernate/src/NHibernate/Id/IncrementGenerator.cs trunk/nhibernate/src/NHibernate/Id/SequenceGenerator.cs trunk/nhibernate/src/NHibernate/Id/TableGenerator.cs trunk/nhibernate/src/NHibernate/Mapping/Table.cs trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Engine/Transaction/ trunk/nhibernate/src/NHibernate/Engine/Transaction/IIsolatedWork.cs trunk/nhibernate/src/NHibernate/Engine/Transaction/Isolater.cs trunk/nhibernate/src/NHibernate/Engine/TransactionHelper.cs trunk/nhibernate/src/NHibernate/Id/Enhanced/ trunk/nhibernate/src/NHibernate/Id/Enhanced/IAccessCallback.cs trunk/nhibernate/src/NHibernate/Id/Enhanced/IDatabaseStructure.cs trunk/nhibernate/src/NHibernate/Id/Enhanced/IOptimizer.cs trunk/nhibernate/src/NHibernate/Id/Enhanced/OptimizerFactory.cs trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStructure.cs trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStyleGenerator.cs trunk/nhibernate/src/NHibernate/Id/Enhanced/TableStructure.cs trunk/nhibernate/src/NHibernate.Test/IdGen/ trunk/nhibernate/src/NHibernate.Test/IdGen/Enhanced/ trunk/nhibernate/src/NHibernate.Test/IdGen/Enhanced/SequenceStyleConfigUnitFixture.cs Modified: trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -701,9 +701,14 @@ IEnumerable<IPersistentIdentifierGenerator> pIDg = IterateGenerators(dialect); foreach (IPersistentIdentifierGenerator idGen in pIDg) { - string dropString = idGen.SqlDropString(dialect); - if (dropString != null) - script.Add(dropString); + string[] lines = idGen.SqlDropString(dialect); + if (lines != null) + { + foreach (string line in lines) + { + script.Add(line); + } + } } return script.ToArray(); Modified: trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -393,7 +393,7 @@ /// <summary> /// Completely optional cascading drop clause /// </summary> - protected virtual string CascadeConstraintsString + public virtual string CascadeConstraintsString { get { return String.Empty; } } @@ -669,7 +669,7 @@ /// <summary> /// Does the dialect support the syntax 'drop table if exists NAME' /// </summary> - protected virtual bool SupportsIfExistsBeforeTableName + public virtual bool SupportsIfExistsBeforeTableName { get { return false; } } @@ -677,7 +677,7 @@ /// <summary> /// Does the dialect support the syntax 'drop table NAME if exists' /// </summary> - protected virtual bool SupportsIfExistsAfterTableName + public virtual bool SupportsIfExistsAfterTableName { get { return false; } } Modified: trunk/nhibernate/src/NHibernate/Dialect/MySQLDialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/MySQLDialect.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Dialect/MySQLDialect.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -112,7 +112,7 @@ get { return '`'; } } - protected override bool SupportsIfExistsBeforeTableName + public override bool SupportsIfExistsBeforeTableName { get { return true; } } Modified: trunk/nhibernate/src/NHibernate/Dialect/Oracle9Dialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/Oracle9Dialect.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Dialect/Oracle9Dialect.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -162,7 +162,7 @@ } /// <summary></summary> - protected override string CascadeConstraintsString + public override string CascadeConstraintsString { get { return " cascade constraints"; } } Modified: trunk/nhibernate/src/NHibernate/Dialect/PostgreSQL82Dialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/PostgreSQL82Dialect.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Dialect/PostgreSQL82Dialect.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -18,7 +18,7 @@ RegisterColumnType(DbType.Guid, "uuid"); } - protected override bool SupportsIfExistsBeforeTableName + public override bool SupportsIfExistsBeforeTableName { get { return true; } } Modified: trunk/nhibernate/src/NHibernate/Dialect/PostgreSQLDialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/PostgreSQLDialect.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Dialect/PostgreSQLDialect.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -77,7 +77,7 @@ get { return false; } } - protected override string CascadeConstraintsString + public override string CascadeConstraintsString { get { return " cascade"; } } Modified: trunk/nhibernate/src/NHibernate/Dialect/SQLiteDialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/SQLiteDialect.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Dialect/SQLiteDialect.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -79,7 +79,7 @@ get { return true; } } - protected override bool SupportsIfExistsBeforeTableName + public override bool SupportsIfExistsBeforeTableName { get { return true; } } Added: trunk/nhibernate/src/NHibernate/Engine/Transaction/IIsolatedWork.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/Transaction/IIsolatedWork.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Engine/Transaction/IIsolatedWork.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -0,0 +1,18 @@ +using System.Data; + +namespace NHibernate.Engine.Transaction +{ + /// <summary> + /// Represents work that needs to be performed in a manner + /// which isolates it from any current application unit of + /// work transaction. + /// </summary> + public interface IIsolatedWork + { + /// <summary> + /// Perform the actual work to be done. + /// </summary> + /// <param name="connection">The ADP cpnnection to use.</param> + void DoWork(IDbConnection connection); + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Engine/Transaction/Isolater.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/Transaction/Isolater.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Engine/Transaction/Isolater.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -0,0 +1,150 @@ +using System; +using System.Data; +using System.Data.Common; +using log4net; +using NHibernate.Exceptions; + +namespace NHibernate.Engine.Transaction +{ + /// <summary> + /// Class which provides the isolation semantics required by + /// an <see cref="IIsolatedWork"/>. + /// </summary> + /// <remarks> + /// <list type="bullet"> + /// <listheader> + /// <description>Processing comes in two flavors:</description> + /// </listheader> + /// <item> + /// <term><see cref="DoIsolatedWork"/> </term> + /// <description>makes sure the work to be done is performed in a seperate, distinct transaction</description> + /// </item> + /// <item> + /// <term><see cref="DoNonTransactedWork"/> </term> + /// <description>makes sure the work to be done is performed outside the scope of any transaction</description> + /// </item> + /// </list> + /// </remarks> + public class Isolater + { + private static readonly ILog log = LogManager.GetLogger(typeof(Isolater)); + + private static DoWork GetApropieateDelegate() + { + bool isAmbientTransation = System.Transactions.Transaction.Current != null; + if (isAmbientTransation) + { + return AmbientDelegateWork; + } + else + { + return AdoDelegateWork; + } + } + /// <summary> + /// Ensures that all processing actually performed by the given work will + /// occur on a seperate transaction. + /// </summary> + /// <param name="work">The work to be performed. </param> + /// <param name="session">The session from which this request is originating. </param> + public static void DoIsolatedWork(IIsolatedWork work, ISessionImplementor session) + { + DoWork worker = GetApropieateDelegate(); + worker(session, work, true); + } + + /// <summary> + /// Ensures that all processing actually performed by the given work will + /// occur outside of a transaction. + /// </summary> + /// <param name="work">The work to be performed. </param> + /// <param name="session">The session from which this request is originating. </param> + public static void DoNonTransactedWork(IIsolatedWork work, ISessionImplementor session) + { + DoWork worker = GetApropieateDelegate(); + worker(session, work, false); + } + + private delegate void DoWork(ISessionImplementor session, IIsolatedWork work, bool transacted); + + private static void AdoDelegateWork(ISessionImplementor session, IIsolatedWork work, bool transacted) + { + IDbConnection connection = null; + IDbTransaction trans = null; + // bool wasAutoCommit = false; + try + { + connection = session.Factory.ConnectionProvider.GetConnection(); + + if (transacted) + { + trans = connection.BeginTransaction(); + // TODO NH: a way to read the autocommit state is needed + //if (TransactionManager.GetAutoCommit(connection)) + //{ + // wasAutoCommit = true; + // TransactionManager.SetAutoCommit(connection, false); + //} + } + + work.DoWork(connection); + + if (transacted) + { + trans.Commit(); + //TransactionManager.Commit(connection); + } + } + catch (Exception t) + { + try + { + if (transacted && connection != null && !(connection.State == ConnectionState.Closed)) + { + trans.Rollback(); + // TransactionManager.RollBack(connection); + } + } + catch (Exception ignore) + { + log.Debug("unable to release connection on exception [" + ignore + "]"); + } + + if (t is HibernateException) + { + throw; + } + else if (t is DbException) + { + throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, t, "error performing isolated work"); + } + else + { + throw new HibernateException("error performing isolated work", t); + } + } + finally + { + //if (transacted && wasAutoCommit) + //{ + // try + // { + // // TODO NH: reset autocommit + // // TransactionManager.SetAutoCommit(connection, true); + // } + // catch (Exception) + // { + // log.Debug("was unable to reset connection back to auto-commit"); + // } + //} + session.Factory.ConnectionProvider.CloseConnection(connection); + } + } + + private static void AmbientDelegateWork(ISessionImplementor session, IIsolatedWork work, bool transacted) + { + throw new NotSupportedException("Not supported yet."); + } + + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Engine/TransactionHelper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/TransactionHelper.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Engine/TransactionHelper.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -0,0 +1,53 @@ +using System.Data; +using NHibernate.Engine.Transaction; +using NHibernate.Exceptions; + +namespace NHibernate.Engine +{ + /// <summary> + /// Allows work to be done outside the current transaction, by suspending it, + /// and performing work in a new transaction + /// </summary> + public abstract class TransactionHelper + { + public class Work : IIsolatedWork + { + private readonly ISessionImplementor session; + private readonly TransactionHelper owner; + internal object generatedValue; + + public Work(ISessionImplementor session, TransactionHelper owner) + { + this.session = session; + this.owner = owner; + } + + #region Implementation of IIsolatedWork + + public void DoWork(IDbConnection connection) + { + try + { + generatedValue = owner.DoWorkInCurrentTransaction(connection, null); + } + catch (System.Data.OleDb.OleDbException sqle) + { + throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, sqle, "could not get or update next value", null); + } + } + + #endregion + } + + /// <summary> The work to be done</summary> + public abstract object DoWorkInCurrentTransaction(IDbConnection conn, string sql); + + /// <summary> Suspend the current transaction and perform work in a new transaction</summary> + public virtual object DoWorkInNewTransaction(ISessionImplementor session) + { + Work work = new Work(session, this); + Isolater.DoIsolatedWork(work, session); + return work.generatedValue; + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Id/Assigned.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/Assigned.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Id/Assigned.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -52,7 +52,7 @@ #region IConfigurable Members - public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect d) + public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect dialect) { parms.TryGetValue(IdGeneratorParmsNames.EntityName, out entityName); if (entityName == null) Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/IAccessCallback.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/Enhanced/IAccessCallback.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Id/Enhanced/IAccessCallback.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -0,0 +1,12 @@ +namespace NHibernate.Id.Enhanced +{ + /// <summary> + /// Contract for providing callback access to a <see cref="IDatabaseStructure"/>, + /// typically from the <see cref="IOptimizer"/>. + /// </summary> + public interface IAccessCallback + { + /// <summary> Retrieve the next value from the underlying source. </summary> + long NextValue { get;} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/IDatabaseStructure.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/Enhanced/IDatabaseStructure.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Id/Enhanced/IDatabaseStructure.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -0,0 +1,44 @@ +using NHibernate.Engine; + +namespace NHibernate.Id.Enhanced +{ + /// <summary> + /// Encapsulates definition of the underlying data structure backing a sequence-style generator. + /// </summary> + public interface IDatabaseStructure + { + /// <summary> The name of the database structure (table or sequence).</summary> + string Name { get; } + + /// <summary> How many times has this structure been accessed through this reference?</summary> + int TimesAccessed { get; } + + /// <summary> The configured increment size</summary> + int IncrementSize { get; } + + /// <summary> + /// A callback to be able to get the next value from the underlying + /// structure as needed. + /// </summary> + /// <param name="session">The session. </param> + /// <returns> The next value. </returns> + IAccessCallback BuildCallback(ISessionImplementor session); + + /// <summary> + /// Prepare this structure for use. Called sometime after instantiation, + /// but before first use. + /// </summary> + /// <param name="optimizer">The optimizer being applied to the generator. </param> + void Prepare(IOptimizer optimizer); + + /// <summary> Commands needed to create the underlying structures.</summary> + /// <param name="dialect">The database dialect being used. </param> + /// <returns> The creation commands. </returns> + string[] SqlCreateStrings(Dialect.Dialect dialect); + + /// <summary> Commands needed to drop the underlying structures.</summary> + /// <param name="dialect">The database dialect being used. </param> + /// <returns> The drop commands. </returns> + string[] SqlDropStrings(Dialect.Dialect dialect); + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/IOptimizer.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/Enhanced/IOptimizer.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Id/Enhanced/IOptimizer.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -0,0 +1,54 @@ +namespace NHibernate.Id.Enhanced +{ + /// <summary> + /// Performs optimization on an optimizable identifier generator. Typically + /// this optimization takes the form of trying to ensure we do not have to + /// hit the database on each and every request to get an identifier value. + /// </summary> + /// <remarks> + /// <para> + /// Optimizers work on constructor injection. They should provide + /// a constructor with the following arguments. + /// </para> + /// - <see cref="System.Type"/> The return type for the generated values. + /// - <langword>int</langword> The increment size. + /// </remarks> + public interface IOptimizer + { + /// <summary> + /// A common means to access the last value obtained from the underlying + /// source. This is intended for testing purposes, since accessing the + /// unerlying database source directly is much more difficult. + /// </summary> + /// <value> + /// The last value we obtained from the underlying source; + /// -1 indicates we have not yet consulted with the source. + /// </value> + long LastSourceValue{get;} + /// <summary> + /// Defined increment size. + /// </summary> + /// <value> The increment size. + /// </value> + int IncrementSize{get;} + + /// <summary> + /// Generate an identifier value accounting for this specific optimization. + /// </summary> + /// <param name="callback">Callback to access the underlying value source. </param> + /// <returns> The generated identifier value. </returns> + object Generate(IAccessCallback callback); + + /// <summary> + /// Are increments to be applied to the values stored in the underlying + /// value source? + /// </summary> + /// <returns> + /// True if the values in the source are to be incremented + /// according to the defined increment size; false otherwise, in which + /// case the increment is totally an in memory construct. + /// </returns> + bool ApplyIncrementSizeToSourceValues { get;} + + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/OptimizerFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/Enhanced/OptimizerFactory.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Id/Enhanced/OptimizerFactory.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -0,0 +1,265 @@ +using System; +using System.Reflection; +using log4net; +using NHibernate.Util; + +namespace NHibernate.Id.Enhanced +{ + public class OptimizerFactory + { + public const string HiLo = "hilo"; + public const string None = "none"; + public const string Pool = "pooled"; + private static readonly System.Type[] CtorSignature = new System.Type[] {typeof (System.Type), typeof (int)}; + private static readonly ILog log = LogManager.GetLogger(typeof (OptimizerFactory)); + + public static IOptimizer BuildOptimizer(string type, System.Type returnClass, int incrementSize) + { + if (string.IsNullOrEmpty(type)) + { + throw new ArgumentNullException("type"); + } + if (returnClass == null) + { + throw new ArgumentNullException("returnClass"); + } + string optimizerClassName; + switch (type) + { + case None: + optimizerClassName = typeof (NoopOptimizer).FullName; + break; + case HiLo: + optimizerClassName = typeof (HiLoOptimizer).FullName; + break; + case Pool: + optimizerClassName = typeof (PooledOptimizer).FullName; + break; + default: + optimizerClassName = type; + break; + } + + try + { + System.Type optimizerClass = ReflectHelper.ClassForName(optimizerClassName); + ConstructorInfo ctor = optimizerClass.GetConstructor(CtorSignature); + return (IOptimizer)ctor.Invoke(new object[] { returnClass, incrementSize }); + } + catch (Exception) + { + // intentionally empty + } + + // the default... + return new NoopOptimizer(returnClass, incrementSize); + } + + #region Nested type: HiLoOptimizer + + public class HiLoOptimizer : OptimizerSupport + { + private long hiValue; + private long lastSourceValue = -1; + private long value_Renamed; + + public HiLoOptimizer(System.Type returnClass, int incrementSize) : base(returnClass, incrementSize) + { + if (incrementSize < 1) + { + throw new HibernateException("increment size cannot be less than 1"); + } + if (log.IsDebugEnabled) + { + log.Debug("creating hilo optimizer with [incrementSize=" + incrementSize + "; returnClass=" + returnClass.FullName + + "]"); + } + } + + public override long LastSourceValue + { + get { return lastSourceValue; } + } + + public long LastValue + { + get { return value_Renamed - 1; } + } + + public long HiValue + { + get { return hiValue; } + } + + public override bool ApplyIncrementSizeToSourceValues + { + get { return false; } + } + + public override object Generate(IAccessCallback callback) + { + if (lastSourceValue < 0) + { + lastSourceValue = callback.NextValue; + while (lastSourceValue <= 0) + { + lastSourceValue = callback.NextValue; + } + hiValue = (lastSourceValue * incrementSize) + 1; + value_Renamed = hiValue - incrementSize; + } + else if (value_Renamed >= hiValue) + { + lastSourceValue = callback.NextValue; + hiValue = (lastSourceValue * incrementSize) + 1; + } + return Make(value_Renamed++); + } + } + + #endregion + + #region Nested type: NoopOptimizer + + public class NoopOptimizer : OptimizerSupport + { + private long lastSourceValue = -1; + + public NoopOptimizer(System.Type returnClass, int incrementSize) : base(returnClass, incrementSize) {} + + public override long LastSourceValue + { + get { return lastSourceValue; } + } + + public override bool ApplyIncrementSizeToSourceValues + { + get { return false; } + } + + public override object Generate(IAccessCallback callback) + { + if (lastSourceValue == -1) + { + while (lastSourceValue <= 0) + { + lastSourceValue = callback.NextValue; + } + } + else + { + lastSourceValue = callback.NextValue; + } + return Make(lastSourceValue); + } + } + + #endregion + + #region Nested type: OptimizerSupport + + public abstract class OptimizerSupport : IOptimizer + { + protected int incrementSize; + protected System.Type returnClass; + + protected OptimizerSupport(System.Type returnClass, int incrementSize) + { + if (returnClass == null) + { + throw new HibernateException("return class is required"); + } + this.returnClass = returnClass; + this.incrementSize = incrementSize; + } + + public System.Type ReturnClass + { + get { return returnClass; } + } + + #region IOptimizer Members + + public int IncrementSize + { + get { return incrementSize; } + } + + public abstract long LastSourceValue { get; } + + public abstract bool ApplyIncrementSizeToSourceValues { get; } + public abstract object Generate(IAccessCallback param); + + #endregion + + protected virtual object Make(long value) + { + return IdentifierGeneratorFactory.CreateNumber(value, returnClass); + } + } + + #endregion + + #region Nested type: PooledOptimizer + + public class PooledOptimizer : OptimizerSupport + { + private long hiValue = -1; + private long value_Renamed; + + public PooledOptimizer(System.Type returnClass, int incrementSize) : base(returnClass, incrementSize) + { + if (incrementSize < 1) + { + throw new HibernateException("increment size cannot be less than 1"); + } + if (log.IsDebugEnabled) + { + log.Debug("creating pooled optimizer with [incrementSize=" + incrementSize + "; returnClass=" + + returnClass.FullName + "]"); + } + } + + public override long LastSourceValue + { + get { return hiValue; } + } + + public long LastValue + { + get { return value_Renamed - 1; } + } + + public override bool ApplyIncrementSizeToSourceValues + { + get { return true; } + } + + public override object Generate(IAccessCallback callback) + { + if (hiValue < 0) + { + value_Renamed = callback.NextValue; + if (value_Renamed < 1) + { + // unfortunately not really safe to normalize this + // to 1 as an initial value like we do the others + // because we would not be able to control this if + // we are using a sequence... + log.Info("pooled optimizer source reported [" + value_Renamed + + "] as the initial value; use of 1 or greater highly recommended"); + } + hiValue = callback.NextValue; + } + else if (value_Renamed >= hiValue) + { + hiValue = callback.NextValue; + value_Renamed = hiValue - incrementSize; + } + return Make(value_Renamed++); + } + } + + #endregion + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStructure.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStructure.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStructure.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -0,0 +1,140 @@ +using System; +using System.Data; +using System.Data.Common; +using log4net; +using NHibernate.Engine; +using NHibernate.Exceptions; +using NHibernate.SqlCommand; +using NHibernate.SqlTypes; + +namespace NHibernate.Id.Enhanced +{ + /// <summary> + /// Describes a sequence. + /// </summary> + public class SequenceStructure : IDatabaseStructure + { + private static readonly ILog log = LogManager.GetLogger(typeof (SequenceStructure)); + private readonly int incrementSize; + private readonly int initialValue; + private readonly string sequenceName; + private readonly SqlString sql; + private int accessCounter; + private bool applyIncrementSizeToSourceValues; + + public SequenceStructure(Dialect.Dialect dialect, string sequenceName, int initialValue, int incrementSize) + { + this.sequenceName = sequenceName; + this.initialValue = initialValue; + this.incrementSize = incrementSize; + sql = new SqlString(dialect.GetSequenceNextValString(sequenceName)); + } + + #region IDatabaseStructure Members + + public string Name + { + get { return sequenceName; } + } + + public int IncrementSize + { + get { return incrementSize; } + } + + public IAccessCallback BuildCallback(ISessionImplementor session) + { + return new SequenceAccessCallback(session, this); + } + + public void Prepare(IOptimizer optimizer) + { + applyIncrementSizeToSourceValues = optimizer.ApplyIncrementSizeToSourceValues; + } + + public string[] SqlCreateStrings(Dialect.Dialect dialect) + { + int sourceIncrementSize = applyIncrementSizeToSourceValues ? incrementSize : 1; + return dialect.GetCreateSequenceStrings(sequenceName, initialValue, sourceIncrementSize); + } + + public string[] SqlDropStrings(Dialect.Dialect dialect) + { + return dialect.GetDropSequenceStrings(sequenceName); + } + + public int TimesAccessed + { + get { return accessCounter; } + } + + #endregion + + #region Nested type: SequenceAccessCallback + + private class SequenceAccessCallback : IAccessCallback + { + private readonly SequenceStructure owner; + private readonly ISessionImplementor session; + + public SequenceAccessCallback(ISessionImplementor session, SequenceStructure owner) + { + this.session = session; + this.owner = owner; + } + + #region IAccessCallback Members + + public virtual long NextValue + { + get + { + owner.accessCounter++; + try + { + IDbCommand st = session.Batcher.PrepareCommand(CommandType.Text, owner.sql, new SqlType[] {SqlTypeFactory.Int64}); + IDataReader rs = null; + try + { + rs = session.Batcher.ExecuteReader(st); + try + { + rs.Read(); + long result = rs.GetInt64(0); + if (log.IsDebugEnabled) + { + log.Debug("Sequence identifier generated: " + result); + } + return result; + } + finally + { + try + { + rs.Close(); + } + catch (Exception ignore) + { + // intentionally empty + } + } + } + finally + { + session.Batcher.CloseCommand(st, rs); + } + } + catch (DbException sqle) + { + throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, sqle, "could not get next sequence value", + owner.sql); + } + } + } + + #endregion + } + + #endregion + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStyleGenerator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStyleGenerator.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStyleGenerator.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -0,0 +1,133 @@ +using System.Collections.Generic; +using log4net; +using NHibernate.Engine; +using NHibernate.Mapping; +using NHibernate.Type; +using NHibernate.Util; + +namespace NHibernate.Id.Enhanced +{ + public class SequenceStyleGenerator : IPersistentIdentifierGenerator, IConfigurable + { + private static readonly ILog log = LogManager.GetLogger(typeof(SequenceStyleGenerator)); + + #region General purpose parameters + + public const string SequenceParam = "sequence_name"; + public const string DefaultSequenceName = "hibernate_sequence"; + + public const string InitialParam = "initial_value"; + public const int DefaultInitialValue = 1; + + public const string IncrementParam= "increment_size"; + public const int DefaultIncrementSize = 1; + + public const string OptimizerParam= "optimizer"; + + public const string ForceTableParam = "force_table_use"; + + #endregion + + #region table-specific parameters + + public const string ValueColumnParam= "value_column"; + public const string DefaultValueColumnName = "next_val"; + + #endregion + + private IDatabaseStructure databaseStructure; + private IOptimizer optimizer; + private IType identifierType; + + public IDatabaseStructure DatabaseStructure + { + get { return databaseStructure; } + } + + public IOptimizer Optimizer + { + get { return optimizer; } + } + + public IType IdentifierType + { + get { return identifierType; } + } + + #region Implementation of IIdentifierGenerator + + public virtual object Generate(ISessionImplementor session, object obj) + { + return optimizer.Generate(databaseStructure.BuildCallback(session)); + } + + #endregion + + #region Implementation of IPersistentIdentifierGenerator + + public virtual string[] SqlCreateStrings(Dialect.Dialect dialect) + { + return databaseStructure.SqlCreateStrings(dialect); + } + + public virtual string[] SqlDropString(Dialect.Dialect dialect) + { + return databaseStructure.SqlDropStrings(dialect); + } + + public virtual string GeneratorKey() + { + return databaseStructure.Name; + } + + #endregion + + #region Implementation of IConfigurable + + public virtual void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect dialect) + { + identifierType = type; + bool forceTableUse = PropertiesHelper.GetBoolean(ForceTableParam, parms, false); + + string sequenceName = PropertiesHelper.GetString(SequenceParam, parms, DefaultSequenceName); + if (sequenceName.IndexOf('.') < 0) + { + string schemaName; + string catalogName; + parms.TryGetValue(PersistentIdGeneratorParmsNames.Schema, out schemaName); + parms.TryGetValue(PersistentIdGeneratorParmsNames.Catalog, out catalogName); + sequenceName = Table.Qualify(catalogName, schemaName, sequenceName); + } + int initialValue = PropertiesHelper.GetInt32(InitialParam, parms, DefaultInitialValue); + int incrementSize = PropertiesHelper.GetInt32(IncrementParam, parms, DefaultIncrementSize); + + string valueColumnName = PropertiesHelper.GetString(ValueColumnParam, parms, DefaultValueColumnName); + + string defOptStrategy = incrementSize <= 1 ? OptimizerFactory.None : OptimizerFactory.Pool; + string optimizationStrategy = PropertiesHelper.GetString(OptimizerParam, parms, defOptStrategy); + if (OptimizerFactory.None.Equals(optimizationStrategy) && incrementSize > 1) + { + log.Warn("config specified explicit optimizer of [" + OptimizerFactory.None + "], but [" + IncrementParam + "=" + incrementSize + "; honoring optimizer setting"); + incrementSize = 1; + } + if (dialect.SupportsSequences && !forceTableUse) + { + if (OptimizerFactory.Pool.Equals(optimizationStrategy) && !dialect.SupportsPooledSequences) + { + // TODO : may even be better to fall back to a pooled table strategy here so that the db stored values remain consistent... + optimizationStrategy = OptimizerFactory.HiLo; + } + databaseStructure = new SequenceStructure(dialect, sequenceName, initialValue, incrementSize); + } + else + { + databaseStructure = new TableStructure(dialect, sequenceName, valueColumnName, initialValue, incrementSize); + } + + optimizer = OptimizerFactory.BuildOptimizer(optimizationStrategy, identifierType.ReturnedClass, incrementSize); + databaseStructure.Prepare(optimizer); + } + + #endregion + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/TableStructure.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/Enhanced/TableStructure.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Id/Enhanced/TableStructure.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -0,0 +1,198 @@ +using System; +using System.Data; +using System.Text; +using log4net; +using NHibernate.Engine; +using NHibernate.SqlCommand; +using NHibernate.SqlTypes; + +namespace NHibernate.Id.Enhanced +{ + /// <summary> + /// Describes a table used to mimic sequence behavior + /// </summary> + public class TableStructure : TransactionHelper, IDatabaseStructure + { + private static readonly ILog log = LogManager.GetLogger(typeof (IDatabaseStructure)); + private static readonly ILog SqlLog = LogManager.GetLogger("NHibernate.SQL"); + private readonly int incrementSize; + private readonly int initialValue; + private readonly string tableName; + private readonly string valueColumnName; + private int accessCounter; + private bool applyIncrementSizeToSourceValues; + private readonly SqlString select; + private readonly SqlString update; + + public TableStructure(Dialect.Dialect dialect, string tableName, string valueColumnName, int initialValue, + int incrementSize) + { + this.tableName = tableName; + this.valueColumnName = valueColumnName; + this.initialValue = initialValue; + this.incrementSize = incrementSize; + + SqlStringBuilder b = new SqlStringBuilder(); + b.Add("select ").Add(valueColumnName).Add(" id_val").Add(" from ").Add(dialect.AppendLockHint(LockMode.Upgrade, + tableName)).Add( + dialect.ForUpdateString); + select = b.ToSqlString(); + + b = new SqlStringBuilder(); + b.Add("update ").Add(tableName).Add(" set ").Add(valueColumnName).Add(" = ").Add(Parameter.Placeholder).Add(" where ") + .Add(valueColumnName).Add(" = ").Add(Parameter.Placeholder); + update = b.ToSqlString(); + } + + #region Implementation of IDatabaseStructure + + public string Name + { + get { return tableName; } + } + + public int TimesAccessed + { + get { return accessCounter; } + } + + public int IncrementSize + { + get { return incrementSize; } + } + + public virtual IAccessCallback BuildCallback(ISessionImplementor session) + { + return new TableAccessCallback(session, this); + } + + public virtual void Prepare(IOptimizer optimizer) + { + applyIncrementSizeToSourceValues = optimizer.ApplyIncrementSizeToSourceValues; + } + + public virtual string[] SqlCreateStrings(Dialect.Dialect dialect) + { + return new String[] + { + "create table " + tableName + " ( " + valueColumnName + " " + dialect.GetTypeName(SqlTypeFactory.Int64) + + " )", "insert into " + tableName + " values ( " + initialValue + " )" + }; + } + + public virtual string[] SqlDropStrings(Dialect.Dialect dialect) + { + StringBuilder sqlDropString = new StringBuilder().Append("drop table "); + if (dialect.SupportsIfExistsBeforeTableName) + { + sqlDropString.Append("if exists "); + } + sqlDropString.Append(tableName).Append(dialect.CascadeConstraintsString); + if (dialect.SupportsIfExistsAfterTableName) + { + sqlDropString.Append(" if exists"); + } + return new String[] {sqlDropString.ToString()}; + } + + #endregion + + #region Overrides of TransactionHelper + + public override object DoWorkInCurrentTransaction(IDbConnection conn, string sql) + { + long result; + int rows; + do + { + string query = select.ToString(); + SqlLog.Debug(query); + IDbCommand qps = conn.CreateCommand(); + IDataReader rs = null; + qps.CommandText = query; + qps.CommandType = CommandType.Text; + qps.Transaction = conn.BeginTransaction(); + try + { + rs = qps.ExecuteReader(); + if (!rs.Read()) + { + string err = "could not read a hi value - you need to populate the table: " + tableName; + log.Error(err); + throw new IdentifierGenerationException(err); + } + result = rs.GetInt64(0); + rs.Close(); + } + catch (Exception sqle) + { + log.Error("could not read a hi value", sqle); + throw; + } + finally + { + if (rs != null) rs.Close(); + qps.Dispose(); + } + + query = update.ToString(); + SqlLog.Debug(sql); + IDbCommand ups = conn.CreateCommand(); + ups.CommandType = CommandType.Text; + ups.CommandText = query; + ups.Connection = conn; + ups.Transaction = conn.BeginTransaction(); + try + { + int increment = applyIncrementSizeToSourceValues ? incrementSize : 1; + ((IDataParameter) ups.Parameters[0]).Value = result + increment; + ((IDataParameter)ups.Parameters[1]).Value = result; + rows = ups.ExecuteNonQuery(); + } + catch (Exception sqle) + { + log.Error("could not update hi value in: " + tableName, sqle); + throw; + } + finally + { + ups.Dispose(); + } + } + while (rows == 0); + + accessCounter++; + + return result; + } + + #endregion + + #region Nested type: TableAccessCallback + + private class TableAccessCallback : IAccessCallback + { + private readonly TableStructure owner; + private readonly ISessionImplementor session; + + public TableAccessCallback(ISessionImplementor session, TableStructure owner) + { + this.session = session; + this.owner = owner; + } + + #region IAccessCallback Members + + public virtual long NextValue + { + get { return Convert.ToInt64(owner.DoWorkInNewTransaction(session)); } + } + + #endregion + } + + #endregion + + + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Id/ForeignGenerator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/ForeignGenerator.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Id/ForeignGenerator.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -82,11 +82,11 @@ /// </summary> /// <param name="type">The <see cref="IType"/> the identifier should be.</param> /// <param name="parms">An <see cref="IDictionary"/> of Param values that are keyed by parameter name.</param> - /// <param name="d">The <see cref="Dialect.Dialect"/> to help with Configuration.</param> + /// <param name="dialect">The <see cref="Dialect.Dialect"/> to help with Configuration.</param> /// <exception cref="MappingException"> /// Thrown if the key <c>property</c> is not found in the <c>parms</c> parameter. /// </exception> - public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect d) + public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect dialect) { parms.TryGetValue(IdGeneratorParmsNames.EntityName, out entityName); parms.TryGetValue("property", out propertyName); Modified: trunk/nhibernate/src/NHibernate/Id/IConfigurable.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/IConfigurable.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Id/IConfigurable.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -16,7 +16,7 @@ /// </summary> /// <param name="type">The <see cref="IType"/> the identifier should be.</param> /// <param name="parms">An <see cref="IDictionary"/> of Param values that are keyed by parameter name.</param> - /// <param name="d">The <see cref="Dialect.Dialect"/> to help with Configuration.</param> - void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect d); + /// <param name="dialect">The <see cref="Dialect.Dialect"/> to help with Configuration.</param> + void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect dialect); } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Id/IPersistentIdentifierGenerator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/IPersistentIdentifierGenerator.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Id/IPersistentIdentifierGenerator.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -53,7 +53,7 @@ /// <returns> /// A <see cref="String"/> that will drop the database objects. /// </returns> - string SqlDropString(Dialect.Dialect dialect); + string[] SqlDropString(Dialect.Dialect dialect); /// <summary> /// Return a key unique to the underlying database objects. Modified: trunk/nhibernate/src/NHibernate/Id/IncrementGenerator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/IncrementGenerator.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Id/IncrementGenerator.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -38,8 +38,8 @@ /// </summary> /// <param name="type"></param> /// <param name="parms"></param> - /// <param name="d"></param> - public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect d) + /// <param name="dialect"></param> + public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect dialect) { string tableList; string column; @@ -62,7 +62,7 @@ { buf.Append("select ").Append(column).Append(" from "); } - buf.Append(d.Qualify(catalog, schema, tables[i])); + buf.Append(dialect.Qualify(catalog, schema, tables[i])); if (i < tables.Length - 1) buf.Append(" union "); } Modified: trunk/nhibernate/src/NHibernate/Id/SequenceGenerator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/SequenceGenerator.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Id/SequenceGenerator.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -4,7 +4,6 @@ using log4net; using NHibernate.Engine; using NHibernate.Exceptions; -using NHibernate.Mapping; using NHibernate.SqlCommand; using NHibernate.SqlTypes; using NHibernate.Type; @@ -157,9 +156,9 @@ /// <returns> /// A <see cref="String"/> that will drop the database objects for the SequenceGenerator. /// </returns> - public string SqlDropString(Dialect.Dialect dialect) + public string[] SqlDropString(Dialect.Dialect dialect) { - return dialect.GetDropSequenceString(sequenceName); + return new string[] { dialect.GetDropSequenceString(sequenceName) }; } /// <summary> Modified: trunk/nhibernate/src/NHibernate/Id/TableGenerator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Id/TableGenerator.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Id/TableGenerator.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -286,9 +286,9 @@ /// <returns> /// A <see cref="string"/> that will drop the database objects for the TableGenerator. /// </returns> - public string SqlDropString(Dialect.Dialect dialect) + public string[] SqlDropString(Dialect.Dialect dialect) { - return dialect.GetDropTableString(tableName); + return new string[] { dialect.GetDropTableString(tableName) }; } /// <summary> Modified: trunk/nhibernate/src/NHibernate/Mapping/Table.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/Table.cs 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/Mapping/Table.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -1022,5 +1022,19 @@ { throw new NotSupportedException(); } + + public static string Qualify(string catalog, string schema, string table) + { + StringBuilder qualifiedName = new StringBuilder(100); + if (catalog != null) + { + qualifiedName.Append(catalog).Append('.'); + } + if (schema != null) + { + qualifiedName.Append(schema).Append('.'); + } + return qualifiedName.Append(table).ToString(); + } } } Modified: trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj 2008-08-15 21:41:48 UTC (rev 3706) @@ -631,6 +631,9 @@ <Compile Include="Engine\Query\Sql\NativeSQLQueryRootReturn.cs" /> <Compile Include="Engine\Query\Sql\NativeSQLQueryScalarReturn.cs" /> <Compile Include="Engine\StatefulPersistenceContext.cs" /> + <Compile Include="Engine\TransactionHelper.cs" /> + <Compile Include="Engine\Transaction\IIsolatedWork.cs" /> + <Compile Include="Engine\Transaction\Isolater.cs" /> <Compile Include="Engine\TwoPhaseLoad.cs" /> <Compile Include="Engine\ValueInclusion.cs" /> <Compile Include="Engine\VersionValue.cs" /> @@ -738,6 +741,13 @@ <Compile Include="Criterion\SqlFunctionProjection.cs" /> <Compile Include="FKUnmatchingColumnsException.cs" /> <Compile Include="Id\AbstractPostInsertGenerator.cs" /> + <Compile Include="Id\Enhanced\IAccessCallback.cs" /> + <Compile Include="Id\Enhanced\IDatabaseStructure.cs" /> + <Compile Include="Id\Enhanced\IOptimizer.cs" /> + <Compile Include="Id\Enhanced\OptimizerFactory.cs" /> + <Compile Include="Id\Enhanced\SequenceStructure.cs" /> + <Compile Include="Id\Enhanced\SequenceStyleGenerator.cs" /> + <Compile Include="Id\Enhanced\TableStructure.cs" /> <Compile Include="Id\Insert\AbstractReturningDelegate.cs"> <SubType>Code</SubType> </Compile> Added: trunk/nhibernate/src/NHibernate.Test/IdGen/Enhanced/SequenceStyleConfigUnitFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/IdGen/Enhanced/SequenceStyleConfigUnitFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/IdGen/Enhanced/SequenceStyleConfigUnitFixture.cs 2008-08-15 21:41:48 UTC (rev 3706) @@ -0,0 +1,172 @@ +using System.Collections.Generic; +using NHibernate.Id.Enhanced; +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; + +namespace NHibernate.Test.IdGen.Enhanced +{ + /// <summary> + /// Tests that SequenceStyleGenerator configures itself as expected in various scenarios + /// </summary> + [TestFixture] + public class SequenceStyleConfigUnitFixture + { + private class TableDialect : Dialect.Dialect + { + public override bool SupportsSequences + { + get { return false; } + } + } + + private class SequenceDialect : Dialect.Dialect + { + public override bool SupportsSequences + { + get { return true; } + } + + public override bool SupportsPooledSequences + { + get { return false; } + } + + public override string GetSequenceNextValString(string sequenceName) + { + return string.Empty; + } + } + + private class PooledSequenceDialect : SequenceDialect + { + public override bool SupportsPooledSequences + { + get { return true; } + } + } + + // Test explicitly specifying both optimizer and increment + [Test] + public void ExplicitOptimizerWithExplicitIncrementSize() + { + // with sequence ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Dialect.Dialect dialect = new SequenceDialect(); + + // optimizer=none w/ increment > 1 => should honor optimizer + IDictionary<string, string> props = new Dictionary<string, string>(); + props[SequenceStyleGenerator.OptimizerParam] = OptimizerFactory.None; + props[SequenceStyleGenerator.IncrementParam] = "20"; + SequenceStyleGenerator generator = new SequenceStyleGenerator(); + generator.Configure(NHibernateUtil.Int64, props, dialect); + Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (SequenceStructure))); + Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.NoopOptimizer))); + Assert.AreEqual(1, generator.Optimizer.IncrementSize); + Assert.AreEqual(1, generator.DatabaseStructure.IncrementSize); + + // optimizer=hilo w/ increment > 1 => hilo + props = new Dictionary<string, string>(); + props[SequenceStyleGenerator.OptimizerParam] = OptimizerFactory.HiLo; + props[SequenceStyleGenerator.IncrementParam] = "20"; + generator = new SequenceStyleGenerator(); + generator.Configure(NHibernateUtil.Int64, props, dialect); + Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (SequenceStructure))); + Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.HiLoOptimizer))); + Assert.AreEqual(20, generator.Optimizer.IncrementSize); + Assert.AreEqual(20, generator.DatabaseStructure.IncrementSize); + + // optimizer=pooled w/ increment > 1 => hilo + props = new Dictionary<string, string>(); + props[SequenceStyleGenerator.OptimizerParam] = OptimizerFactory.Pool; + props[SequenceStyleGenerator.IncrementParam] = "20"; + generator = new SequenceStyleGenerator(); + generator.Configure(NHibernateUtil.Int64, props, dialect); + Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (SequenceStructure))); + Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.HiLoOptimizer))); + Assert.AreEqual(20, generator.Optimizer.IncrementSize); + Assert.AreEqual(20, generator.DatabaseStructure.IncrementSize); + } + + // Test all params defaulted with a dialect supporting sequences + [Test] + public void DefaultedSequenceBackedConfiguration() + { + Dialect.Dialect dialect = new SequenceDialect(); + IDictionary<string, string> props = new Dictionary<string, string>(); + SequenceStyleGenerator generator = new SequenceStyleGenerator(); + generator.Configure(NHibernateUtil.Int64, props, dialect); + + Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (SequenceStructure))); + Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.NoopOptimizer))); + Assert.That(generator.DatabaseStructure.Name, Is.EqualTo(SequenceStyleGenerator.DefaultSequenceName)); + } + + // Test all params defaulted with a dialect which does not support sequences + [Test] + public void DefaultedTableBackedConfiguration() + { + Dialect.Dialect dialect = new TableDialect(); + IDictionary<string, string> props = new Dictionary<string, string>(); + SequenceStyleGenerator generator = new SequenceStyleGenerator(); + generator.Configure(NHibernateUtil.Int64, props, dialect); + + Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (TableStructure))); + Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.NoopOptimizer))); + Assert.That(generator.DatabaseStructure.Name, Is.EqualTo(SequenceStyleGenerator.DefaultSequenceName)); + } + + //Test default optimizer selection for sequence backed generators + //based on the configured increment size; both in the case of the + //dialect supporting pooled sequences (pooled) and not (hilo) + [Test] + public void DefaultOptimizerBasedOnIncrementBackedBySequence() + { + IDictionary<string, string> props = new Dictionary<string, string>(); + props[SequenceStyleGenerator.IncrementParam] = "10"; + + // for dialects which do not support pooled sequences, we default to hilo + Dialect.Dialect dialect = new SequenceDialect(); + SequenceStyleGenerator generator = new SequenceStyleGenerator(); + generator.Configure(NHibernateUtil.Int64, props, dialect); + Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (SequenceStructure))); + Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.HiLoOptimizer))); + Assert.That(generator.DatabaseStructure.Name, Is.EqualTo(SequenceStyleGenerator.DefaultSequenceName)); + + // for dialects which do support pooled sequences, we default to pooled + dialect = new PooledSequenceDialect(); + generator = new SequenceStyleGenerator(); + generator.Configure(NHibernateUtil.Int64, props, dialect); + Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (SequenceStructure))); + Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.PooledOptimizer))); + Assert.That(generator.DatabaseStructure.Name, Is.EqualTo(SequenceStyleGenerator.DefaultSequenceName)); + } + + // Test default optimizer selection for table backed generators + // based on the configured increment size. Here we always prefer pooled. + [Test] + public void DefaultOptimizerBasedOnIncrementBackedByTable() + { + IDictionary<string, string> props = new Dictionary<string, string>(); + props[SequenceStyleGenerator.IncrementParam] = "10"; + Dialect.Dialect dialect = new TableDialect(); + SequenceStyleGenerator generator = new SequenceStyleGenerator(); + generator.Configure(NHibernateUtil.Int64, props, dialect); + Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (TableStructure))); + Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.PooledOptimizer))); + Assert.That(generator.DatabaseStructure.Name, Is.EqualTo(SequenceStyleGenerator.DefaultSequenceName)); + } + + // Test forcing of table as backing strucuture with dialect supporting sequences + [Test] + public void ForceTableUse() + { + Dialect.Dialect dialect = new SequenceDialect(); + IDictionary<string, string> props = new Dictionary<string, string>(); + props[SequenceStyleGenerator.ForceTableParam] = "true"; + SequenceStyleGenerator generator = new SequenceStyleGenerator(); + generator.Configure(NHibernateUtil.Int64, props, dialect); + Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (TableStructure))); + Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.NoopOptimizer))); + Assert.That(generator.DatabaseStructure.Name, Is.EqualTo(SequenceStyleGenerator.DefaultSequenceName)); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-08-15 11:25:15 UTC (rev 3705) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-08-15 21:41:48 UTC (rev 3706) @@ -226,6 +226,7 @@ <Compile Include="HQLFunctionTest\SQLFunctionTemplateTest.cs" /> <Compile Include="BulkManipulation\NativeSQLBulkOperations.cs" /> <Compile Include="BulkManipulation\Vehicles.cs" /> + <Compile Include="IdGen\Enhanced\SequenceStyleConfigUnitFixture.cs" /> <Compile Include="IdTest\Car.cs" /> <Compile Include="IdTest\HiLoInt16Class.cs" /> <Compile Include="IdTest\HiLoInt32Class.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-08-16 04:11:10
|
Revision: 3707 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3707&view=rev Author: fabiomaulo Date: 2008-08-16 04:11:17 +0000 (Sat, 16 Aug 2008) Log Message: ----------- - Port of <natural-id> from H3.2.6 - Bug fix in statistics Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs trunk/nhibernate/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs trunk/nhibernate/src/NHibernate/Stat/StatisticsImpl.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/Naturalid/ trunk/nhibernate/src/NHibernate.Test/Naturalid/Immutable/ trunk/nhibernate/src/NHibernate.Test/Naturalid/Immutable/ImmutableNaturalIdFixture.cs trunk/nhibernate/src/NHibernate.Test/Naturalid/Immutable/User.cs trunk/nhibernate/src/NHibernate.Test/Naturalid/Immutable/User.hbm.xml trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/ trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/User.cs trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/User.hbm.xml Modified: trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs 2008-08-15 21:41:48 UTC (rev 3706) +++ trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs 2008-08-16 04:11:17 UTC (rev 3707) @@ -32,6 +32,13 @@ protected void PropertiesFromXML(XmlNode node, PersistentClass model) { + PropertiesFromXML(node, model, null, true, true, false); + } + + protected void PropertiesFromXML(XmlNode node, PersistentClass model, UniqueKey uniqueKey, bool mutable, bool nullable, bool naturalId) + { + string entityName = model.EntityName; + Table table = model.Table; foreach (XmlNode subnode in node.ChildNodes) @@ -47,8 +54,8 @@ CollectionBinder collectionBinder = new CollectionBinder(this); if (collectionBinder.CanCreate(name)) { - Mapping.Collection collection = collectionBinder.Create(name, subnode, model.EntityName, - propertyName, model, model.MappedClass); + Mapping.Collection collection = collectionBinder.Create(name, subnode, entityName, + propertyName, model, model.MappedClass); mappings.AddCollection(collection); value = collection; @@ -78,7 +85,7 @@ // NH: Modified from H2.1 to allow specifying the type explicitly using class attribute System.Type reflectedClass = GetPropertyType(subnode, model.MappedClass, propertyName); value = new Component(model); - BindComponent(subnode, (Component) value, reflectedClass, model.EntityName, propertyName, true); + BindComponent(subnode, (Component)value, reflectedClass, entityName, propertyName, true); } else if ("join".Equals(name)) { @@ -98,9 +105,34 @@ else if ("filter".Equals(name)) ParseFilter(subnode, model); + else if ("natural-id".Equals(name)) + { + UniqueKey uk = new UniqueKey(); + uk.Name = "_UniqueKey"; + uk.Table = table; + //by default, natural-ids are "immutable" (constant) + bool mutableId = false; + if (subnode.Attributes["mutable"] != null) + { + mutableId = "true".Equals(subnode.Attributes["mutable"]); + } + + PropertiesFromXML(subnode, model, uk, mutableId, false, true); + table.AddUniqueKey(uk); + } + if (value != null) - model.AddProperty(CreateProperty(value, propertyName, model.MappedClass, subnode)); + { + Property property = CreateProperty(value, propertyName, model.MappedClass, subnode); + if (!mutable) + property.IsUpdateable = false; + if (naturalId) + property.IsNaturalIdentifier = true; + model.AddProperty(property); + if (uniqueKey != null) + uniqueKey.AddColumns(new SafetyEnumerable<Column>(property.ColumnIterator)); + } } } Modified: trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs 2008-08-15 21:41:48 UTC (rev 3706) +++ trunk/nhibernate/src/NHibernate/Criterion/Restrictions.cs 2008-08-16 04:11:17 UTC (rev 3707) @@ -727,5 +727,9 @@ return conj; } + public static NaturalIdentifier NaturalId() + { + return new NaturalIdentifier(); + } } } Modified: trunk/nhibernate/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs 2008-08-15 21:41:48 UTC (rev 3706) +++ trunk/nhibernate/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs 2008-08-16 04:11:17 UTC (rev 3707) @@ -81,9 +81,9 @@ CheckId(entity, persister, entry.Id, entityMode); // grab its current state - values = persister.GetPropertyValues(entity, session.EntityMode); + values = persister.GetPropertyValues(entity, entityMode); - CheckNaturalId(persister, entry.Id, values, loadedState, session); + CheckNaturalId(persister, entry, values, loadedState, entityMode, session); } return values; } @@ -118,30 +118,29 @@ } } - private void CheckNaturalId(IEntityPersister persister, object identifier, object[] current, object[] loaded, ISessionImplementor session) + private void CheckNaturalId(IEntityPersister persister, EntityEntry entry, object[] current, object[] loaded, EntityMode entityMode, ISessionImplementor session) { - // TODO NH: Natural Identifier - //if (persister.HasNaturalIdentifier) - //{ - // if (loaded == null) - // { - // loaded = session.PersistenceContext.GetNaturalIdSnapshot(identifier, persister); - // } - // IType[] types = persister.PropertyTypes; - // int[] props = persister.NaturalIdentifierProperties; - // bool[] updateable = persister.PropertyUpdateability; - // for (int i = 0; i < props.Length; i++) - // { - // int prop = props[i]; - // if (!updateable[prop]) - // { - // if (!types[prop].Equals(current[prop], loaded[prop])) - // { - // throw new HibernateException("immutable natural identifier of an instance of " + persister.EntityName + " was altered"); - // } - // } - // } - //} + if (persister.HasNaturalIdentifier && entry.Status != Status.ReadOnly) + { + if (loaded == null) + { + loaded = session.PersistenceContext.GetNaturalIdSnapshot(entry.Id, persister); + } + IType[] types = persister.PropertyTypes; + int[] props = persister.NaturalIdentifierProperties; + bool[] updateable = persister.PropertyUpdateability; + for (int i = 0; i < props.Length; i++) + { + int prop = props[i]; + if (!updateable[prop]) + { + if (!types[prop].IsEqual(current[prop], loaded[prop], entityMode)) + { + throw new HibernateException("immutable natural identifier of an instance of " + persister.EntityName + " was altered"); + } + } + } + } } private bool WrapCollections(IEventSource session, IEntityPersister persister, IType[] types, object[] values) Modified: trunk/nhibernate/src/NHibernate/Stat/StatisticsImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Stat/StatisticsImpl.cs 2008-08-15 21:41:48 UTC (rev 3706) +++ trunk/nhibernate/src/NHibernate/Stat/StatisticsImpl.cs 2008-08-16 04:11:17 UTC (rev 3707) @@ -657,7 +657,10 @@ qs.cacheHitCount++; } SecondLevelCacheStatistics slcs = GetSecondLevelCacheStatistics(regionName); - slcs.hitCount++; + if (slcs != null) + { + slcs.hitCount++; + } } } @@ -673,7 +676,10 @@ qs.cacheMissCount++; } SecondLevelCacheStatistics slcs = GetSecondLevelCacheStatistics(regionName); - slcs.missCount++; + if (slcs != null) + { + slcs.missCount++; + } } } @@ -689,7 +695,10 @@ qs.cachePutCount++; } SecondLevelCacheStatistics slcs = GetSecondLevelCacheStatistics(regionName); - slcs.putCount++; + if (slcs != null) + { + slcs.putCount++; + } } } Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-08-15 21:41:48 UTC (rev 3706) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-08-16 04:11:17 UTC (rev 3707) @@ -300,6 +300,10 @@ <Compile Include="MultipleCollectionFetchTest\MultipleSetFetchFixture.cs" /> <Compile Include="MultipleCollectionFetchTest\Person.cs" /> <Compile Include="MultiThreadRunner.cs" /> + <Compile Include="Naturalid\Immutable\ImmutableNaturalIdFixture.cs" /> + <Compile Include="Naturalid\Immutable\User.cs" /> + <Compile Include="Naturalid\Mutable\MutableNaturalIdFixture.cs" /> + <Compile Include="Naturalid\Mutable\User.cs" /> <Compile Include="NHAssert.cs" /> <Compile Include="NHibernateUtilTest.cs" /> <Compile Include="NHSpecificTest\AliasFixture.cs" /> @@ -1406,6 +1410,8 @@ <EmbeddedResource Include="CompositeId\Order.hbm.xml" /> <EmbeddedResource Include="CompositeId\Product.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="Naturalid\Immutable\User.hbm.xml" /> + <EmbeddedResource Include="Naturalid\Mutable\User.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1419\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1413\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1304\Mappings.hbm.xml" /> Added: trunk/nhibernate/src/NHibernate.Test/Naturalid/Immutable/ImmutableNaturalIdFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Naturalid/Immutable/ImmutableNaturalIdFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Naturalid/Immutable/ImmutableNaturalIdFixture.cs 2008-08-16 04:11:17 UTC (rev 3707) @@ -0,0 +1,144 @@ +using System.Collections; +using NHibernate.Cfg; +using NHibernate.Criterion; +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; + +namespace NHibernate.Test.Naturalid.Immutable +{ + [TestFixture] + public class ImmutableNaturalIdFixture : TestCase + { + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + protected override IList Mappings + { + get { return new string[] {"Naturalid.Immutable.User.hbm.xml"}; } + } + + protected override void Configure(Configuration configuration) + { + cfg.SetProperty(Environment.UseSecondLevelCache, "true"); + cfg.SetProperty(Environment.UseQueryCache, "true"); + cfg.SetProperty(Environment.GenerateStatistics, "true"); + } + + [Test] + public void Update() + { + // prepare some test data... + User user; + using (ISession session = OpenSession()) + { + session.BeginTransaction(); + user = new User(); + user.UserName = "steve"; + user.Email = "st...@hi..."; + user.Password = "brewhaha"; + session.Save(user); + session.Transaction.Commit(); + } + // 'user' is now a detached entity, so lets change a property and reattch... + user.Password = "homebrew"; + using (ISession session = OpenSession()) + { + session.BeginTransaction(); + session.Update(user); + session.Transaction.Commit(); + } + + // clean up + using (ISession session = OpenSession()) + { + session.BeginTransaction(); + session.Delete(user); + session.Transaction.Commit(); + } + } + + [Test] + public void NaturalIdCheck() + { + ISession s = OpenSession(); + ITransaction t = s.BeginTransaction(); + + User u = new User("steve", "superSecret"); + s.Persist(u); + u.UserName = "Steve"; + try + { + s.Flush(); + Assert.Fail(); + } + catch (HibernateException he) {} + u.UserName = "steve"; + s.Delete(u); + t.Commit(); + s.Close(); + } + + [Test] + public void NaturalIdCache() + { + ISession s = OpenSession(); + s.BeginTransaction(); + User u = new User("steve", "superSecret"); + s.Persist(u); + s.Transaction.Commit(); + s.Close(); + + sessions.Statistics.Clear(); + + s = OpenSession(); + s.BeginTransaction(); + u = + (User) + s.CreateCriteria(typeof (User)).Add(Restrictions.NaturalId().Set("UserName", "steve")).SetCacheable(true). + UniqueResult(); + Assert.That(u, Is.Not.Null); + s.Transaction.Commit(); + s.Close(); + + Assert.AreEqual(1, sessions.Statistics.QueryExecutionCount); + Assert.AreEqual(0, sessions.Statistics.QueryCacheHitCount); + Assert.AreEqual(1, sessions.Statistics.QueryCachePutCount); + + s = OpenSession(); + s.BeginTransaction(); + User v = new User("gavin", "supsup"); + s.Persist(v); + s.Transaction.Commit(); + s.Close(); + + sessions.Statistics.Clear(); + + s = OpenSession(); + s.BeginTransaction(); + u = + (User) + s.CreateCriteria(typeof(User)).Add(Restrictions.NaturalId().Set("UserName", "steve")).SetCacheable(true). + UniqueResult(); + Assert.That(u, Is.Not.Null); + Assert.AreEqual(0, sessions.Statistics.QueryExecutionCount); + Assert.AreEqual(1, sessions.Statistics.QueryCacheHitCount); + u = + (User) + s.CreateCriteria(typeof(User)).Add(Restrictions.NaturalId().Set("UserName", "steve")).SetCacheable(true). + UniqueResult(); + Assert.That(u, Is.Not.Null); + Assert.AreEqual(0, sessions.Statistics.QueryExecutionCount); + Assert.AreEqual(2, sessions.Statistics.QueryCacheHitCount); + s.Transaction.Commit(); + s.Close(); + + s = OpenSession(); + s.BeginTransaction(); + s.Delete("from User"); + s.Transaction.Commit(); + s.Close(); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Naturalid/Immutable/User.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Naturalid/Immutable/User.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Naturalid/Immutable/User.cs 2008-08-16 04:11:17 UTC (rev 3707) @@ -0,0 +1,48 @@ +namespace NHibernate.Test.Naturalid.Immutable +{ + public class User + { + private int myUserId; + private int version; + private string userName; + private string password; + private string email; + public User() {} + + public User(string userName, string password) + { + this.userName = userName; + this.password = password; + } + + public virtual int MyUserId + { + get { return myUserId; } + set { myUserId = value; } + } + + public virtual int Version + { + get { return version; } + set { version = value; } + } + + public virtual string UserName + { + get { return userName; } + set { userName = value; } + } + + public virtual string Password + { + get { return password; } + set { password = value; } + } + + public virtual string Email + { + get { return email; } + set { email = value; } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Naturalid/Immutable/User.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Naturalid/Immutable/User.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Naturalid/Immutable/User.hbm.xml 2008-08-16 04:11:17 UTC (rev 3707) @@ -0,0 +1,24 @@ +<?xml version="1.0"?> +<!-- + + This mapping illustrates use of <natural-id mutable="false"/> + +--> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + namespace="NHibernate.Test.Naturalid.Immutable" + assembly="NHibernate.Test"> + + <class name="User" table="IMM_NAT_ID_USER" lazy="true"> + <comment>Users may bid for or sell auction items.</comment> + <id name="MyUserId" type="int"> + <generator class="increment"/> + </id> + <natural-id mutable="false"> + <property name="UserName" length="10"/> + </natural-id> + <version name="Version"/> + <property name="Password" not-null="true" length="15" column="`password`"/> + <property name="Email"/> + </class> + +</hibernate-mapping> \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs 2008-08-16 04:11:17 UTC (rev 3707) @@ -0,0 +1,250 @@ +using System; +using System.Collections; +using System.Reflection; +using NHibernate.Cfg; +using NHibernate.Criterion; +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; +using Environment=NHibernate.Cfg.Environment; + +namespace NHibernate.Test.Naturalid.Mutable +{ + [TestFixture] + public class MutableNaturalIdFixture : TestCase + { + // TODO : Complete the test as H3.2.6 + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + protected override IList Mappings + { + get { return new string[] {"Naturalid.Mutable.User.hbm.xml"}; } + } + + protected override void Configure(Configuration configuration) + { + cfg.SetProperty(Environment.UseSecondLevelCache, "true"); + cfg.SetProperty(Environment.UseQueryCache, "true"); + cfg.SetProperty(Environment.GenerateStatistics, "true"); + } + + [Test] + public void ReattachmentNaturalIdCheck() + { + ISession s = OpenSession(); + s.BeginTransaction(); + User u = new User("gavin", "hb", "secret"); + s.Persist(u); + s.Transaction.Commit(); + s.Close(); + + FieldInfo name = u.GetType().GetField("name", + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); + name.SetValue(u, "Gavin"); + s = OpenSession(); + s.BeginTransaction(); + try + { + s.Update(u); + s.Transaction.Commit(); + } + catch (HibernateException) + { + s.Transaction.Rollback(); + } + catch (Exception) + { + try + { + s.Transaction.Rollback(); + } + catch (Exception) {} + throw; + } + finally + { + s.Close(); + } + + s = OpenSession(); + s.BeginTransaction(); + s.Delete(u); + s.Transaction.Commit(); + s.Close(); + } + + [Test] + public void NonexistentNaturalIdCache() + { + sessions.Statistics.Clear(); + + ISession s = OpenSession(); + ITransaction t = s.BeginTransaction(); + + object nullUser = + s.CreateCriteria(typeof (User)) + .Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")) + .SetCacheable(true) + .UniqueResult(); + + Assert.That(nullUser, Is.Null); + + t.Commit(); + s.Close(); + + Assert.AreEqual(1, sessions.Statistics.QueryExecutionCount); + Assert.AreEqual(0, sessions.Statistics.QueryCacheHitCount); + Assert.AreEqual(0, sessions.Statistics.QueryCachePutCount); + + s = OpenSession(); + t = s.BeginTransaction(); + + User u = new User("gavin", "hb", "secret"); + s.Persist(u); + + t.Commit(); + s.Close(); + + sessions.Statistics.Clear(); + + s = OpenSession(); + t = s.BeginTransaction(); + + u =(User) s.CreateCriteria(typeof (User)) + .Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")) + .SetCacheable(true).UniqueResult(); + + Assert.That(u, Is.Not.Null); + + t.Commit(); + s.Close(); + + Assert.AreEqual(1, sessions.Statistics.QueryExecutionCount); + Assert.AreEqual(0, sessions.Statistics.QueryCacheHitCount); + Assert.AreEqual(1, sessions.Statistics.QueryCachePutCount); + + sessions.Statistics.Clear(); + + s = OpenSession(); + t = s.BeginTransaction(); + + u =(User) s.CreateCriteria(typeof (User)) + .Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")) + .SetCacheable(true).UniqueResult(); + + s.Delete(u); + + t.Commit(); + s.Close(); + + Assert.AreEqual(0, sessions.Statistics.QueryExecutionCount); + Assert.AreEqual(1, sessions.Statistics.QueryCacheHitCount); + + sessions.Statistics.Clear(); + + s = OpenSession(); + t = s.BeginTransaction(); + + nullUser = s.CreateCriteria(typeof (User)) + .Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")) + .SetCacheable(true).UniqueResult(); + + Assert.That(nullUser, Is.Null); + + t.Commit(); + s.Close(); + + Assert.AreEqual(1, sessions.Statistics.QueryExecutionCount); + Assert.AreEqual(0, sessions.Statistics.QueryCacheHitCount); + Assert.AreEqual(0, sessions.Statistics.QueryCachePutCount); + } + + [Test] + public void NaturalIdCache() + { + ISession s = OpenSession(); + ITransaction t = s.BeginTransaction(); + + User u = new User("gavin", "hb", "secret"); + s.Persist(u); + + t.Commit(); + s.Close(); + + sessions.Statistics.Clear(); + + s = OpenSession(); + t = s.BeginTransaction(); + + u = (User) s.CreateCriteria(typeof (User)) + .Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")) + .SetCacheable(true).UniqueResult(); + + Assert.That(u, Is.Not.Null); + + t.Commit(); + s.Close(); + + Assert.AreEqual(1, sessions.Statistics.QueryExecutionCount); + Assert.AreEqual(0, sessions.Statistics.QueryCacheHitCount); + Assert.AreEqual(1, sessions.Statistics.QueryCachePutCount); + + s = OpenSession(); + t = s.BeginTransaction(); + + User v = new User("xam", "hb", "foobar"); + s.Persist(v); + + t.Commit(); + s.Close(); + + sessions.Statistics.Clear(); + + s = OpenSession(); + t = s.BeginTransaction(); + + u = (User) s.CreateCriteria(typeof (User)) + .Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")) + .SetCacheable(true).UniqueResult(); + + Assert.That(u, Is.Not.Null); + + t.Commit(); + s.Close(); + + Assert.AreEqual(0, sessions.Statistics.QueryExecutionCount); + Assert.AreEqual(1, sessions.Statistics.QueryCacheHitCount); + + s = OpenSession(); + t = s.BeginTransaction(); + s.Delete("from User"); + t.Commit(); + s.Close(); + } + + [Test] + public void Querying() + { + ISession s = OpenSession(); + ITransaction t = s.BeginTransaction(); + + User u = new User("emmanuel", "hb", "bh"); + s.Persist(u); + + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + + u = (User) s.CreateQuery("from User u where u.name = :name").SetParameter("name", "emmanuel").UniqueResult(); + Assert.AreEqual("emmanuel", u.Name); + s.Delete(u); + + t.Commit(); + s.Close(); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/User.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/User.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/User.cs 2008-08-16 04:11:17 UTC (rev 3707) @@ -0,0 +1,34 @@ +namespace NHibernate.Test.Naturalid.Mutable +{ + public class User + { + private long id; + private readonly string name; + private readonly string org; + private string password; + + public User() {} + public User(string name, string org, string password) + { + this.name = name; + this.org = org; + this.password = password; + } + + public virtual string Name + { + get { return name; } + } + + public virtual string Org + { + get { return org; } + } + + public virtual string Password + { + get { return password; } + set { password = value; } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/User.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/User.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/User.hbm.xml 2008-08-16 04:11:17 UTC (rev 3707) @@ -0,0 +1,24 @@ +<?xml version="1.0"?> +<!-- + + This mapping illustrates use of <natural-id mutable="true"/> + +--> + +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + namespace="NHibernate.Test.Naturalid.Mutable" + assembly="NHibernate.Test" + default-access="field"> + + <class name="User" table="SystemUserInfo"> + <id name="id"> + <generator class="increment"/> + </id> + <natural-id mutable="true"> + <property name="name"/> + <property name="org"/> + </natural-id> + <property name="password"/> + </class> + +</hibernate-mapping> \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-08-16 05:03:48
|
Revision: 3708 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3708&view=rev Author: fabiomaulo Date: 2008-08-16 05:03:56 +0000 (Sat, 16 Aug 2008) Log Message: ----------- Complete the port of tests for <natural-id> with bug fix and "todo" done. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs trunk/nhibernate/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs Modified: trunk/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs 2008-08-16 04:11:17 UTC (rev 3707) +++ trunk/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs 2008-08-16 05:03:56 UTC (rev 3708) @@ -356,48 +356,46 @@ /// </summary> public object[] GetNaturalIdSnapshot(object id, IEntityPersister persister) { - // todo Natural Identifier - //if (!persister.HasNaturalIdentifier) - //{ - // return null; - //} + if (!persister.HasNaturalIdentifier) + { + return null; + } - //// if the natural-id is marked as non-mutable, it is not retrieved during a - //// normal database-snapshot operation... - //int[] props = persister.NaturalIdentifierProperties; - //bool[] updateable = persister.PropertyUpdateability; - //bool allNatualIdPropsAreUpdateable = true; - //for (int i = 0; i < props.Length; i++) - //{ - // if (!updateable[props[i]]) - // { - // allNatualIdPropsAreUpdateable = false; - // break; - // } - //} + // if the natural-id is marked as non-mutable, it is not retrieved during a + // normal database-snapshot operation... + int[] props = persister.NaturalIdentifierProperties; + bool[] updateable = persister.PropertyUpdateability; + bool allNatualIdPropsAreUpdateable = true; + for (int i = 0; i < props.Length; i++) + { + if (!updateable[props[i]]) + { + allNatualIdPropsAreUpdateable = false; + break; + } + } - //if (allNatualIdPropsAreUpdateable) - //{ - // // do this when all the properties are updateable since there is - // // a certain likelihood that the information will already be - // // snapshot-cached. - // object[] entitySnapshot = GetDatabaseSnapshot(id, persister); - // if (entitySnapshot == NoRow) - // { - // return null; - // } - // object[] naturalIdSnapshot = new object[props.Length]; - // for (int i = 0; i < props.Length; i++) - // { - // naturalIdSnapshot[i] = entitySnapshot[props[i]]; - // } - // return naturalIdSnapshot; - //} - //else - //{ - // return persister.GetNaturalIdentifierSnapshot(id, session); - //} - return null; + if (allNatualIdPropsAreUpdateable) + { + // do this when all the properties are updateable since there is + // a certain likelihood that the information will already be + // snapshot-cached. + object[] entitySnapshot = GetDatabaseSnapshot(id, persister); + if (entitySnapshot == NoRow) + { + return null; + } + object[] naturalIdSnapshot = new object[props.Length]; + for (int i = 0; i < props.Length; i++) + { + naturalIdSnapshot[i] = entitySnapshot[props[i]]; + } + return naturalIdSnapshot; + } + else + { + return persister.GetNaturalIdentifierSnapshot(id, session); + } } /// <summary> Add a canonical mapping from entity key to entity instance</summary> Modified: trunk/nhibernate/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs 2008-08-16 04:11:17 UTC (rev 3707) +++ trunk/nhibernate/src/NHibernate/Event/Default/DefaultFlushEntityEventListener.cs 2008-08-16 05:03:56 UTC (rev 3708) @@ -122,10 +122,7 @@ { if (persister.HasNaturalIdentifier && entry.Status != Status.ReadOnly) { - if (loaded == null) - { - loaded = session.PersistenceContext.GetNaturalIdSnapshot(entry.Id, persister); - } + object[] snapshot = null; IType[] types = persister.PropertyTypes; int[] props = persister.NaturalIdentifierProperties; bool[] updateable = persister.PropertyUpdateability; @@ -134,10 +131,24 @@ int prop = props[i]; if (!updateable[prop]) { - if (!types[prop].IsEqual(current[prop], loaded[prop], entityMode)) + object loadedVal; + if (loaded == null) { - throw new HibernateException("immutable natural identifier of an instance of " + persister.EntityName + " was altered"); + if (snapshot == null) + { + snapshot = session.PersistenceContext.GetNaturalIdSnapshot(entry.Id, persister); + } + loadedVal = snapshot[i]; } + else + { + loadedVal = loaded[prop]; + } + if (!types[prop].IsEqual(current[prop], loadedVal, entityMode)) + { + throw new HibernateException("immutable natural identifier of an instance of " + persister.EntityName + + " was altered"); + } } } } Modified: trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs 2008-08-16 04:11:17 UTC (rev 3707) +++ trunk/nhibernate/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs 2008-08-16 05:03:56 UTC (rev 3708) @@ -12,7 +12,6 @@ [TestFixture] public class MutableNaturalIdFixture : TestCase { - // TODO : Complete the test as H3.2.6 protected override string MappingsAssembly { get { return "NHibernate.Test"; } @@ -56,12 +55,7 @@ } catch (Exception) { - try - { s.Transaction.Rollback(); - } - catch (Exception) {} - throw; } finally { @@ -84,10 +78,8 @@ ITransaction t = s.BeginTransaction(); object nullUser = - s.CreateCriteria(typeof (User)) - .Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")) - .SetCacheable(true) - .UniqueResult(); + s.CreateCriteria(typeof (User)).Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")).SetCacheable( + true).UniqueResult(); Assert.That(nullUser, Is.Null); @@ -112,9 +104,10 @@ s = OpenSession(); t = s.BeginTransaction(); - u =(User) s.CreateCriteria(typeof (User)) - .Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")) - .SetCacheable(true).UniqueResult(); + u = + (User) + s.CreateCriteria(typeof (User)).Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")).SetCacheable( + true).UniqueResult(); Assert.That(u, Is.Not.Null); @@ -130,9 +123,10 @@ s = OpenSession(); t = s.BeginTransaction(); - u =(User) s.CreateCriteria(typeof (User)) - .Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")) - .SetCacheable(true).UniqueResult(); + u = + (User) + s.CreateCriteria(typeof (User)).Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")).SetCacheable( + true).UniqueResult(); s.Delete(u); @@ -147,9 +141,9 @@ s = OpenSession(); t = s.BeginTransaction(); - nullUser = s.CreateCriteria(typeof (User)) - .Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")) - .SetCacheable(true).UniqueResult(); + nullUser = + s.CreateCriteria(typeof (User)).Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")).SetCacheable( + true).UniqueResult(); Assert.That(nullUser, Is.Null); @@ -206,16 +200,23 @@ t = s.BeginTransaction(); u = (User) s.CreateCriteria(typeof (User)) - .Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")) + .Add(Restrictions.NaturalId().Set("name", "xam").Set("org", "hb")) .SetCacheable(true).UniqueResult(); Assert.That(u, Is.Not.Null); + Assert.AreEqual(1, sessions.Statistics.QueryExecutionCount); + Assert.AreEqual(0, sessions.Statistics.QueryCacheHitCount); + u = (User)s.CreateCriteria(typeof(User)) + .Add(Restrictions.NaturalId().Set("name", "gavin").Set("org", "hb")) + .SetCacheable(true).UniqueResult(); + Assert.That(u, Is.Not.Null); + Assert.AreEqual(1, sessions.Statistics.QueryExecutionCount); + Assert.AreEqual(1, sessions.Statistics.QueryCacheHitCount); + t.Commit(); s.Close(); - Assert.AreEqual(0, sessions.Statistics.QueryExecutionCount); - Assert.AreEqual(1, sessions.Statistics.QueryCacheHitCount); s = OpenSession(); t = s.BeginTransaction(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-08-16 07:02:38
|
Revision: 3710 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3710&view=rev Author: fabiomaulo Date: 2008-08-16 07:02:48 +0000 (Sat, 16 Aug 2008) Log Message: ----------- - Fix NH-1251 - TypeFactory thread safe + refactoring NET2.0 Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs trunk/nhibernate/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs Modified: trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs 2008-08-16 06:10:38 UTC (rev 3709) +++ trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs 2008-08-16 07:02:48 UTC (rev 3710) @@ -10,6 +10,7 @@ using NHibernate.Tuple; using NHibernate.UserTypes; using NHibernate.Util; +using System.Runtime.CompilerServices; namespace NHibernate.Type { @@ -32,8 +33,8 @@ PrecisionScale } - private static char[] precisionScaleSplit = new char[] {'(', ')', ','}; - private static char[] lengthSplit = new char[] {'(', ')'}; + private static readonly char[] precisionScaleSplit = new char[] {'(', ')', ','}; + private static readonly char[] lengthSplit = new char[] {'(', ')'}; /* * Maps the string representation of the type to the IType. The string @@ -54,11 +55,16 @@ * "String(l)" -> instance of StringType with specified l * "System.String(l)" -> instance of StringType with specified l */ - private static Hashtable typeByTypeOfName = Hashtable.Synchronized(new Hashtable(79)); - private static Hashtable getTypeDelegatesWithLength = Hashtable.Synchronized(new Hashtable(7)); - private static Hashtable getTypeDelegatesWithPrecision = Hashtable.Synchronized(new Hashtable(3)); + private static readonly IDictionary<string, IType> typeByTypeOfName = + new ThreadSafeDictionary<string, IType>(new Dictionary<string, IType>()); + private static readonly IDictionary<string, GetNullableTypeWithLength> getTypeDelegatesWithLength = + new ThreadSafeDictionary<string, GetNullableTypeWithLength>(new Dictionary<string, GetNullableTypeWithLength>()); + + private static readonly IDictionary<string, GetNullableTypeWithPrecision> getTypeDelegatesWithPrecision = + new ThreadSafeDictionary<string, GetNullableTypeWithPrecision>(new Dictionary<string, GetNullableTypeWithPrecision>()); + private delegate NullableType GetNullableTypeWithLength(int length); private delegate NullableType GetNullableTypeWithPrecision(byte precision, byte scale); @@ -121,7 +127,7 @@ // add the mappings of the NHibernate specific names that are used in type="" typeByTypeOfName[NHibernateUtil.AnsiString.Name] = NHibernateUtil.AnsiString; - getTypeDelegatesWithLength.Add(NHibernateUtil.AnsiString.Name, new GetNullableTypeWithLength(GetAnsiStringType)); + getTypeDelegatesWithLength.Add(NHibernateUtil.AnsiString.Name, GetAnsiStringType); typeByTypeOfName[NHibernateUtil.AnsiChar.Name] = NHibernateUtil.AnsiChar; typeByTypeOfName[NHibernateUtil.BinaryBlob.Name] = NHibernateUtil.BinaryBlob; @@ -155,12 +161,12 @@ typeByTypeOfName["yes_no"] = NHibernateUtil.YesNo; - getTypeDelegatesWithLength.Add(NHibernateUtil.Binary.Name, new GetNullableTypeWithLength(GetBinaryType)); - getTypeDelegatesWithLength.Add(NHibernateUtil.Serializable.Name, new GetNullableTypeWithLength(GetSerializableType)); - getTypeDelegatesWithLength.Add(NHibernateUtil.String.Name, new GetNullableTypeWithLength(GetStringType)); - getTypeDelegatesWithLength.Add(NHibernateUtil.Class.Name, new GetNullableTypeWithLength(GetTypeType)); + getTypeDelegatesWithLength.Add(NHibernateUtil.Binary.Name, GetBinaryType); + getTypeDelegatesWithLength.Add(NHibernateUtil.Serializable.Name, GetSerializableType); + getTypeDelegatesWithLength.Add(NHibernateUtil.String.Name, GetStringType); + getTypeDelegatesWithLength.Add(NHibernateUtil.Class.Name, GetTypeType); - getTypeDelegatesWithPrecision.Add(NHibernateUtil.Decimal.Name, new GetNullableTypeWithPrecision(GetDecimalType)); + getTypeDelegatesWithPrecision.Add(NHibernateUtil.Decimal.Name, GetDecimalType); } @@ -230,13 +236,12 @@ /// </remarks> public static IType Basic(string name) { - string typeName = String.Empty; + string typeName; // Use the basic name (such as String or String(255)) to get the // instance of the IType object. IType returnType; - returnType = (IType) typeByTypeOfName[name]; - if (returnType != null) + if (typeByTypeOfName.TryGetValue(name,out returnType)) { return returnType; } @@ -249,9 +254,6 @@ if (typeClassification == TypeClassification.PrecisionScale) { //precision/scale based - GetNullableTypeWithPrecision precisionDelegate; - byte precision; - byte scale; string[] parsedName = name.Split(precisionScaleSplit); if (parsedName.Length < 4) @@ -261,22 +263,20 @@ } typeName = parsedName[0].Trim(); - precision = Byte.Parse(parsedName[1].Trim()); - scale = Byte.Parse(parsedName[2].Trim()); + byte precision = Byte.Parse(parsedName[1].Trim()); + byte scale = Byte.Parse(parsedName[2].Trim()); - if (getTypeDelegatesWithPrecision.ContainsKey(typeName) == false) + GetNullableTypeWithPrecision precisionDelegate; + if (!getTypeDelegatesWithPrecision.TryGetValue(typeName, out precisionDelegate)) { return null; } - precisionDelegate = (GetNullableTypeWithPrecision) getTypeDelegatesWithPrecision[typeName]; return precisionDelegate(precision, scale); } else if (typeClassification == TypeClassification.Length) { //length based - GetNullableTypeWithLength lengthDelegate; - int length; string[] parsedName = name.Split(lengthSplit); if (parsedName.Length < 3) @@ -285,15 +285,15 @@ } typeName = parsedName[0].Trim(); - length = Int32.Parse(parsedName[1].Trim()); + int length = Int32.Parse(parsedName[1].Trim()); - if (getTypeDelegatesWithLength.ContainsKey(typeName) == false) - // we were not able to find a delegate to get the Type + GetNullableTypeWithLength lengthDelegate; + + if (!getTypeDelegatesWithLength.TryGetValue(typeName, out lengthDelegate)) { + // we were not able to find a delegate to get the Type return null; } - - lengthDelegate = (GetNullableTypeWithLength) getTypeDelegatesWithLength[typeName]; return lengthDelegate(length); } @@ -307,23 +307,20 @@ } } - private static IType AddToTypeOfName(string key, IType type) + private static void AddToTypeOfName(string key, IType type) { typeByTypeOfName.Add(key, type); typeByTypeOfName.Add(type.Name, type); - return type; } - private static IType AddToTypeOfNameWithLength(string key, IType type) + private static void AddToTypeOfNameWithLength(string key, IType type) { typeByTypeOfName.Add(key, type); - return type; } - private static IType AddToTypeOfNameWithPrecision(string key, IType type) + private static void AddToTypeOfNameWithPrecision(string key, IType type) { typeByTypeOfName.Add(key, type); - return type; } private static string GetKeyForLengthBased(string name, int length) @@ -375,14 +372,8 @@ { parsedTypeName = typeName.Split(lengthSplit); } - else if (typeClassification == TypeClassification.PrecisionScale) - { - parsedTypeName = typeName.Split(precisionScaleSplit); - } - else - { - parsedTypeName = new string[] {typeName}; - } + else + parsedTypeName = typeClassification == TypeClassification.PrecisionScale ? typeName.Split(precisionScaleSplit) : new string[] {typeName}; System.Type typeClass; @@ -455,22 +446,19 @@ return genericClass.IsSubclassOf(typeof (Enum)); } - /// <summary> - /// - /// </summary> - /// <param name="length"></param> - /// <returns></returns> + + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetAnsiStringType(int length) { string key = GetKeyForLengthBased(NHibernateUtil.AnsiString.Name, length); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new AnsiStringType(SqlTypeFactory.GetAnsiString(length)); AddToTypeOfNameWithLength(key, returnType); } - return returnType; + return (NullableType)returnType; } /// <summary> @@ -483,6 +471,7 @@ /// been added to the basicNameMap with the keys <c>Byte[](length)</c> and /// <c>NHibernate.Type.BinaryType(length)</c>. /// </remarks> + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetBinaryType(int length) { //HACK: don't understand why SerializableType calls this with length=0 @@ -492,27 +481,28 @@ } string key = GetKeyForLengthBased(NHibernateUtil.Binary.Name, length); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new BinaryType(SqlTypeFactory.GetBinary(length)); AddToTypeOfNameWithLength(key, returnType); } - return returnType; + return (NullableType)returnType; } + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetDecimalType(byte precision, byte scale) { string key = GetKeyForPrecisionScaleBased(NHibernateUtil.Decimal.Name, precision, scale); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new DecimalType(SqlTypeFactory.GetDecimal(precision, scale)); AddToTypeOfNameWithPrecision(key, returnType); } - return returnType; + return (NullableType)returnType; } /// <summary> @@ -534,95 +524,79 @@ /// with the default length, those keys will also be added. /// </para> /// </remarks> + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetSerializableType(System.Type serializableType) { string key = serializableType.AssemblyQualifiedName; - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new SerializableType(serializableType); AddToTypeOfName(key, returnType); } - return returnType; + return (NullableType)returnType; } - /// <summary> - /// - /// </summary> - /// <param name="serializableType"></param> - /// <param name="length"></param> - /// <returns></returns> + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetSerializableType(System.Type serializableType, int length) { string key = GetKeyForLengthBased(serializableType.AssemblyQualifiedName, length); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new SerializableType(serializableType, SqlTypeFactory.GetBinary(length)); AddToTypeOfNameWithLength(key, returnType); } - return returnType; + return (NullableType)returnType; } - /// <summary> - /// - /// </summary> - /// <param name="length"></param> - /// <returns></returns> + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetSerializableType(int length) { string key = GetKeyForLengthBased(NHibernateUtil.Serializable.Name, length); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new SerializableType(typeof(object), SqlTypeFactory.GetBinary(length)); AddToTypeOfNameWithLength(key, returnType); } - return returnType; + return (NullableType)returnType; } - /// <summary> - /// - /// </summary> - /// <param name="length"></param> - /// <returns></returns> + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetStringType(int length) { string key = GetKeyForLengthBased(NHibernateUtil.String.Name, length); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new StringType(SqlTypeFactory.GetString(length)); AddToTypeOfNameWithLength(key, returnType); } - return returnType; + return (NullableType)returnType; } - /// <summary> - /// - /// </summary> - /// <param name="length"></param> - /// <returns></returns> + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetTypeType(int length) { string key = GetKeyForLengthBased(typeof(TypeType).FullName, length); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new TypeType(SqlTypeFactory.GetString(length)); AddToTypeOfNameWithLength(key, returnType); } - return returnType; + return (NullableType)returnType; } // Association Types Modified: trunk/nhibernate/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs 2008-08-16 06:10:38 UTC (rev 3709) +++ trunk/nhibernate/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs 2008-08-16 07:02:48 UTC (rev 3710) @@ -1,5 +1,4 @@ using System; -using System.Threading; using log4net; using log4net.Repository.Hierarchy; using NHibernate.Type; @@ -79,6 +78,8 @@ [Test, Explicit] public void MultiThreadAccess() { + // Test added for NH-1251 + // If one thread break the test you can see the result in the console. ((Logger) log.Logger).Level = log4net.Core.Level.Debug; MultiThreadRunner<object>.ExecuteAction[] actions = new MultiThreadRunner<object>.ExecuteAction[] { @@ -108,7 +109,6 @@ mtr.TimeoutBetweenThreadStart = 2; mtr.Run(null); log.DebugFormat("{0} calls", totalCall); - TypeFactory.GetTypeType(rnd.Next()); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-08-18 14:20:58
|
Revision: 3715 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3715&view=rev Author: fabiomaulo Date: 2008-08-18 14:21:05 +0000 (Mon, 18 Aug 2008) Log Message: ----------- Partial support of lazy="extra" (collections) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs trunk/nhibernate/src/NHibernate/Collection/PersistentSet.cs trunk/nhibernate/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs trunk/nhibernate/src/NHibernate/Persister/Collection/BasicCollectionPersister.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/Extralazy/ trunk/nhibernate/src/NHibernate.Test/Extralazy/Document.cs trunk/nhibernate/src/NHibernate.Test/Extralazy/ExtraLazyFixture.cs trunk/nhibernate/src/NHibernate.Test/Extralazy/Group.cs trunk/nhibernate/src/NHibernate.Test/Extralazy/SessionAttribute.cs trunk/nhibernate/src/NHibernate.Test/Extralazy/User.cs trunk/nhibernate/src/NHibernate.Test/Extralazy/UserGroup.hbm.xml Modified: trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs 2008-08-18 13:38:05 UTC (rev 3714) +++ trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs 2008-08-18 14:21:05 UTC (rev 3715) @@ -167,7 +167,12 @@ // LAZINESS InitLaziness(node, model, "true", mappings.DefaultLazy); - // TODO: H3.1 - lazy="extra" + XmlAttribute lazyNode = node.Attributes["lazy"]; + if (lazyNode != null && "extra".Equals(lazyNode.Value)) + { + model.IsLazy = true; + model.ExtraLazy = true; + } XmlNode oneToManyNode = node.SelectSingleNode(HbmConstants.nsOneToMany, namespaceManager); if (oneToManyNode != null) @@ -507,7 +512,7 @@ string name = subnode.LocalName; //.Name; - if ("index".Equals(name)) + if ("index".Equals(name) || "map-key".Equals(name)) { SimpleValue value = new SimpleValue(model.CollectionTable); BindSimpleValue(subnode, value, model.IsOneToMany, IndexedCollection.DefaultIndexColumnName); @@ -515,13 +520,13 @@ if (model.Index.Type == null) throw new MappingException("map index element must specify a type: " + model.Role); } - else if ("index-many-to-many".Equals(name)) + else if ("index-many-to-many".Equals(name) || "map-key-many-to-many".Equals(name)) { ManyToOne mto = new ManyToOne(model.CollectionTable); BindManyToOne(subnode, mto, IndexedCollection.DefaultIndexColumnName, model.IsOneToMany); model.Index = mto; } - else if ("composite-index".Equals(name)) + else if ("composite-index".Equals(name) || "composite-map-key".Equals(name)) { Component component = new Component(model); BindComponent(subnode, component, null, model.Role, "index", model.IsOneToMany); Modified: trunk/nhibernate/src/NHibernate/Collection/PersistentSet.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Collection/PersistentSet.cs 2008-08-18 13:38:05 UTC (rev 3714) +++ trunk/nhibernate/src/NHibernate/Collection/PersistentSet.cs 2008-08-18 14:21:05 UTC (rev 3715) @@ -385,8 +385,7 @@ if (!exists.HasValue) { Initialize(true); - bool contained = set.Remove(o); - if (contained) + if (set.Remove(o)) { Dirty(); return true; Modified: trunk/nhibernate/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs 2008-08-18 13:38:05 UTC (rev 3714) +++ trunk/nhibernate/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs 2008-08-18 14:21:05 UTC (rev 3715) @@ -1443,7 +1443,7 @@ IDataReader rs = null; try { - KeyType.NullSafeSet(st, key, 1, session); + KeyType.NullSafeSet(st, key, 0, session); rs = session.Batcher.ExecuteReader(st); return rs.Read() ? rs.GetInt32(0) - baseIndex : 0; } @@ -1481,8 +1481,8 @@ IDataReader rs = null; try { - KeyType.NullSafeSet(st, key, 1, session); - indexOrElementType.NullSafeSet(st, indexOrElement, keyColumnNames.Length + 1, session); + KeyType.NullSafeSet(st, key, 0, session); + indexOrElementType.NullSafeSet(st, indexOrElement, keyColumnNames.Length, session); rs = session.Batcher.ExecuteReader(st); try { @@ -1520,8 +1520,8 @@ IDataReader rs = null; try { - KeyType.NullSafeSet(st, key, 1, session); - IndexType.NullSafeSet(st, IncrementIndexByBase(index), keyColumnNames.Length + 1, session); + KeyType.NullSafeSet(st, key, 0, session); + IndexType.NullSafeSet(st, IncrementIndexByBase(index), keyColumnNames.Length, session); rs = session.Batcher.ExecuteReader(st); try { Modified: trunk/nhibernate/src/NHibernate/Persister/Collection/BasicCollectionPersister.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Persister/Collection/BasicCollectionPersister.cs 2008-08-18 13:38:05 UTC (rev 3714) +++ trunk/nhibernate/src/NHibernate/Persister/Collection/BasicCollectionPersister.cs 2008-08-18 14:21:05 UTC (rev 3715) @@ -74,13 +74,13 @@ insert.AddColumns(new string[] {IdentifierColumnName}, null, IdentifierType); if (HasIndex) - insert.AddColumns(IndexColumnNames, null, IndexType); + insert.AddColumns(IndexColumnNames, indexColumnIsSettable, IndexType); - insert.AddColumns(ElementColumnNames, elementColumnIsSettable, ElementType); - if (Factory.Settings.IsCommentsEnabled) insert.SetComment("insert collection row " + Role); + insert.AddColumns(ElementColumnNames, elementColumnIsSettable, ElementType); + return insert.ToSqlCommandInfo(); } Added: trunk/nhibernate/src/NHibernate.Test/Extralazy/Document.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Extralazy/Document.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Extralazy/Document.cs 2008-08-18 14:21:05 UTC (rev 3715) @@ -0,0 +1,34 @@ +namespace NHibernate.Test.Extralazy +{ + public class Document + { + private string title; + private string content; + private User owner; + protected Document() {} + public Document(string title, string content, User owner) + { + this.title = title; + this.content = content; + this.owner = owner; + } + + public virtual string Title + { + get { return title; } + set { title = value; } + } + + public virtual string Content + { + get { return content; } + set { content = value; } + } + + public virtual User Owner + { + get { return owner; } + set { owner = value; } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Extralazy/ExtraLazyFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Extralazy/ExtraLazyFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Extralazy/ExtraLazyFixture.cs 2008-08-18 14:21:05 UTC (rev 3715) @@ -0,0 +1,232 @@ +using System.Collections; +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; + +namespace NHibernate.Test.Extralazy +{ + [TestFixture] + public class ExtraLazyFixture : TestCase + { + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + protected override IList Mappings + { + get { return new string[] {"Extralazy.UserGroup.hbm.xml"}; } + } + + protected override string CacheConcurrencyStrategy + { + get { return null; } + } + + [Test, Ignore("Not supported yet") ] + public void OrphanDelete() + { + ISession s = OpenSession(); + ITransaction t = s.BeginTransaction(); + User gavin = new User("gavin", "secret"); + Document hia = new Document("HiA", "blah blah blah", gavin); + Document hia2 = new Document("HiA2", "blah blah blah blah", gavin); + gavin.Documents.Add(hia); // NH: added ; I don't understand how can work in H3.2.5 without add + gavin.Documents.Add(hia2);// NH: added + s.Persist(gavin); + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + gavin = s.Get<User>("gavin"); + Assert.AreEqual(2, gavin.Documents.Count); + gavin.Documents.Remove(hia2); + Assert.IsFalse(gavin.Documents.Contains(hia2)); + Assert.IsTrue(gavin.Documents.Contains(hia)); + Assert.AreEqual(1, gavin.Documents.Count); + Assert.IsFalse(NHibernateUtil.IsInitialized(gavin.Documents)); + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + gavin = s.Get<User>("gavin"); + Assert.AreEqual(1, gavin.Documents.Count); + Assert.IsFalse(gavin.Documents.Contains(hia2)); + Assert.IsTrue(gavin.Documents.Contains(hia)); + Assert.IsFalse(NHibernateUtil.IsInitialized(gavin.Documents)); + Assert.That(s.Get<Document>("HiA2"), Is.Null); + gavin.Documents.Clear(); + Assert.IsTrue(NHibernateUtil.IsInitialized(gavin.Documents)); + s.Delete(gavin); + t.Commit(); + s.Close(); + } + + [Test] + public void Get() + { + ISession s = OpenSession(); + ITransaction t = s.BeginTransaction(); + User gavin = new User("gavin", "secret"); + User turin = new User("turin", "tiger"); + Group g = new Group("developers"); + g.Users.Add("gavin", gavin); + g.Users.Add("turin", turin); + s.Persist(g); + gavin.Session.Add("foo", new SessionAttribute("foo", "foo bar baz")); + gavin.Session.Add("bar", new SessionAttribute("bar", "foo bar baz 2")); + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + g = s.Get<Group>("developers"); + gavin = (User) g.Users["gavin"]; + turin = (User) g.Users["turin"]; + Assert.That(gavin, Is.Not.Null); + Assert.That(turin, Is.Not.Null); + Assert.That(g.Users["emmanuel"], Is.Null); + Assert.IsFalse(NHibernateUtil.IsInitialized(g.Users)); + Assert.That(gavin.Session["foo"], Is.Not.Null); + Assert.That(turin.Session["foo"], Is.Null); + Assert.IsFalse(NHibernateUtil.IsInitialized(gavin.Session)); + Assert.IsFalse(NHibernateUtil.IsInitialized(turin.Session)); + s.Delete(gavin); + s.Delete(turin); + s.Delete(g); + t.Commit(); + s.Close(); + } + + [Test] + public void RemoveClear() + { + ISession s = OpenSession(); + ITransaction t = s.BeginTransaction(); + User gavin = new User("gavin", "secret"); + User turin = new User("turin", "tiger"); + Group g = new Group("developers"); + g.Users.Add("gavin", gavin); + g.Users.Add("turin", turin); + s.Persist(g); + gavin.Session.Add("foo", new SessionAttribute("foo", "foo bar baz")); + gavin.Session.Add("bar", new SessionAttribute("bar", "foo bar baz 2")); + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + g = s.Get<Group>("developers"); + gavin = (User) g.Users["gavin"]; + turin = (User) g.Users["turin"]; + Assert.IsFalse(NHibernateUtil.IsInitialized(g.Users)); + g.Users.Clear(); + gavin.Session.Remove("foo"); + Assert.IsTrue(NHibernateUtil.IsInitialized(g.Users)); + Assert.IsTrue(NHibernateUtil.IsInitialized(gavin.Session)); + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + g = s.Get<Group>("developers"); + //Assert.IsTrue( g.Users.IsEmpty() ); + //Assert.IsFalse( NHibernateUtil.IsInitialized( g.getUsers() ) ); + gavin = s.Get<User>("gavin"); + Assert.IsFalse(gavin.Session.Contains("foo")); + Assert.IsFalse(NHibernateUtil.IsInitialized(gavin.Session)); + s.Delete(gavin); + s.Delete(turin); + s.Delete(g); + t.Commit(); + s.Close(); + } + + [Test, Ignore("Not supported yet")] + public void IndexFormulaMap() + { + ISession s = OpenSession(); + ITransaction t = s.BeginTransaction(); + User gavin = new User("gavin", "secret"); + User turin = new User("turin", "tiger"); + Group g = new Group("developers"); + g.Users.Add("gavin", gavin); + g.Users.Add("turin", turin); + s.Persist(g); + gavin.Session.Add("foo", new SessionAttribute("foo", "foo bar baz")); + gavin.Session.Add("bar", new SessionAttribute("bar", "foo bar baz 2")); + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + g = s.Get<Group>("developers"); + Assert.AreEqual(2, g.Users.Count); + g.Users.Remove("turin"); + IDictionary smap = ((User) g.Users["gavin"]).Session; + Assert.AreEqual(2, smap.Count); + smap.Remove("bar"); + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + g = s.Get<Group>("developers"); + Assert.AreEqual(1, g.Users.Count); + smap = ((User) g.Users["gavin"]).Session; + Assert.AreEqual(1, smap.Count); + g.Users["gavin"]= turin; + gavin = (User) g.Users["gavin"]; + s.Delete(gavin); + Assert.AreEqual(0, s.CreateQuery("select count(*) from SessionAttribute").UniqueResult<long>()); + t.Commit(); + s.Close(); + + s = OpenSession(); + t = s.BeginTransaction(); + g = s.Get<Group>("developers"); + Assert.AreEqual(1, g.Users.Count); + turin = (User) g.Users["turin"]; + smap = turin.Session; + Assert.AreEqual(0, smap.Count); + Assert.AreEqual(1L, s.CreateQuery("select count(*) from User").UniqueResult<long>()); + s.Delete(g); + s.Delete(turin); + Assert.AreEqual(0, s.CreateQuery("select count(*) from User").UniqueResult<long>()); + t.Commit(); + s.Close(); + } + + [Test] + public void SQLQuery() + { + ISession s = OpenSession(); + ITransaction t = s.BeginTransaction(); + User gavin = new User("gavin", "secret"); + User turin = new User("turin", "tiger"); + gavin.Session.Add("foo", new SessionAttribute("foo", "foo bar baz")); + gavin.Session.Add("bar", new SessionAttribute("bar", "foo bar baz 2")); + s.Persist(gavin); + s.Persist(turin); + s.Flush(); + s.Clear(); + + IList results = s.GetNamedQuery("UserSessionData").SetParameter("uname", "%in").List(); + Assert.AreEqual(2, results.Count); + gavin = (User) ((object[]) results[0])[0]; + Assert.AreEqual("gavin", gavin.Name); + Assert.AreEqual(2, gavin.Session.Count); + t.Commit(); + s.Close(); + + using (s = OpenSession()) + using (t= s.BeginTransaction()) + { + s.Delete("from SessionAttribute"); + s.Delete("from User"); + t.Commit(); + } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Extralazy/Group.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Extralazy/Group.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Extralazy/Group.cs 2008-08-18 14:21:05 UTC (rev 3715) @@ -0,0 +1,27 @@ +using System.Collections; + +namespace NHibernate.Test.Extralazy +{ + public class Group + { + private string name; + private IDictionary users = new Hashtable(); + protected Group() {} + public Group(string name) + { + this.name = name; + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual IDictionary Users + { + get { return users; } + set { users = value; } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Extralazy/SessionAttribute.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Extralazy/SessionAttribute.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Extralazy/SessionAttribute.cs 2008-08-18 14:21:05 UTC (rev 3715) @@ -0,0 +1,42 @@ +namespace NHibernate.Test.Extralazy +{ + public class SessionAttribute + { +#pragma warning disable 169 + private long id; +#pragma warning restore 169 + private string name; + private string stringData; + private object objectData; + protected SessionAttribute() {} + public SessionAttribute(string name, string stringData) + { + this.name = name; + this.stringData = stringData; + } + + public SessionAttribute(string name, object objectData) + { + this.name = name; + this.objectData = objectData; + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual string StringData + { + get { return stringData; } + set { stringData = value; } + } + + public virtual object ObjectData + { + get { return objectData; } + set { objectData = value; } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Extralazy/User.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Extralazy/User.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Extralazy/User.cs 2008-08-18 14:21:05 UTC (rev 3715) @@ -0,0 +1,43 @@ +using System.Collections; +using Iesi.Collections; + +namespace NHibernate.Test.Extralazy +{ + public class User + { + private string name; + private string password; + private IDictionary session = new Hashtable(); + private ISet documents = new HashedSet(); + protected User() {} + public User(string name, string password) + { + this.name = name; + this.password = password; + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual string Password + { + get { return password; } + set { password = value; } + } + + public virtual IDictionary Session + { + get { return session; } + set { session = value; } + } + + public virtual ISet Documents + { + get { return documents; } + set { documents = value; } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Extralazy/UserGroup.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Extralazy/UserGroup.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Extralazy/UserGroup.hbm.xml 2008-08-18 14:21:05 UTC (rev 3715) @@ -0,0 +1,62 @@ +<?xml version="1.0"?> + +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.Extralazy"> + + <class name="Group" table="groups"> + <id name="Name"/> + <map name="Users" cascade="persist" table="group_user" lazy="extra"> + <key column="groupName"/> + <map-key formula="lower(personName)" type="string"/> + <many-to-many class="User" column="personName"/> + </map> + </class> + + <class name="User" table="users"> + <id name="Name"/> + <property name="Password"/> + <map name="Session" lazy="extra" cascade="persist,save-update,delete,delete-orphan"> + <key column="userName"/> <!--Need to investigate not-null="true"--> + <map-key column="name" type="string"/> + <one-to-many class="SessionAttribute"/> + </map> + <set name="Documents" inverse="true" lazy="extra" cascade="all,delete-orphan"> + <key column="owner"/> + <one-to-many class="Document"/> + </set> + </class> + + <class name="Document" table="documents"> + <id name="Title"/> + <property name="Content" type="string" length="10000"/> + <many-to-one name="Owner" not-null="true"/> + </class> + + <class name="SessionAttribute" table="session_attributes"> + <id name="id" access="field"> + <generator class="native"/> + </id> + <property name="Name" update="false"/> <!--Need to investigate not-null="true"--> + <property name="StringData"/> + <property name="ObjectData" type="Serializable"/> + </class> + <!-- + NH the map of SessionAttribute in H3.2.6 have insert="false" for property "Name" but it can't work with not-null="true" + We remove the inconsistence. + --> + + <sql-query name="UserSessionData"> + <return alias="u" class="User"/> + <return-join alias="s" property="u.Session"/> + select + lower(u.name) as {u.Name}, lower(u.password) as {u.Password}, + lower(s.userName) as {s.key}, lower(s.name) as {s.index}, s.id as {s.element}, + {s.element.*} + from users u + join session_attributes s on lower(s.userName) = lower(u.name) + where u.name like :uname + </sql-query> + + +</hibernate-mapping> Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-08-18 13:38:05 UTC (rev 3714) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-08-18 14:21:05 UTC (rev 3715) @@ -173,6 +173,11 @@ <Compile Include="ExpressionTest\SQLExpressionFixture.cs" /> <Compile Include="ExpressionTest\SubQueries\Classes.cs" /> <Compile Include="ExpressionTest\SubQueries\SubQueriesSqlFixture.cs" /> + <Compile Include="Extralazy\Document.cs" /> + <Compile Include="Extralazy\ExtraLazyFixture.cs" /> + <Compile Include="Extralazy\Group.cs" /> + <Compile Include="Extralazy\SessionAttribute.cs" /> + <Compile Include="Extralazy\User.cs" /> <Compile Include="FilterTest\BinaryFiltered.cs" /> <Compile Include="FilterTest\Category.cs" /> <Compile Include="FilterTest\Department.cs" /> @@ -1410,6 +1415,7 @@ <EmbeddedResource Include="CompositeId\Order.hbm.xml" /> <EmbeddedResource Include="CompositeId\Product.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="Extralazy\UserGroup.hbm.xml" /> <EmbeddedResource Include="Naturalid\Immutable\User.hbm.xml" /> <EmbeddedResource Include="Naturalid\Mutable\User.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1419\Mappings.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-08-18 17:27:01
|
Revision: 3717 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3717&view=rev Author: fabiomaulo Date: 2008-08-18 17:27:06 +0000 (Mon, 18 Aug 2008) Log Message: ----------- Support of lazy="extra" on air Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs trunk/nhibernate/src/NHibernate/Engine/Cascade.cs trunk/nhibernate/src/NHibernate.Test/Extralazy/ExtraLazyFixture.cs Modified: trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs 2008-08-18 14:29:49 UTC (rev 3716) +++ trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs 2008-08-18 17:27:06 UTC (rev 3717) @@ -225,7 +225,7 @@ //ORPHAN DELETE (used for programmer error detection) XmlAttribute cascadeAtt = node.Attributes["cascade"]; - if (cascadeAtt != null && cascadeAtt.Value.Equals("all-delete-orphan")) + if (cascadeAtt != null && cascadeAtt.Value.IndexOf("delete-orphan") >= 0) model.HasOrphanDelete = true; bool? isGeneric = null; Modified: trunk/nhibernate/src/NHibernate/Engine/Cascade.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/Cascade.cs 2008-08-18 14:29:49 UTC (rev 3716) +++ trunk/nhibernate/src/NHibernate/Engine/Cascade.cs 2008-08-18 17:27:06 UTC (rev 3717) @@ -262,7 +262,7 @@ } else { - orphans = CollectionHelper.EmptyCollection; // TODO NH: H3.2 Different pc.GetQueuedOrphans(entityName); + orphans = pc.GetQueuedOrphans(entityName); } foreach (object orphan in orphans) Modified: trunk/nhibernate/src/NHibernate.Test/Extralazy/ExtraLazyFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Extralazy/ExtraLazyFixture.cs 2008-08-18 14:29:49 UTC (rev 3716) +++ trunk/nhibernate/src/NHibernate.Test/Extralazy/ExtraLazyFixture.cs 2008-08-18 17:27:06 UTC (rev 3717) @@ -22,7 +22,7 @@ get { return null; } } - [Test, Ignore("Not supported yet") ] + [Test] public void OrphanDelete() { ISession s = OpenSession(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-08-19 13:23:24
|
Revision: 3720 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3720&view=rev Author: fabiomaulo Date: 2008-08-19 13:23:30 +0000 (Tue, 19 Aug 2008) Log Message: ----------- Start porting of new events Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs trunk/nhibernate/src/NHibernate/Cfg/ConfigurationSchema/CfgXmlHelper.cs trunk/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs trunk/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs trunk/nhibernate/src/NHibernate/Event/EventListeners.cs trunk/nhibernate/src/NHibernate/Event/InitializeCollectionEvent.cs trunk/nhibernate/src/NHibernate/Event/ListenerType.cs trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj trunk/nhibernate/src/NHibernate/Type/CollectionType.cs trunk/nhibernate/src/NHibernate/nhibernate-configuration.xsd trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Event/AbstractCollectionEvent.cs trunk/nhibernate/src/NHibernate/Event/IPostCollectionRecreateEventListener.cs trunk/nhibernate/src/NHibernate/Event/IPostCollectionRemoveEventListener.cs trunk/nhibernate/src/NHibernate/Event/IPostCollectionUpdateEventListener.cs trunk/nhibernate/src/NHibernate/Event/IPreCollectionRecreateEventListener.cs trunk/nhibernate/src/NHibernate/Event/IPreCollectionRemoveEventListener.cs trunk/nhibernate/src/NHibernate/Event/IPreCollectionUpdateEventListener.cs trunk/nhibernate/src/NHibernate/Event/PostCollectionRecreateEvent.cs trunk/nhibernate/src/NHibernate/Event/PostCollectionRemoveEvent.cs trunk/nhibernate/src/NHibernate/Event/PostCollectionUpdateEvent.cs trunk/nhibernate/src/NHibernate/Event/PreCollectionRecreateEvent.cs trunk/nhibernate/src/NHibernate/Event/PreCollectionRemoveEvent.cs trunk/nhibernate/src/NHibernate/Event/PreCollectionUpdateEvent.cs trunk/nhibernate/src/NHibernate.Test/Events/ Modified: trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2008-08-18 19:58:38 UTC (rev 3719) +++ trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -1666,93 +1666,110 @@ private void ClearListeners(ListenerType type) { - switch (type) { case ListenerType.Autoflush: - eventListeners.AutoFlushEventListeners = new IAutoFlushEventListener[] { }; + eventListeners.AutoFlushEventListeners = new IAutoFlushEventListener[] {}; break; case ListenerType.Merge: - eventListeners.MergeEventListeners = new IMergeEventListener[] { }; + eventListeners.MergeEventListeners = new IMergeEventListener[] {}; break; case ListenerType.Create: - eventListeners.PersistEventListeners = new IPersistEventListener[] { }; + eventListeners.PersistEventListeners = new IPersistEventListener[] {}; break; case ListenerType.CreateOnFlush: - eventListeners.PersistOnFlushEventListeners = new IPersistEventListener[] { }; + eventListeners.PersistOnFlushEventListeners = new IPersistEventListener[] {}; break; case ListenerType.Delete: - eventListeners.DeleteEventListeners = new IDeleteEventListener[] { }; + eventListeners.DeleteEventListeners = new IDeleteEventListener[] {}; break; case ListenerType.DirtyCheck: - eventListeners.DirtyCheckEventListeners = new IDirtyCheckEventListener[] { }; + eventListeners.DirtyCheckEventListeners = new IDirtyCheckEventListener[] {}; break; case ListenerType.Evict: - eventListeners.EvictEventListeners = new IEvictEventListener[] { }; + eventListeners.EvictEventListeners = new IEvictEventListener[] {}; break; case ListenerType.Flush: - eventListeners.FlushEventListeners = new IFlushEventListener[] { }; + eventListeners.FlushEventListeners = new IFlushEventListener[] {}; break; case ListenerType.FlushEntity: - eventListeners.FlushEntityEventListeners = new IFlushEntityEventListener[] { }; + eventListeners.FlushEntityEventListeners = new IFlushEntityEventListener[] {}; break; case ListenerType.Load: - eventListeners.LoadEventListeners = new ILoadEventListener[] { }; + eventListeners.LoadEventListeners = new ILoadEventListener[] {}; break; case ListenerType.LoadCollection: - eventListeners.InitializeCollectionEventListeners = new IInitializeCollectionEventListener[] { }; + eventListeners.InitializeCollectionEventListeners = new IInitializeCollectionEventListener[] {}; break; case ListenerType.Lock: - eventListeners.LockEventListeners = new ILockEventListener[] { }; + eventListeners.LockEventListeners = new ILockEventListener[] {}; break; case ListenerType.Refresh: - eventListeners.RefreshEventListeners = new IRefreshEventListener[] { }; + eventListeners.RefreshEventListeners = new IRefreshEventListener[] {}; break; case ListenerType.Replicate: - eventListeners.ReplicateEventListeners = new IReplicateEventListener[] { }; + eventListeners.ReplicateEventListeners = new IReplicateEventListener[] {}; break; case ListenerType.SaveUpdate: - eventListeners.SaveOrUpdateEventListeners = new ISaveOrUpdateEventListener[] { }; + eventListeners.SaveOrUpdateEventListeners = new ISaveOrUpdateEventListener[] {}; break; case ListenerType.Save: - eventListeners.SaveEventListeners = new ISaveOrUpdateEventListener[] { }; + eventListeners.SaveEventListeners = new ISaveOrUpdateEventListener[] {}; break; case ListenerType.PreUpdate: - eventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[] { }; + eventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[] {}; break; case ListenerType.Update: - eventListeners.UpdateEventListeners = new ISaveOrUpdateEventListener[] { }; + eventListeners.UpdateEventListeners = new ISaveOrUpdateEventListener[] {}; break; case ListenerType.PreLoad: - eventListeners.PreLoadEventListeners = new IPreLoadEventListener[] { }; + eventListeners.PreLoadEventListeners = new IPreLoadEventListener[] {}; break; case ListenerType.PreDelete: - eventListeners.PreDeleteEventListeners = new IPreDeleteEventListener[] { }; + eventListeners.PreDeleteEventListeners = new IPreDeleteEventListener[] {}; break; case ListenerType.PreInsert: - eventListeners.PreInsertEventListeners = new IPreInsertEventListener[] { }; + eventListeners.PreInsertEventListeners = new IPreInsertEventListener[] {}; break; case ListenerType.PostLoad: - eventListeners.PostLoadEventListeners = new IPostLoadEventListener[] { }; + eventListeners.PostLoadEventListeners = new IPostLoadEventListener[] {}; break; case ListenerType.PostInsert: - eventListeners.PostInsertEventListeners = new IPostInsertEventListener[] { }; + eventListeners.PostInsertEventListeners = new IPostInsertEventListener[] {}; break; case ListenerType.PostUpdate: - eventListeners.PostUpdateEventListeners = new IPostUpdateEventListener[] { }; + eventListeners.PostUpdateEventListeners = new IPostUpdateEventListener[] {}; break; case ListenerType.PostDelete: - eventListeners.PostDeleteEventListeners = new IPostDeleteEventListener[] { }; + eventListeners.PostDeleteEventListeners = new IPostDeleteEventListener[] {}; break; case ListenerType.PostCommitUpdate: - eventListeners.PostCommitUpdateEventListeners = new IPostUpdateEventListener[] { }; + eventListeners.PostCommitUpdateEventListeners = new IPostUpdateEventListener[] {}; break; case ListenerType.PostCommitInsert: - eventListeners.PostCommitInsertEventListeners = new IPostInsertEventListener[] { }; + eventListeners.PostCommitInsertEventListeners = new IPostInsertEventListener[] {}; break; case ListenerType.PostCommitDelete: - eventListeners.PostCommitDeleteEventListeners = new IPostDeleteEventListener[] { }; + eventListeners.PostCommitDeleteEventListeners = new IPostDeleteEventListener[] {}; break; + case ListenerType.PreCollectionRecreate: + eventListeners.PreCollectionRecreateEventListeners = new IPreCollectionRecreateEventListener[] {}; + break; + case ListenerType.PreCollectionRemove: + eventListeners.PreCollectionRemoveEventListeners = new IPreCollectionRemoveEventListener[] {}; + break; + case ListenerType.PreCollectionUpdate: + eventListeners.PreCollectionUpdateEventListeners = new IPreCollectionUpdateEventListener[] {}; + break; + case ListenerType.PostCollectionRecreate: + eventListeners.PostCollectionRecreateEventListeners = new IPostCollectionRecreateEventListener[] {}; + break; + case ListenerType.PostCollectionRemove: + eventListeners.PostCollectionRemoveEventListeners = new IPostCollectionRemoveEventListener[] {}; + break; + case ListenerType.PostCollectionUpdate: + eventListeners.PostCollectionUpdateEventListeners = new IPostCollectionUpdateEventListener[] {}; + break; default: log.Warn("Unrecognized listener type [" + type + "]"); break; @@ -1856,6 +1873,24 @@ case ListenerType.PostCommitDelete: eventListeners.PostCommitDeleteEventListeners = (IPostDeleteEventListener[])listeners; break; + case ListenerType.PreCollectionRecreate: + eventListeners.PreCollectionRecreateEventListeners = (IPreCollectionRecreateEventListener[])listeners; + break; + case ListenerType.PreCollectionRemove: + eventListeners.PreCollectionRemoveEventListeners = (IPreCollectionRemoveEventListener[])listeners; + break; + case ListenerType.PreCollectionUpdate: + eventListeners.PreCollectionUpdateEventListeners = (IPreCollectionUpdateEventListener[])listeners; + break; + case ListenerType.PostCollectionRecreate: + eventListeners.PostCollectionRecreateEventListeners = (IPostCollectionRecreateEventListener[])listeners; + break; + case ListenerType.PostCollectionRemove: + eventListeners.PostCollectionRemoveEventListeners = (IPostCollectionRemoveEventListener[])listeners; + break; + case ListenerType.PostCollectionUpdate: + eventListeners.PostCollectionUpdateEventListeners = (IPostCollectionUpdateEventListener[])listeners; + break; default: log.Warn("Unrecognized listener type [" + type + "]"); break; Modified: trunk/nhibernate/src/NHibernate/Cfg/ConfigurationSchema/CfgXmlHelper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/ConfigurationSchema/CfgXmlHelper.cs 2008-08-18 19:58:38 UTC (rev 3719) +++ trunk/nhibernate/src/NHibernate/Cfg/ConfigurationSchema/CfgXmlHelper.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -254,6 +254,18 @@ return ListenerType.PostCommitInsert; case "post-commit-delete": return ListenerType.PostCommitDelete; + case "pre-collection-recreate": + return ListenerType.PreCollectionRecreate; + case "pre-collection-remove": + return ListenerType.PreCollectionRemove; + case "pre-collection-update": + return ListenerType.PreCollectionUpdate; + case "post-collection-recreate": + return ListenerType.PostCollectionRecreate; + case "post-collection-remove": + return ListenerType.PostCollectionRemove; + case "post-collection-update": + return ListenerType.PostCollectionUpdate; default: throw new HibernateConfigException(string.Format("Invalid ListenerType value:{0}", listenerType)); } @@ -319,6 +331,18 @@ return "post-commit-insert"; case ListenerType.PostCommitDelete: return "post-commit-delete"; + case ListenerType.PreCollectionRecreate: + return "pre-collection-recreate"; + case ListenerType.PreCollectionRemove: + return "pre-collection-remove"; + case ListenerType.PreCollectionUpdate: + return "pre-collection-update"; + case ListenerType.PostCollectionRecreate: + return "post-collection-recreate"; + case ListenerType.PostCollectionRemove: + return "post-collection-remove"; + case ListenerType.PostCollectionUpdate: + return "post-collection-update"; default: return string.Empty; } Modified: trunk/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs 2008-08-18 19:58:38 UTC (rev 3719) +++ trunk/nhibernate/src/NHibernate/Engine/IPersistenceContext.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -226,6 +226,19 @@ /// <summary> Get the entity that owns this persistent collection</summary> object GetCollectionOwner(object key, ICollectionPersister collectionPersister); + /// <summary> Get the entity that owned this persistent collection when it was loaded </summary> + /// <param name="collection">The persistent collection </param> + /// <returns> + /// The owner if its entity ID is available from the collection's loaded key + /// and the owner entity is in the persistence context; otherwise, returns null + /// </returns> + object GetLoadedCollectionOwnerOrNull(IPersistentCollection collection); + + /// <summary> Get the ID for the entity that owned this persistent collection when it was loaded </summary> + /// <param name="collection">The persistent collection </param> + /// <returns> the owner ID if available from the collection's loaded key; otherwise, returns null </returns> + object GetLoadedCollectionOwnerIdOrNull(IPersistentCollection collection); + /// <summary> add a collection we just loaded up (still needs initializing)</summary> void AddUninitializedCollection(ICollectionPersister persister, IPersistentCollection collection, object id); Modified: trunk/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs 2008-08-18 19:58:38 UTC (rev 3719) +++ trunk/nhibernate/src/NHibernate/Engine/StatefulPersistenceContext.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -80,16 +80,16 @@ // yet loaded ... for now, this is purely transient! private Dictionary<CollectionKey, IPersistentCollection> unownedCollections; - private bool hasNonReadOnlyEntities = false; + private bool hasNonReadOnlyEntities; [NonSerialized] - private int cascading = 0; + private int cascading; [NonSerialized] - private bool flushing = false; + private bool flushing; [NonSerialized] - private int loadCounter = 0; + private int loadCounter; [NonSerialized] private LoadContexts loadContexts; @@ -101,6 +101,9 @@ /// <param name="session">The session "owning" this context. </param> public StatefulPersistenceContext(ISessionImplementor session) { + loadCounter = 0; + flushing = false; + cascading = 0; this.session = session; entitiesByKey = new Dictionary<EntityKey, object>(InitCollectionSize); @@ -761,6 +764,52 @@ return GetEntity(new EntityKey(key, collectionPersister.OwnerEntityPersister, session.EntityMode)); } + /// <summary> Get the entity that owned this persistent collection when it was loaded </summary> + /// <param name="collection">The persistent collection </param> + /// <returns> + /// The owner, if its entity ID is available from the collection's loaded key + /// and the owner entity is in the persistence context; otherwise, returns null + /// </returns> + public virtual object GetLoadedCollectionOwnerOrNull(IPersistentCollection collection) + { + CollectionEntry ce = GetCollectionEntry(collection); + if (ce.LoadedPersister == null) + { + return null; // early exit... + } + object loadedOwner = null; + // TODO: an alternative is to check if the owner has changed; if it hasn't then + // return collection.getOwner() + object entityId = GetLoadedCollectionOwnerIdOrNull(ce); + if (entityId != null) + { + loadedOwner = GetCollectionOwner(entityId, ce.LoadedPersister); + } + return loadedOwner; + } + + /// <summary> Get the ID for the entity that owned this persistent collection when it was loaded </summary> + /// <param name="collection">The persistent collection </param> + /// <returns> the owner ID if available from the collection's loaded key; otherwise, returns null </returns> + public virtual object GetLoadedCollectionOwnerIdOrNull(IPersistentCollection collection) + { + return GetLoadedCollectionOwnerIdOrNull(GetCollectionEntry(collection)); + } + + /// <summary> Get the ID for the entity that owned this persistent collection when it was loaded </summary> + /// <param name="ce">The collection entry </param> + /// <returns> the owner ID if available from the collection's loaded key; otherwise, returns null </returns> + private object GetLoadedCollectionOwnerIdOrNull(CollectionEntry ce) + { + if (ce == null || ce.LoadedKey == null || ce.LoadedPersister == null) + { + return null; + } + // TODO: an alternative is to check if the owner has changed; if it hasn't then + // get the ID from collection.getOwner() + return ce.LoadedPersister.CollectionType.GetIdOfOwnerOrNull(ce.LoadedKey, session); + } + /// <summary> add a collection we just loaded up (still needs initializing)</summary> public void AddUninitializedCollection(ICollectionPersister persister, IPersistentCollection collection, object id) { @@ -1159,6 +1208,9 @@ #region ISerializable Members internal StatefulPersistenceContext(SerializationInfo info, StreamingContext context) { + loadCounter = 0; + flushing = false; + cascading = 0; entitiesByKey = (Dictionary<EntityKey, object>)info.GetValue("context.entitiesByKey", typeof(Dictionary<EntityKey, object>)); entitiesByUniqueKey = (Dictionary<EntityUniqueKey, object>)info.GetValue("context.entitiesByUniqueKey", typeof(Dictionary<EntityUniqueKey, object>)); entityEntries = (IdentityMap)info.GetValue("context.entityEntries", typeof(IdentityMap)); Added: trunk/nhibernate/src/NHibernate/Event/AbstractCollectionEvent.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/AbstractCollectionEvent.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Event/AbstractCollectionEvent.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -0,0 +1,111 @@ +using System; +using NHibernate.Collection; +using NHibernate.Engine; +using NHibernate.Persister.Collection; + +namespace NHibernate.Event +{ + /// <summary> Defines a base class for events involving collections. </summary> + [Serializable] + public abstract class AbstractCollectionEvent : AbstractEvent + { + private readonly object affectedOwner; + private readonly string affectedOwnerEntityName; + private readonly object affectedOwnerId; + private readonly IPersistentCollection collection; + + /// <summary> Constructs an AbstractCollectionEvent object. </summary> + /// <param name="collectionPersister">The collection persister.</param> + /// <param name="collection">The collection </param> + /// <param name="source">The Session source </param> + /// <param name="affectedOwner">The owner that is affected by this event; can be null if unavailable </param> + /// <param name="affectedOwnerId"> + /// The ID for the owner that is affected by this event; can be null if unavailable + /// that is affected by this event; can be null if unavailable + /// </param> + protected AbstractCollectionEvent(ICollectionPersister collectionPersister, IPersistentCollection collection, + IEventSource source, object affectedOwner, object affectedOwnerId) : base(source) + { + this.collection = collection; + this.affectedOwner = affectedOwner; + this.affectedOwnerId = affectedOwnerId; + affectedOwnerEntityName = GetAffectedOwnerEntityName(collectionPersister, affectedOwner, source); + } + + public IPersistentCollection Collection + { + get { return collection; } + } + + /// <summary> The collection owner entity that is affected by this event. </summary> + /// <value> + /// Returns null if the entity is not in the persistence context + /// (e.g., because the collection from a detached entity was moved to a new owner) + /// </value> + public object AffectedOwnerOrNull + { + get { return affectedOwner; } + } + + /// <summary> Get the ID for the collection owner entity that is affected by this event. </summary> + /// <value> + /// Returns null if the ID cannot be obtained + /// from the collection's loaded key (e.g., a property-ref is used for the + /// collection and does not include the entity's ID) + /// </value> + public object AffectedOwnerIdOrNull + { + get { return affectedOwnerId; } + } + + protected static ICollectionPersister GetLoadedCollectionPersister(IPersistentCollection collection, + IEventSource source) + { + CollectionEntry ce = source.PersistenceContext.GetCollectionEntry(collection); + return (ce == null ? null : ce.LoadedPersister); + } + + protected static object GetLoadedOwnerOrNull(IPersistentCollection collection, IEventSource source) + { + return source.PersistenceContext.GetLoadedCollectionOwnerOrNull(collection); + } + + protected static object GetLoadedOwnerIdOrNull(IPersistentCollection collection, IEventSource source) + { + return source.PersistenceContext.GetLoadedCollectionOwnerIdOrNull(collection); + } + + protected static object GetOwnerIdOrNull(object owner, IEventSource source) + { + EntityEntry ownerEntry = source.PersistenceContext.GetEntry(owner); + return (ownerEntry == null ? null : ownerEntry.Id); + } + + protected static string GetAffectedOwnerEntityName(ICollectionPersister collectionPersister, object affectedOwner, + IEventSource source) + { + // collectionPersister should not be null, but we don't want to throw + // an exception if it is null + string entityName = (collectionPersister == null ? null : collectionPersister.OwnerEntityPersister.EntityName); + if (affectedOwner != null) + { + EntityEntry ee = source.PersistenceContext.GetEntry(affectedOwner); + if (ee != null && ee.EntityName != null) + { + entityName = ee.EntityName; + } + } + return entityName; + } + + /// <summary> Get the entity name for the collection owner entity that is affected by this event. </summary> + /// <returns> + /// The entity name; if the owner is not in the PersistenceContext, the + /// returned value may be a superclass name, instead of the actual class name + /// </returns> + public virtual string GetAffectedOwnerEntityName() + { + return affectedOwnerEntityName; + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Event/EventListeners.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/EventListeners.cs 2008-08-18 19:58:38 UTC (rev 3719) +++ trunk/nhibernate/src/NHibernate/Event/EventListeners.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -2,6 +2,7 @@ using System.Collections.Generic; using NHibernate.Cfg; using NHibernate.Event.Default; +using NHibernate.Util; namespace NHibernate.Event { @@ -13,71 +14,127 @@ { private static readonly IDictionary<ListenerType, System.Type> eventInterfaceFromType = new Dictionary<ListenerType, System.Type>(28); + static EventListeners() { - eventInterfaceFromType[ListenerType.Autoflush] = typeof(IAutoFlushEventListener); - eventInterfaceFromType[ListenerType.Merge] = typeof(IMergeEventListener); - eventInterfaceFromType[ListenerType.Create] = typeof(IPersistEventListener); - eventInterfaceFromType[ListenerType.CreateOnFlush] = typeof(IPersistEventListener); - eventInterfaceFromType[ListenerType.Delete] = typeof(IDeleteEventListener); - eventInterfaceFromType[ListenerType.DirtyCheck] = typeof(IDirtyCheckEventListener); - eventInterfaceFromType[ListenerType.Evict] = typeof(IEvictEventListener); - eventInterfaceFromType[ListenerType.Flush] = typeof(IFlushEventListener); - eventInterfaceFromType[ListenerType.FlushEntity] = typeof(IFlushEntityEventListener); - eventInterfaceFromType[ListenerType.Load] = typeof(ILoadEventListener); - eventInterfaceFromType[ListenerType.LoadCollection] = typeof(IInitializeCollectionEventListener); - eventInterfaceFromType[ListenerType.Lock] = typeof(ILockEventListener); - eventInterfaceFromType[ListenerType.Refresh] = typeof(IRefreshEventListener); - eventInterfaceFromType[ListenerType.Replicate] = typeof(IReplicateEventListener); - eventInterfaceFromType[ListenerType.SaveUpdate] = typeof(ISaveOrUpdateEventListener); - eventInterfaceFromType[ListenerType.Save] = typeof(ISaveOrUpdateEventListener); - eventInterfaceFromType[ListenerType.Update] = typeof(ISaveOrUpdateEventListener); - eventInterfaceFromType[ListenerType.PreLoad] = typeof(IPreLoadEventListener); - eventInterfaceFromType[ListenerType.PreUpdate] = typeof(IPreUpdateEventListener); - eventInterfaceFromType[ListenerType.PreDelete] = typeof(IPreDeleteEventListener); - eventInterfaceFromType[ListenerType.PreInsert] = typeof(IPreInsertEventListener); - eventInterfaceFromType[ListenerType.PostLoad] = typeof(IPostLoadEventListener); - eventInterfaceFromType[ListenerType.PostUpdate] = typeof(IPostUpdateEventListener); - eventInterfaceFromType[ListenerType.PostDelete] = typeof(IPostDeleteEventListener); - eventInterfaceFromType[ListenerType.PostInsert] = typeof(IPostInsertEventListener); - eventInterfaceFromType[ListenerType.PostCommitUpdate] = typeof(IPostUpdateEventListener); - eventInterfaceFromType[ListenerType.PostCommitDelete] = typeof(IPostDeleteEventListener); - eventInterfaceFromType[ListenerType.PostCommitInsert] = typeof(IPostInsertEventListener); + eventInterfaceFromType[ListenerType.Autoflush] = typeof (IAutoFlushEventListener); + eventInterfaceFromType[ListenerType.Merge] = typeof (IMergeEventListener); + eventInterfaceFromType[ListenerType.Create] = typeof (IPersistEventListener); + eventInterfaceFromType[ListenerType.CreateOnFlush] = typeof (IPersistEventListener); + eventInterfaceFromType[ListenerType.Delete] = typeof (IDeleteEventListener); + eventInterfaceFromType[ListenerType.DirtyCheck] = typeof (IDirtyCheckEventListener); + eventInterfaceFromType[ListenerType.Evict] = typeof (IEvictEventListener); + eventInterfaceFromType[ListenerType.Flush] = typeof (IFlushEventListener); + eventInterfaceFromType[ListenerType.FlushEntity] = typeof (IFlushEntityEventListener); + eventInterfaceFromType[ListenerType.Load] = typeof (ILoadEventListener); + eventInterfaceFromType[ListenerType.LoadCollection] = typeof (IInitializeCollectionEventListener); + eventInterfaceFromType[ListenerType.Lock] = typeof (ILockEventListener); + eventInterfaceFromType[ListenerType.Refresh] = typeof (IRefreshEventListener); + eventInterfaceFromType[ListenerType.Replicate] = typeof (IReplicateEventListener); + eventInterfaceFromType[ListenerType.SaveUpdate] = typeof (ISaveOrUpdateEventListener); + eventInterfaceFromType[ListenerType.Save] = typeof (ISaveOrUpdateEventListener); + eventInterfaceFromType[ListenerType.Update] = typeof (ISaveOrUpdateEventListener); + eventInterfaceFromType[ListenerType.PreLoad] = typeof (IPreLoadEventListener); + eventInterfaceFromType[ListenerType.PreUpdate] = typeof (IPreUpdateEventListener); + eventInterfaceFromType[ListenerType.PreDelete] = typeof (IPreDeleteEventListener); + eventInterfaceFromType[ListenerType.PreInsert] = typeof (IPreInsertEventListener); + eventInterfaceFromType[ListenerType.PreCollectionRecreate] = typeof (IPreCollectionRecreateEventListener); + eventInterfaceFromType[ListenerType.PreCollectionRemove] = typeof (IPreCollectionRemoveEventListener); + eventInterfaceFromType[ListenerType.PreCollectionUpdate] = typeof (IPreCollectionUpdateEventListener); + eventInterfaceFromType[ListenerType.PostLoad] = typeof (IPostLoadEventListener); + eventInterfaceFromType[ListenerType.PostUpdate] = typeof (IPostUpdateEventListener); + eventInterfaceFromType[ListenerType.PostDelete] = typeof (IPostDeleteEventListener); + eventInterfaceFromType[ListenerType.PostInsert] = typeof (IPostInsertEventListener); + eventInterfaceFromType[ListenerType.PostCommitUpdate] = typeof (IPostUpdateEventListener); + eventInterfaceFromType[ListenerType.PostCommitDelete] = typeof (IPostDeleteEventListener); + eventInterfaceFromType[ListenerType.PostCommitInsert] = typeof (IPostInsertEventListener); + eventInterfaceFromType[ListenerType.PostCollectionRecreate] = typeof (IPostCollectionRecreateEventListener); + eventInterfaceFromType[ListenerType.PostCollectionRemove] = typeof (IPostCollectionRemoveEventListener); + eventInterfaceFromType[ListenerType.PostCollectionUpdate] = typeof (IPostCollectionUpdateEventListener); + eventInterfaceFromType = new UnmodifiableDictionary<ListenerType, System.Type>(eventInterfaceFromType); } - private ILoadEventListener[] loadEventListeners = new ILoadEventListener[] { new DefaultLoadEventListener() }; - private ISaveOrUpdateEventListener[] saveOrUpdateEventListeners = new ISaveOrUpdateEventListener[] { new DefaultSaveOrUpdateEventListener() }; - private IMergeEventListener[] mergeEventListeners = new IMergeEventListener[] { new DefaultMergeEventListener() }; - private IPersistEventListener[] persistEventListeners = new IPersistEventListener[] { new DefaultPersistEventListener() }; - private IPersistEventListener[] persistOnFlushEventListeners = new IPersistEventListener[] { new DefaultPersistOnFlushEventListener() }; - private IReplicateEventListener[] replicateEventListeners = new IReplicateEventListener[] { new DefaultReplicateEventListener() }; - private IDeleteEventListener[] deleteEventListeners = new IDeleteEventListener[] { new DefaultDeleteEventListener() }; - private IAutoFlushEventListener[] autoFlushEventListeners = new IAutoFlushEventListener[] { new DefaultAutoFlushEventListener() }; - private IDirtyCheckEventListener[] dirtyCheckEventListeners = new IDirtyCheckEventListener[] { new DefaultDirtyCheckEventListener() }; - private IFlushEventListener[] flushEventListeners = new IFlushEventListener[] { new DefaultFlushEventListener() }; - private IEvictEventListener[] evictEventListeners = new IEvictEventListener[] { new DefaultEvictEventListener() }; - private ILockEventListener[] lockEventListeners = new ILockEventListener[] { new DefaultLockEventListener() }; - private IRefreshEventListener[] refreshEventListeners = new IRefreshEventListener[] { new DefaultRefreshEventListener() }; - private IFlushEntityEventListener[] flushEntityEventListeners = new IFlushEntityEventListener[] { new DefaultFlushEntityEventListener() }; - private IInitializeCollectionEventListener[] initializeCollectionEventListeners = new IInitializeCollectionEventListener[] { new DefaultInitializeCollectionEventListener() }; + private ILoadEventListener[] loadEventListeners = new ILoadEventListener[] {new DefaultLoadEventListener()}; - private IPostLoadEventListener[] postLoadEventListeners = new IPostLoadEventListener[] { new DefaultPostLoadEventListener() }; - private IPreLoadEventListener[] preLoadEventListeners = new IPreLoadEventListener[] { new DefaultPreLoadEventListener() }; + private ISaveOrUpdateEventListener[] saveOrUpdateEventListeners = new ISaveOrUpdateEventListener[] + {new DefaultSaveOrUpdateEventListener()}; - private IPreDeleteEventListener[] preDeleteEventListeners = new IPreDeleteEventListener[] { }; - private IPreUpdateEventListener[] preUpdateEventListeners = new IPreUpdateEventListener[] { }; - private IPreInsertEventListener[] preInsertEventListeners = new IPreInsertEventListener[] { }; - private IPostDeleteEventListener[] postDeleteEventListeners = new IPostDeleteEventListener[] { }; - private IPostUpdateEventListener[] postUpdateEventListeners = new IPostUpdateEventListener[] { }; - private IPostInsertEventListener[] postInsertEventListeners = new IPostInsertEventListener[] { }; - private IPostDeleteEventListener[] postCommitDeleteEventListeners = new IPostDeleteEventListener[] { }; - private IPostUpdateEventListener[] postCommitUpdateEventListeners = new IPostUpdateEventListener[] { }; - private IPostInsertEventListener[] postCommitInsertEventListeners = new IPostInsertEventListener[] { }; + private IMergeEventListener[] mergeEventListeners = new IMergeEventListener[] {new DefaultMergeEventListener()}; - private ISaveOrUpdateEventListener[] saveEventListeners = new ISaveOrUpdateEventListener[] { new DefaultSaveEventListener() }; - private ISaveOrUpdateEventListener[] updateEventListeners = new ISaveOrUpdateEventListener[] { new DefaultUpdateEventListener() }; - private IMergeEventListener[] saveOrUpdateCopyEventListeners = new IMergeEventListener[] { new DefaultSaveOrUpdateCopyEventListener() }; //saveOrUpdateCopy() is deprecated! + private IPersistEventListener[] persistEventListeners = new IPersistEventListener[] + {new DefaultPersistEventListener()}; + private IPersistEventListener[] persistOnFlushEventListeners = new IPersistEventListener[] + {new DefaultPersistOnFlushEventListener()}; + + private IReplicateEventListener[] replicateEventListeners = new IReplicateEventListener[] + {new DefaultReplicateEventListener()}; + + private IDeleteEventListener[] deleteEventListeners = new IDeleteEventListener[] {new DefaultDeleteEventListener()}; + + private IAutoFlushEventListener[] autoFlushEventListeners = new IAutoFlushEventListener[] + {new DefaultAutoFlushEventListener()}; + + private IDirtyCheckEventListener[] dirtyCheckEventListeners = new IDirtyCheckEventListener[] + {new DefaultDirtyCheckEventListener()}; + + private IFlushEventListener[] flushEventListeners = new IFlushEventListener[] {new DefaultFlushEventListener()}; + private IEvictEventListener[] evictEventListeners = new IEvictEventListener[] {new DefaultEvictEventListener()}; + private ILockEventListener[] lockEventListeners = new ILockEventListener[] {new DefaultLockEventListener()}; + + private IRefreshEventListener[] refreshEventListeners = new IRefreshEventListener[] + {new DefaultRefreshEventListener()}; + + private IFlushEntityEventListener[] flushEntityEventListeners = new IFlushEntityEventListener[] + {new DefaultFlushEntityEventListener()}; + + private IInitializeCollectionEventListener[] initializeCollectionEventListeners = + new IInitializeCollectionEventListener[] {new DefaultInitializeCollectionEventListener()}; + + private IPostLoadEventListener[] postLoadEventListeners = new IPostLoadEventListener[] + {new DefaultPostLoadEventListener()}; + + private IPreLoadEventListener[] preLoadEventListeners = new IPreLoadEventListener[] + {new DefaultPreLoadEventListener()}; + + private IPreDeleteEventListener[] preDeleteEventListeners = new IPreDeleteEventListener[] {}; + private IPreUpdateEventListener[] preUpdateEventListeners = new IPreUpdateEventListener[] {}; + private IPreInsertEventListener[] preInsertEventListeners = new IPreInsertEventListener[] {}; + private IPostDeleteEventListener[] postDeleteEventListeners = new IPostDeleteEventListener[] {}; + private IPostUpdateEventListener[] postUpdateEventListeners = new IPostUpdateEventListener[] {}; + private IPostInsertEventListener[] postInsertEventListeners = new IPostInsertEventListener[] {}; + private IPostDeleteEventListener[] postCommitDeleteEventListeners = new IPostDeleteEventListener[] {}; + private IPostUpdateEventListener[] postCommitUpdateEventListeners = new IPostUpdateEventListener[] {}; + private IPostInsertEventListener[] postCommitInsertEventListeners = new IPostInsertEventListener[] {}; + + private IPreCollectionRecreateEventListener[] preCollectionRecreateEventListeners = + new IPreCollectionRecreateEventListener[] {}; + + private IPostCollectionRecreateEventListener[] postCollectionRecreateEventListeners = + new IPostCollectionRecreateEventListener[] {}; + + private IPreCollectionRemoveEventListener[] preCollectionRemoveEventListeners = + new IPreCollectionRemoveEventListener[] {}; + + private IPostCollectionRemoveEventListener[] postCollectionRemoveEventListeners = + new IPostCollectionRemoveEventListener[] {}; + + private IPreCollectionUpdateEventListener[] preCollectionUpdateEventListeners = + new IPreCollectionUpdateEventListener[] {}; + + private IPostCollectionUpdateEventListener[] postCollectionUpdateEventListeners = + new IPostCollectionUpdateEventListener[] {}; + + private ISaveOrUpdateEventListener[] saveEventListeners = new ISaveOrUpdateEventListener[] + {new DefaultSaveEventListener()}; + + private ISaveOrUpdateEventListener[] updateEventListeners = new ISaveOrUpdateEventListener[] + {new DefaultUpdateEventListener()}; + + private IMergeEventListener[] saveOrUpdateCopyEventListeners = new IMergeEventListener[] + {new DefaultSaveOrUpdateCopyEventListener()}; + //saveOrUpdateCopy() is deprecated! + public ILoadEventListener[] LoadEventListeners { get { return loadEventListeners; } @@ -420,11 +477,85 @@ } } + public IPreCollectionRecreateEventListener[] PreCollectionRecreateEventListeners + { + get { return preCollectionRecreateEventListeners; } + set + { + if (value != null) + { + preCollectionRecreateEventListeners = value; + } + } + } + + public IPostCollectionRecreateEventListener[] PostCollectionRecreateEventListeners + { + get { return postCollectionRecreateEventListeners; } + set + { + if (value != null) + { + postCollectionRecreateEventListeners = value; + } + } + } + + public IPreCollectionRemoveEventListener[] PreCollectionRemoveEventListeners + { + get { return preCollectionRemoveEventListeners; } + set + { + if (value != null) + { + preCollectionRemoveEventListeners = value; + } + } + } + + public IPostCollectionRemoveEventListener[] PostCollectionRemoveEventListeners + { + get { return postCollectionRemoveEventListeners; } + set + { + if (value != null) + { + postCollectionRemoveEventListeners = value; + } + } + } + + public IPreCollectionUpdateEventListener[] PreCollectionUpdateEventListeners + { + get { return preCollectionUpdateEventListeners; } + set + { + if (value != null) + { + preCollectionUpdateEventListeners = value; + } + } + } + + public IPostCollectionUpdateEventListener[] PostCollectionUpdateEventListeners + { + get { return postCollectionUpdateEventListeners; } + set + { + if (value != null) + { + postCollectionUpdateEventListeners = value; + } + } + } + public System.Type GetListenerClassFor(ListenerType type) { System.Type result; if (!eventInterfaceFromType.TryGetValue(type, out result)) + { throw new MappingException("Unrecognized listener type [" + type + "]"); + } return result; } @@ -465,15 +596,24 @@ InitializeListeners(cfg, postCommitInsertEventListeners); InitializeListeners(cfg, saveEventListeners); InitializeListeners(cfg, updateEventListeners); + + InitializeListeners(cfg, preCollectionRecreateEventListeners); + InitializeListeners(cfg, postCollectionRecreateEventListeners); + InitializeListeners(cfg, preCollectionRemoveEventListeners); + InitializeListeners(cfg, postCollectionRemoveEventListeners); + InitializeListeners(cfg, preCollectionUpdateEventListeners); + InitializeListeners(cfg, postCollectionUpdateEventListeners); } - private void InitializeListeners(Configuration cfg, object[] list) + private void InitializeListeners(Configuration cfg, object[] list) { foreach (object i in list) { IInitializable initializable = i as IInitializable; if (initializable != null) + { initializable.Initialize(cfg); + } } } @@ -483,4 +623,4 @@ return this; } } -} +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Event/IPostCollectionRecreateEventListener.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/IPostCollectionRecreateEventListener.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Event/IPostCollectionRecreateEventListener.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -0,0 +1,8 @@ +namespace NHibernate.Event +{ + /// <summary> Called after recreating a collection </summary> + public interface IPostCollectionRecreateEventListener + { + void OnPostRecreateCollection(PostCollectionRecreateEvent @event); + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Event/IPostCollectionRemoveEventListener.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/IPostCollectionRemoveEventListener.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Event/IPostCollectionRemoveEventListener.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -0,0 +1,8 @@ +namespace NHibernate.Event +{ + /// <summary> Called after removing a collection </summary> + public interface IPostCollectionRemoveEventListener + { + void OnPostRemoveCollection(PostCollectionRemoveEvent @event); + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Event/IPostCollectionUpdateEventListener.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/IPostCollectionUpdateEventListener.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Event/IPostCollectionUpdateEventListener.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -0,0 +1,8 @@ +namespace NHibernate.Event +{ + /// <summary> Called after updating a collection </summary> + public interface IPostCollectionUpdateEventListener + { + void OnPostUpdateCollection(PostCollectionUpdateEvent @event); + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Event/IPreCollectionRecreateEventListener.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/IPreCollectionRecreateEventListener.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Event/IPreCollectionRecreateEventListener.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -0,0 +1,8 @@ +namespace NHibernate.Event +{ + /// <summary> Called before recreating a collection </summary> + public interface IPreCollectionRecreateEventListener + { + void OnPreRecreateCollection(PreCollectionRecreateEvent @event); + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Event/IPreCollectionRemoveEventListener.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/IPreCollectionRemoveEventListener.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Event/IPreCollectionRemoveEventListener.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -0,0 +1,8 @@ +namespace NHibernate.Event +{ + /// <summary> Called before removing a collection </summary> + public interface IPreCollectionRemoveEventListener + { + void OnPreRemoveCollection(PreCollectionRemoveEvent @event); + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Event/IPreCollectionUpdateEventListener.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/IPreCollectionUpdateEventListener.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Event/IPreCollectionUpdateEventListener.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -0,0 +1,8 @@ +namespace NHibernate.Event +{ + /// <summary> Called before updating a collection </summary> + public interface IPreCollectionUpdateEventListener + { + void OnPreUpdateCollection(PreCollectionUpdateEvent @event); + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Event/InitializeCollectionEvent.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/InitializeCollectionEvent.cs 2008-08-18 19:58:38 UTC (rev 3719) +++ trunk/nhibernate/src/NHibernate/Event/InitializeCollectionEvent.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -7,19 +7,11 @@ /// An event that occurs when a collection wants to be initialized /// </summary> [Serializable] - public class InitializeCollectionEvent : AbstractEvent + public class InitializeCollectionEvent : AbstractCollectionEvent { - private readonly IPersistentCollection collection; - public InitializeCollectionEvent(IPersistentCollection collection, IEventSource source) - : base(source) - { - this.collection = collection; - } - - public IPersistentCollection Collection - { - get { return collection; } - } + : base( + GetLoadedCollectionPersister(collection, source), collection, source, GetLoadedOwnerOrNull(collection, source), + GetLoadedOwnerIdOrNull(collection, source)) {} } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Event/ListenerType.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/ListenerType.cs 2008-08-18 19:58:38 UTC (rev 3719) +++ trunk/nhibernate/src/NHibernate/Event/ListenerType.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -3,10 +3,8 @@ /// <summary> /// Values for listener type property. /// </summary> - /// <remarks>Unused</remarks> public enum ListenerType { - // TODO:Implement listeners and events (remove de remarks from this enum) /// <summary>Not allowed in Xml. It represente de default value when an explicit type is assigned.</summary> NotValidType, /// <summary>Xml value: auto-flush</summary> @@ -51,6 +49,12 @@ PreDelete, /// <summary>Xml value: pre-insert</summary> PreInsert, + /// <summary>Xml value: pre-collection-recreate </summary> + PreCollectionRecreate, + /// <summary>Xml value: pre-collection-remove </summary> + PreCollectionRemove, + /// <summary>Xml value: pre-collection-update </summary> + PreCollectionUpdate, /// <summary>Xml value: post-load</summary> PostLoad, /// <summary>Xml value: post-insert</summary> @@ -64,6 +68,12 @@ /// <summary>Xml value: post-commit-insert</summary> PostCommitInsert, /// <summary>Xml value: post-commit-delete</summary> - PostCommitDelete + PostCommitDelete, + /// <summary>Xml value: post-collection-recreate </summary> + PostCollectionRecreate, + /// <summary>Xml value: post-collection-remove </summary> + PostCollectionRemove, + /// <summary>Xml value: post-collection-update </summary> + PostCollectionUpdate, } } Added: trunk/nhibernate/src/NHibernate/Event/PostCollectionRecreateEvent.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/PostCollectionRecreateEvent.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Event/PostCollectionRecreateEvent.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -0,0 +1,15 @@ +using System; +using NHibernate.Collection; +using NHibernate.Persister.Collection; + +namespace NHibernate.Event +{ + /// <summary> An event that occurs after a collection is recreated </summary> + [Serializable] + public class PostCollectionRecreateEvent : AbstractCollectionEvent + { + public PostCollectionRecreateEvent(ICollectionPersister collectionPersister, IPersistentCollection collection, + IEventSource source) + : base(collectionPersister, collection, source, collection.Owner, GetOwnerIdOrNull(collection.Owner, source)) {} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Event/PostCollectionRemoveEvent.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/PostCollectionRemoveEvent.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Event/PostCollectionRemoveEvent.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -0,0 +1,15 @@ +using System; +using NHibernate.Collection; +using NHibernate.Persister.Collection; + +namespace NHibernate.Event +{ + /// <summary> An event that occurs after a collection is removed </summary> + [Serializable] + public class PostCollectionRemoveEvent : AbstractCollectionEvent + { + public PostCollectionRemoveEvent(ICollectionPersister collectionPersister, IPersistentCollection collection, + IEventSource source, object loadedOwner) + : base(collectionPersister, collection, source, loadedOwner, GetOwnerIdOrNull(loadedOwner, source)) {} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Event/PostCollectionUpdateEvent.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/PostCollectionUpdateEvent.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Event/PostCollectionUpdateEvent.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -0,0 +1,17 @@ +using System; +using NHibernate.Collection; +using NHibernate.Persister.Collection; + +namespace NHibernate.Event +{ + /// <summary> An event that occurs after a collection is updated </summary> + [Serializable] + public class PostCollectionUpdateEvent : AbstractCollectionEvent + { + public PostCollectionUpdateEvent(ICollectionPersister collectionPersister, IPersistentCollection collection, + IEventSource source) + : base( + collectionPersister, collection, source, GetLoadedOwnerOrNull(collection, source), + GetLoadedOwnerIdOrNull(collection, source)) {} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Event/PreCollectionRecreateEvent.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/PreCollectionRecreateEvent.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Event/PreCollectionRecreateEvent.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -0,0 +1,15 @@ +using System; +using NHibernate.Collection; +using NHibernate.Persister.Collection; + +namespace NHibernate.Event +{ + /// <summary> An event that occurs before a collection is recreated </summary> + [Serializable] + public class PreCollectionRecreateEvent : AbstractCollectionEvent + { + public PreCollectionRecreateEvent(ICollectionPersister collectionPersister, IPersistentCollection collection, + IEventSource source) + : base(collectionPersister, collection, source, collection.Owner, GetOwnerIdOrNull(collection.Owner, source)) {} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Event/PreCollectionRemoveEvent.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/PreCollectionRemoveEvent.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Event/PreCollectionRemoveEvent.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -0,0 +1,15 @@ +using System; +using NHibernate.Collection; +using NHibernate.Persister.Collection; + +namespace NHibernate.Event +{ + /// <summary> An event that occurs before a collection is removed </summary> + [Serializable] + public class PreCollectionRemoveEvent : AbstractCollectionEvent + { + public PreCollectionRemoveEvent(ICollectionPersister collectionPersister, IPersistentCollection collection, + IEventSource source, object loadedOwner) + : base(collectionPersister, collection, source, loadedOwner, GetOwnerIdOrNull(loadedOwner, source)) {} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/Event/PreCollectionUpdateEvent.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/PreCollectionUpdateEvent.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Event/PreCollectionUpdateEvent.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -0,0 +1,17 @@ +using System; +using NHibernate.Collection; +using NHibernate.Persister.Collection; + +namespace NHibernate.Event +{ + /// <summary> An event that occurs before a collection is updated </summary> + [Serializable] + public class PreCollectionUpdateEvent : AbstractCollectionEvent + { + public PreCollectionUpdateEvent(ICollectionPersister collectionPersister, IPersistentCollection collection, + IEventSource source) + : base( + collectionPersister, collection, source, GetLoadedOwnerOrNull(collection, source), + GetLoadedOwnerIdOrNull(collection, source)) {} + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj 2008-08-18 19:58:38 UTC (rev 3719) +++ trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj 2008-08-19 13:23:30 UTC (rev 3720) @@ -638,6 +638,7 @@ <Compile Include="Engine\ValueInclusion.cs" /> <Compile Include="Engine\VersionValue.cs" /> <Compile Include="EntityMode.cs" /> + <Compile Include="Event\AbstractCollectionEvent.cs" /> <Compile Include="Event\AbstractEvent.cs" /> <Compile Include="Event\AutoFlushEvent.cs" /> <Compile Include="Event\Default\AbstractFlushingEventListener.cs" /> @@ -693,10 +694,16 @@ <Compile Include="Event\IMergeEventListener.cs" /> <Compile Include="Event\InitializeCollectionEvent.cs" /> <Compile Include="Event\IPersistEventListener.cs" /> + <Compile Include="Event\IPostCollectionRecreateEventListener.cs" /> + <Compile Include="Event\IPostCollectionRemoveEventListener.cs" /> + <Compile Include="Event\IPostCollectionUpdateEventListener.cs" /> <Compile Include="Event\IPostDeleteEventListener.cs" /> <Compile Include="Event\IPostInsertEventListener.cs" /> <Compile Include="Event\IPostLoadEventListener.cs" /> <Compile Include="Event\IPostUpdateEventListener.cs" /> + <Compile Include="Event\IPreCollectionRecreateEventListener.cs" /> + <Compile Include="Event\IPreCollectionRemoveEventListener.cs" /> + <Compile Include="Event\IPreCollectionUpdateEventListener.cs" /> <Compile Include="Event\IPreDeleteEventListener.cs" /> <Compile Include="Event\IPreInsertEventListener.cs" /> <Compile Include="Event\IPreLoadEventListener.cs" /> @@ -711,10 +718,16 @@ <Compile Include="Event\LockEvent.cs" /> <Compile Include="Event\MergeEvent.cs" /> <Compile Include="Event\PersistEvent.cs" /> + <Compile Include="Event\PostCollectionRecreateEvent.cs" /> + <Compile Include="Event\PostCollectionRemoveEvent.cs" /> + <Compile Include="Event\PostCollectionUpdateEvent.cs" /> <Compile Include="Event\PostDeleteEvent.cs" /> <Compile Include="Event\PostInsertEvent.cs" /> <Compile Include="Event\PostLoadEvent.cs" /> <Compile Include="Event\PostUpdateEvent.cs" /> + <Compile Include="Event\PreCollectionRecreateEvent.cs" /> + <Compile Include="Event\PreCollectionRemoveEvent.cs" /> + <Compile Include="Event\PreCollectionUpdateEvent.cs" /> <Compile Include="Event\PreDeleteEvent.cs" /> <Compile Include="Event\PreInsertEvent.cs" /> <Compile Include="Event\PreLoadEvent.cs" /> Modified: trunk/nhibernate/src/NHibernate/Type/CollectionType.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Type/CollectionType.cs 2008-08-18 19:58:38 UTC (rev 3719) +++ trunk/nhibernate/src/NHibernate/Type/CollectionType.cs 2008-08-19 13:23:30 UTC (rev 3720) @@ -502,6 +502,42 @@ } /// <summary> + /// Get the id value from the owning entity key, usually the same as the key, but might be some + /// other property, in the case of property-ref + /// </summary> + /// <param name="key">The collection owner key </param> + /// <param name="session">The session from which the request is originating. </param> + /// <returns> + /// The collection owner's id, if it can be obtained from the key; + /// otherwise, null is returned + /// </returns> + public virtual object GetIdOfOwnerOrNull(object key, ISessionImplementor session) + { + object ownerId = null; + if (foreignKeyPropertyName == null) + { + ownerId = key; + } + else + { + IType keyType = GetPersister(session).KeyType; + IEntityPersister ownerPersister = GetPersister(session).OwnerEntityPersister; + // TODO: Fix this so it will work for non-POJO entity mode + System.Type ownerMappedClass = ownerPersister.GetMappedClass(session.EntityMode); + if (ownerMappedClass.IsAssignableFrom(keyType.ReturnedClass) && keyType.ReturnedClass.IsInstanceOfType(key)) + { + // the key is the owning entity itself, so get the ID from the key + ownerId = ownerPersister.GetIdentifier(key, session.EntityMode); + } + else + { + // TODO: check if key contains the owner ID + } + } + return ownerId; + } + + /// <summary> /// Instantiate an empty instance of the "underlying" collection (not a wrapper), /// but with the given anticipated size (i.e. accounting for initial capacity /// and perhaps load factor). Modified: trunk/nhibernate/src/NHibernate/nhibernate-configuration.xsd =================================================================== --- trunk/nhibernate/src/NHibernate/nhibernate-configuration.xsd 2008-08-18 19:58:38 UTC (rev 3719) +++ trunk/nhibernate/src/NHibernate/nhibernate-configuration.xsd 2008-08-19 13:23:30 UTC (rev 3720) @@ -178,6 +178,12 @@ <xs:enumeration value="post-commit-update" /> <xs:enumeration value="post-commit-insert" /> <xs:enumeration value="post-commit-delete" /> + <xs:enumeration value="pre-collection-recreate" /> + <xs:enumeration value="pre-collection-remove" /> + <xs:enumeration value="pre-collection-update" /> + <xs:enumeration value="post-collection-recreate" /> + <xs:enumeration value="post-collection-remove" /> + <xs:enumeration value="post-collection-update" /> </xs:restriction> </xs:simpleType> <xs:element name="bytecode-provider"> Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-08-18 19:58:38 UTC (rev 3719) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-08-19 13:23:30 UTC (rev 3720) @@ -1440,6 +1440,7 @@ <EmbeddedResource Include="DynamicEntity\Tuplizer\Customer.hbm.xml" /> </ItemGroup> <ItemGroup> + <Folder Include="Events\" /> <Folder Include="Properties\" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2008-08-20 20:07:49
|
Revision: 3721 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3721&view=rev Author: fabiomaulo Date: 2008-08-20 20:07:55 +0000 (Wed, 20 Aug 2008) Log Message: ----------- End porting of new events for collections (need some "more" investigation of tests for ManyToMany) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Action/CollectionRecreateAction.cs trunk/nhibernate/src/NHibernate/Action/CollectionRemoveAction.cs trunk/nhibernate/src/NHibernate/Action/CollectionUpdateAction.cs trunk/nhibernate/src/NHibernate/Event/Default/ReattachVisitor.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/Events/Collections/ trunk/nhibernate/src/NHibernate.Test/Events/Collections/AbstractCollectionEventFixture.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/AbstractParentWithCollection.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/ trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/AbstractAssociationCollectionEventFixture.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/ trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/BidirectionalManyToManyBagToSetCollectionEventFixture.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/BidirectionalManyToManyBagToSetMapping.hbm.xml trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/BidirectionalManyToManySetToSetCollectionEventFixture.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/BidirectionalManyToManySetToSetMapping.hbm.xml trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/ChildWithBidirectionalManyToMany.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/ParentWithBidirectionalManyToMany.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/OneToMany/ trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/OneToMany/BidirectionalOneToManyBagCollectionEventFixture.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/OneToMany/BidirectionalOneToManyBagMapping.hbm.xml trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/OneToMany/BidirectionalOneToManyBagSubclassCollectionEventFixture.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/OneToMany/BidirectionalOneToManyBagSubclassMapping.hbm.xml trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/OneToMany/BidirectionalOneToManySetCollectionEventFixture.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/OneToMany/BidirectionalOneToManySetMapping.hbm.xml trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/OneToMany/ChildWithManyToOne.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/OneToMany/ParentWithBidirectionalOneToMany.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/OneToMany/ParentWithBidirectionalOneToManySubclass.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Unidirectional/ trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Unidirectional/ManyToMany/ trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Unidirectional/ManyToMany/UnidirectionalManyToManyBagCollectionEventFixture.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Unidirectional/ManyToMany/UnidirectionalManyToManyBagMapping.hbm.xml trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Unidirectional/OneToMany/ trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Unidirectional/OneToMany/UnidirectionalOneToManyBagCollectionEventFixture.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Unidirectional/OneToMany/UnidirectionalOneToManyBagMapping.hbm.xml trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Unidirectional/OneToMany/UnidirectionalOneToManySetCollectionEventFixture.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Unidirectional/OneToMany/UnidirectionalOneToManySetMapping.hbm.xml trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Unidirectional/ParentWithCollectionOfEntities.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/ChildEntity.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/ChildValue.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/CollectionListeners.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/IChild.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/IEntity.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/IParentWithCollection.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Values/ trunk/nhibernate/src/NHibernate.Test/Events/Collections/Values/ParentWithCollectionOfValues.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Values/ValuesBagCollectionEventFixture.cs trunk/nhibernate/src/NHibernate.Test/Events/Collections/Values/ValuesBagMapping.hbm.xml Modified: trunk/nhibernate/src/NHibernate/Action/CollectionRecreateAction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Action/CollectionRecreateAction.cs 2008-08-19 13:23:30 UTC (rev 3720) +++ trunk/nhibernate/src/NHibernate/Action/CollectionRecreateAction.cs 2008-08-20 20:07:55 UTC (rev 3721) @@ -1,6 +1,7 @@ using System; using NHibernate.Collection; using NHibernate.Engine; +using NHibernate.Event; using NHibernate.Persister.Collection; namespace NHibernate.Action @@ -16,16 +17,46 @@ { IPersistentCollection collection = Collection; + PreRecreate(); + Persister.Recreate(collection, Key, Session); Session.PersistenceContext.GetCollectionEntry(collection).AfterAction(collection); Evict(); + PostRecreate(); + if (Session.Factory.Statistics.IsStatisticsEnabled) { Session.Factory.StatisticsImplementor.RecreateCollection(Persister.Role); } } + + private void PreRecreate() + { + IPreCollectionRecreateEventListener[] preListeners = Session.Listeners.PreCollectionRecreateEventListeners; + if (preListeners.Length > 0) + { + PreCollectionRecreateEvent preEvent = new PreCollectionRecreateEvent(Persister, Collection, (IEventSource)Session); + for (int i = 0; i < preListeners.Length; i++) + { + preListeners[i].OnPreRecreateCollection(preEvent); + } + } + } + + private void PostRecreate() + { + IPostCollectionRecreateEventListener[] postListeners = Session.Listeners.PostCollectionRecreateEventListeners; + if (postListeners.Length > 0) + { + PostCollectionRecreateEvent postEvent = new PostCollectionRecreateEvent(Persister, Collection, (IEventSource)Session); + for (int i = 0; i < postListeners.Length; i++) + { + postListeners[i].OnPostRecreateCollection(postEvent); + } + } + } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Action/CollectionRemoveAction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Action/CollectionRemoveAction.cs 2008-08-19 13:23:30 UTC (rev 3720) +++ trunk/nhibernate/src/NHibernate/Action/CollectionRemoveAction.cs 2008-08-20 20:07:55 UTC (rev 3721) @@ -1,26 +1,67 @@ using System; using NHibernate.Collection; using NHibernate.Engine; +using NHibernate.Event; using NHibernate.Persister.Collection; namespace NHibernate.Action { [Serializable] - public sealed class CollectionRemoveAction : CollectionAction + public sealed class CollectionRemoveAction : CollectionAction { private readonly bool emptySnapshot; + private readonly object affectedOwner; - public CollectionRemoveAction(IPersistentCollection collection, ICollectionPersister persister, - object key, bool emptySnapshot, ISessionImplementor session) - : base(persister, collection, key, session) + /// <summary> + /// Removes a persistent collection from its loaded owner. + /// </summary> + /// <param name="collection">The collection to to remove; must be non-null </param> + /// <param name="persister"> The collection's persister </param> + /// <param name="id">The collection key </param> + /// <param name="emptySnapshot">Indicates if the snapshot is empty </param> + /// <param name="session">The session </param> + /// <remarks>Use this constructor when the collection is non-null.</remarks> + public CollectionRemoveAction(IPersistentCollection collection, ICollectionPersister persister, object id, + bool emptySnapshot, ISessionImplementor session) + : base(persister, collection, id, session) { + if (collection == null) + { + throw new AssertionFailure("collection == null"); + } + this.emptySnapshot = emptySnapshot; + affectedOwner = session.PersistenceContext.GetLoadedCollectionOwnerOrNull(collection); } + /// <summary> + /// Removes a persistent collection from a specified owner. + /// </summary> + /// <param name="affectedOwner">The collection's owner; must be non-null </param> + /// <param name="persister"> The collection's persister </param> + /// <param name="id">The collection key </param> + /// <param name="emptySnapshot">Indicates if the snapshot is empty </param> + /// <param name="session">The session </param> + /// <remarks> Use this constructor when the collection to be removed has not been loaded. </remarks> + public CollectionRemoveAction(object affectedOwner, ICollectionPersister persister, object id, bool emptySnapshot, + ISessionImplementor session) : base(persister, null, id, session) + { + if (affectedOwner == null) + { + throw new AssertionFailure("affectedOwner == null"); + } + this.emptySnapshot = emptySnapshot; + this.affectedOwner = affectedOwner; + } + public override void Execute() { + PreRemove(); + if (!emptySnapshot) + { Persister.Remove(Key, Session); + } IPersistentCollection collection = Collection; if (collection != null) @@ -30,15 +71,45 @@ Evict(); + PostRemove(); + if (Session.Factory.Statistics.IsStatisticsEnabled) { Session.Factory.StatisticsImplementor.RemoveCollection(Persister.Role); } } + private void PreRemove() + { + IPreCollectionRemoveEventListener[] preListeners = Session.Listeners.PreCollectionRemoveEventListeners; + if (preListeners.Length > 0) + { + PreCollectionRemoveEvent preEvent = new PreCollectionRemoveEvent(Persister, Collection, (IEventSource) Session, + affectedOwner); + for (int i = 0; i < preListeners.Length; i++) + { + preListeners[i].OnPreRemoveCollection(preEvent); + } + } + } + + private void PostRemove() + { + IPostCollectionRemoveEventListener[] postListeners = Session.Listeners.PostCollectionRemoveEventListeners; + if (postListeners.Length > 0) + { + PostCollectionRemoveEvent postEvent = new PostCollectionRemoveEvent(Persister, Collection, (IEventSource) Session, + affectedOwner); + for (int i = 0; i < postListeners.Length; i++) + { + postListeners[i].OnPostRemoveCollection(postEvent); + } + } + } + public override int CompareTo(CollectionAction other) { return 0; } } -} +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Action/CollectionUpdateAction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Action/CollectionUpdateAction.cs 2008-08-19 13:23:30 UTC (rev 3720) +++ trunk/nhibernate/src/NHibernate/Action/CollectionUpdateAction.cs 2008-08-20 20:07:55 UTC (rev 3721) @@ -3,6 +3,7 @@ using NHibernate.Cache.Entry; using NHibernate.Collection; using NHibernate.Engine; +using NHibernate.Event; using NHibernate.Impl; using NHibernate.Persister.Collection; @@ -28,6 +29,8 @@ IPersistentCollection collection = Collection; bool affectedByFilters = persister.IsAffectedByEnabledFilters(session); + PreUpdate(); + if (!collection.WasInitialized) { if (!collection.HasQueuedOperations) @@ -67,12 +70,40 @@ Evict(); + PostUpdate(); + if (Session.Factory.Statistics.IsStatisticsEnabled) { Session.Factory.StatisticsImplementor.UpdateCollection(Persister.Role); } } + private void PreUpdate() + { + IPreCollectionUpdateEventListener[] preListeners = Session.Listeners.PreCollectionUpdateEventListeners; + if (preListeners.Length > 0) + { + PreCollectionUpdateEvent preEvent = new PreCollectionUpdateEvent(Persister, Collection, (IEventSource)Session); + for (int i = 0; i < preListeners.Length; i++) + { + preListeners[i].OnPreUpdateCollection(preEvent); + } + } + } + + private void PostUpdate() + { + IPostCollectionUpdateEventListener[] postListeners = Session.Listeners.PostCollectionUpdateEventListeners; + if (postListeners.Length > 0) + { + PostCollectionUpdateEvent postEvent = new PostCollectionUpdateEvent(Persister, Collection, (IEventSource)Session); + for (int i = 0; i < postListeners.Length; i++) + { + postListeners[i].OnPostUpdateCollection(postEvent); + } + } + } + public override void AfterTransactionCompletion(bool success) { // NH Different behavior: to support unlocking collections from the cache.(r3260) Modified: trunk/nhibernate/src/NHibernate/Event/Default/ReattachVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/Default/ReattachVisitor.cs 2008-08-19 13:23:30 UTC (rev 3720) +++ trunk/nhibernate/src/NHibernate/Event/Default/ReattachVisitor.cs 2008-08-20 20:07:55 UTC (rev 3721) @@ -15,7 +15,7 @@ private readonly object owner; private static readonly ILog log = LogManager.GetLogger(typeof(AbstractFlushingEventListener)); - public ReattachVisitor(IEventSource session, object ownerIdentifier, object owner) + protected ReattachVisitor(IEventSource session, object ownerIdentifier, object owner) : base(session) { this.ownerIdentifier = ownerIdentifier; @@ -60,7 +60,7 @@ log.Debug("collection dereferenced while transient " + MessageHelper.InfoString(role, ownerIdentifier, source.Factory)); } - source.ActionQueue.AddAction(new CollectionRemoveAction(null, role, collectionKey, false, source)); + source.ActionQueue.AddAction(new CollectionRemoveAction(owner, role, collectionKey, false, source)); } /// <summary> Added: trunk/nhibernate/src/NHibernate.Test/Events/Collections/AbstractCollectionEventFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Events/Collections/AbstractCollectionEventFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Events/Collections/AbstractCollectionEventFixture.cs 2008-08-20 20:07:55 UTC (rev 3721) @@ -0,0 +1,907 @@ +using System.Collections; +using System.Collections.Generic; +using NHibernate.Collection; +using NHibernate.Event; +using NHibernate.Test.Events.Collections.Association.Bidirectional.ManyToMany; +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; + +namespace NHibernate.Test.Events.Collections +{ + public abstract class AbstractCollectionEventFixture : TestCase + { + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + public abstract IParentWithCollection CreateParent(string name); + + public abstract ICollection<IChild> CreateCollection(); + + protected override void OnTearDown() + { + IParentWithCollection dummyParent = CreateParent("dummyParent"); + dummyParent.NewChildren(CreateCollection()); + IChild dummyChild = dummyParent.AddChild("dummyChild"); + + using (ISession s = OpenSession()) + { + using (ITransaction tx = s.BeginTransaction()) + { + IList children = s.CreateCriteria(dummyChild.GetType()).List(); + IList parents = s.CreateCriteria(dummyParent.GetType()).List(); + foreach (IParentWithCollection parent in parents) + { + parent.ClearChildren(); + s.Delete(parent); + } + foreach (IChild child in children) + { + s.Delete(child); + } + + tx.Commit(); + } + } + base.OnTearDown(); + } + + [Test] + public void SaveParentEmptyChildren() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithNoChildren("parent"); + Assert.That(parent.Children.Count, Is.EqualTo(0)); + int index = 0; + CheckResult(listeners, listeners.PreCollectionRecreate, parent, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, parent, index++); + CheckNumberOfResults(listeners, index); + listeners.Clear(); + using (ISession s = OpenSession()) + { + using (ITransaction tx = s.BeginTransaction()) + { + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + tx.Commit(); + } + } + Assert.That(parent.Children, Is.Not.Null); + CheckNumberOfResults(listeners, 0); + } + + [Test] + public virtual void SaveParentOneChild() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + int index = 0; + CheckResult(listeners, listeners.PreCollectionRecreate, parent, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, parent, index++); + ChildWithBidirectionalManyToMany child = GetFirstChild(parent.Children) as ChildWithBidirectionalManyToMany; + if (child != null) + { + CheckResult(listeners, listeners.PreCollectionRecreate, child, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, child, index++); + } + + CheckNumberOfResults(listeners, index); + } + + [Test] + public void UpdateParentNullToOneChild() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithNullChildren("parent"); + listeners.Clear(); + Assert.That(parent.Children, Is.Null); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + Assert.That(parent.Children, Is.Not.Null); + ChildWithBidirectionalManyToMany newChild = parent.AddChild("new") as ChildWithBidirectionalManyToMany; + tx.Commit(); + s.Close(); + int index = 0; + if (((IPersistentCollection) parent.Children).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, parent, index++); + } + CheckResult(listeners, listeners.PreCollectionUpdate, parent, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, parent, index++); + if (newChild != null) + { + CheckResult(listeners, listeners.PreCollectionRecreate, newChild, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, newChild, index++); + } + + CheckNumberOfResults(listeners, index); + } + + [Test] + public void UpdateParentNoneToOneChild() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithNoChildren("parent"); + listeners.Clear(); + Assert.That(parent.Children.Count, Is.EqualTo(0)); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + ChildWithBidirectionalManyToMany newChild = parent.AddChild("new") as ChildWithBidirectionalManyToMany; + tx.Commit(); + s.Close(); + int index = 0; + if (((IPersistentCollection) parent.Children).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, parent, index++); + } + CheckResult(listeners, listeners.PreCollectionUpdate, parent, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, parent, index++); + if (newChild != null) + { + CheckResult(listeners, listeners.PreCollectionRecreate, newChild, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, newChild, index++); + } + + CheckNumberOfResults(listeners, index); + } + + [Test] + public void UpdateParentOneToTwoChildren() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + Assert.That(parent.Children.Count, Is.EqualTo(1)); + listeners.Clear(); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + ChildWithBidirectionalManyToMany newChild = parent.AddChild("new2") as ChildWithBidirectionalManyToMany; + tx.Commit(); + s.Close(); + int index = 0; + if (((IPersistentCollection) parent.Children).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, parent, index++); + } + CheckResult(listeners, listeners.PreCollectionUpdate, parent, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, parent, index++); + if (newChild != null) + { + CheckResult(listeners, listeners.PreCollectionRecreate, newChild, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, newChild, index++); + } + + CheckNumberOfResults(listeners, index); + } + + [Test] + public void UpdateParentOneToTwoSameChildren() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + IChild child = GetFirstChild(parent.Children); + Assert.That(parent.Children.Count, Is.EqualTo(1)); + listeners.Clear(); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + IEntity e = child as IEntity; + if (e != null) + { + child = (IChild) s.Get(child.GetType(), e.Id); + } + parent.AddChild(child); + tx.Commit(); + s.Close(); + int index = 0; + if (((IPersistentCollection) parent.Children).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, parent, index++); + } + ChildWithBidirectionalManyToMany childWithManyToMany = child as ChildWithBidirectionalManyToMany; + if (childWithManyToMany != null) + { + if (((IPersistentCollection) childWithManyToMany.Parents).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, childWithManyToMany, index++); + } + } + + if (!(parent.Children is PersistentSet)) + { + CheckResult(listeners, listeners.PreCollectionUpdate, parent, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, parent, index++); + } + if (childWithManyToMany != null && !(childWithManyToMany.Parents is PersistentSet)) + { + CheckResult(listeners, listeners.PreCollectionUpdate, childWithManyToMany, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, childWithManyToMany, index++); + } + + CheckNumberOfResults(listeners, index); + } + + [Test] + public void UpdateParentNullToOneChildDiffCollection() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithNullChildren("parent"); + listeners.Clear(); + Assert.That(parent.Children, Is.Null); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + ICollection<IChild> collectionOrig = parent.Children; + parent.NewChildren(CreateCollection()); + ChildWithBidirectionalManyToMany newChild = parent.AddChild("new") as ChildWithBidirectionalManyToMany; + tx.Commit(); + s.Close(); + int index = 0; + if (((IPersistentCollection) collectionOrig).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, parent, collectionOrig, index++); + } + CheckResult(listeners, listeners.PreCollectionRemove, parent, collectionOrig, index++); + CheckResult(listeners, listeners.PostCollectionRemove, parent, collectionOrig, index++); + if (newChild != null) + { + CheckResult(listeners, listeners.PreCollectionRecreate, newChild, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, newChild, index++); + } + CheckResult(listeners, listeners.PreCollectionRecreate, parent, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, parent, index++); + CheckNumberOfResults(listeners, index); + } + + [Test] + public void UpdateParentNoneToOneChildDiffCollection() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithNoChildren("parent"); + listeners.Clear(); + Assert.That(parent.Children.Count, Is.EqualTo(0)); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + ICollection<IChild> oldCollection = parent.Children; + parent.NewChildren(CreateCollection()); + ChildWithBidirectionalManyToMany newChild = parent.AddChild("new") as ChildWithBidirectionalManyToMany; + tx.Commit(); + s.Close(); + int index = 0; + if (((IPersistentCollection) oldCollection).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, parent, oldCollection, index++); + } + CheckResult(listeners, listeners.PreCollectionRemove, parent, oldCollection, index++); + CheckResult(listeners, listeners.PostCollectionRemove, parent, oldCollection, index++); + if (newChild != null) + { + CheckResult(listeners, listeners.PreCollectionRecreate, newChild, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, newChild, index++); + } + + CheckResult(listeners, listeners.PreCollectionRecreate, parent, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, parent, index++); + CheckNumberOfResults(listeners, index); + } + + [Test] + public void UpdateParentOneChildDiffCollectionSameChild() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + IChild child = GetFirstChild(parent.Children); + listeners.Clear(); + Assert.That(parent.Children.Count, Is.EqualTo(1)); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + IEntity e = child as IEntity; + if (e != null) + { + child = (IChild) s.Get(child.GetType(), e.Id); + } + ICollection<IChild> oldCollection = parent.Children; + parent.NewChildren(CreateCollection()); + parent.AddChild(child); + tx.Commit(); + s.Close(); + int index = 0; + if (((IPersistentCollection) oldCollection).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, parent, oldCollection, index++); + } + ChildWithBidirectionalManyToMany childWithManyToMany = child as ChildWithBidirectionalManyToMany; + if (childWithManyToMany != null) + { + if (((IPersistentCollection) childWithManyToMany.Parents).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, childWithManyToMany, index++); + } + } + + CheckResult(listeners, listeners.PreCollectionRemove, parent, oldCollection, index++); + CheckResult(listeners, listeners.PostCollectionRemove, parent, oldCollection, index++); + if (childWithManyToMany != null) + { + // hmmm, the same parent was removed and re-added to the child's collection; + // should this be considered an update? + CheckResult(listeners, listeners.PreCollectionUpdate, childWithManyToMany, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, childWithManyToMany, index++); + } + CheckResult(listeners, listeners.PreCollectionRecreate, parent, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, parent, index++); + CheckNumberOfResults(listeners, index); + } + + [Test] + public void UpdateParentOneChildDiffCollectionDiffChild() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + IChild oldChild = GetFirstChild(parent.Children); + listeners.Clear(); + Assert.That(parent.Children.Count, Is.EqualTo(1)); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + IEntity e = oldChild as IEntity; + ChildWithBidirectionalManyToMany oldChildWithManyToMany = null; + if (e != null) + { + oldChildWithManyToMany = s.Get(oldChild.GetType(), e.Id) as ChildWithBidirectionalManyToMany; + } + ICollection<IChild> oldCollection = parent.Children; + parent.NewChildren(CreateCollection()); + IChild newChild = parent.AddChild("new1"); + tx.Commit(); + s.Close(); + int index = 0; + if (((IPersistentCollection) oldCollection).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, parent, oldCollection, index++); + } + if (oldChildWithManyToMany != null) + { + if (((IPersistentCollection) oldChildWithManyToMany.Parents).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, oldChildWithManyToMany, index++); + } + } + CheckResult(listeners, listeners.PreCollectionRemove, parent, oldCollection, index++); + CheckResult(listeners, listeners.PostCollectionRemove, parent, oldCollection, index++); + if (oldChildWithManyToMany != null) + { + CheckResult(listeners, listeners.PreCollectionUpdate, oldChildWithManyToMany, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, oldChildWithManyToMany, index++); + CheckResult(listeners, listeners.PreCollectionRecreate, (ChildWithBidirectionalManyToMany) newChild, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, (ChildWithBidirectionalManyToMany) newChild, index++); + } + CheckResult(listeners, listeners.PreCollectionRecreate, parent, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, parent, index++); + CheckNumberOfResults(listeners, index); + } + + [Test] + public void UpdateParentOneChildToNoneByRemove() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + Assert.That(parent.Children.Count, Is.EqualTo(1)); + IChild child = GetFirstChild(parent.Children); + listeners.Clear(); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + IEntity e = child as IEntity; + + if (e != null) + { + child = (IChild) s.Get(child.GetType(), e.Id); + } + parent.RemoveChild(child); + tx.Commit(); + s.Close(); + int index = 0; + if (((IPersistentCollection) parent.Children).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, parent, index++); + } + ChildWithBidirectionalManyToMany childWithManyToMany = child as ChildWithBidirectionalManyToMany; + if (childWithManyToMany != null) + { + if (((IPersistentCollection) childWithManyToMany.Parents).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, childWithManyToMany, index++); + } + } + CheckResult(listeners, listeners.PreCollectionUpdate, parent, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, parent, index++); + if (childWithManyToMany != null) + { + CheckResult(listeners, listeners.PreCollectionUpdate, childWithManyToMany, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, childWithManyToMany, index++); + } + CheckNumberOfResults(listeners, index); + } + + [Test] + public void UpdateParentOneChildToNoneByClear() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + Assert.That(parent.Children.Count, Is.EqualTo(1)); + IChild child = GetFirstChild(parent.Children); + listeners.Clear(); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + IEntity e = child as IEntity; + if (e != null) + { + child = (IChild) s.Get(child.GetType(), e.Id); + } + parent.ClearChildren(); + tx.Commit(); + s.Close(); + int index = 0; + if (((IPersistentCollection) parent.Children).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, parent, index++); + } + ChildWithBidirectionalManyToMany childWithManyToMany = child as ChildWithBidirectionalManyToMany; + if (childWithManyToMany != null) + { + if (((IPersistentCollection) childWithManyToMany.Parents).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, childWithManyToMany, index++); + } + } + CheckResult(listeners, listeners.PreCollectionUpdate, parent, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, parent, index++); + if (childWithManyToMany != null) + { + CheckResult(listeners, listeners.PreCollectionUpdate, childWithManyToMany, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, childWithManyToMany, index++); + } + CheckNumberOfResults(listeners, index); + } + + [Test] + public void UpdateParentTwoChildrenToOne() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + Assert.That(parent.Children.Count, Is.EqualTo(1)); + IChild oldChild = GetFirstChild(parent.Children); + listeners.Clear(); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + parent.AddChild("new"); + tx.Commit(); + s.Close(); + listeners.Clear(); + s = OpenSession(); + tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + IEntity e = oldChild as IEntity; + if (e != null) + { + oldChild = (IChild) s.Get(oldChild.GetType(), e.Id); + } + + parent.RemoveChild(oldChild); + tx.Commit(); + s.Close(); + int index = 0; + if (((IPersistentCollection) parent.Children).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, parent, index++); + } + ChildWithBidirectionalManyToMany oldChildWithManyToMany = oldChild as ChildWithBidirectionalManyToMany; + if (oldChildWithManyToMany != null) + { + if (((IPersistentCollection) oldChildWithManyToMany.Parents).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, oldChildWithManyToMany, index++); + } + } + + CheckResult(listeners, listeners.PreCollectionUpdate, parent, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, parent, index++); + if (oldChildWithManyToMany != null) + { + CheckResult(listeners, listeners.PreCollectionUpdate, oldChildWithManyToMany, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, oldChildWithManyToMany, index++); + } + CheckNumberOfResults(listeners, index); + } + + [Test] + public void DeleteParentWithNullChildren() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithNullChildren("parent"); + listeners.Clear(); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + s.Delete(parent); + tx.Commit(); + s.Close(); + int index = 0; + CheckResult(listeners, listeners.InitializeCollection, parent, index++); + CheckResult(listeners, listeners.PreCollectionRemove, parent, index++); + CheckResult(listeners, listeners.PostCollectionRemove, parent, index++); + CheckNumberOfResults(listeners, index); + } + + [Test] + public void DeleteParentWithNoChildren() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithNoChildren("parent"); + listeners.Clear(); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + s.Delete(parent); + tx.Commit(); + s.Close(); + + int index = 0; + CheckResult(listeners, listeners.InitializeCollection, parent, index++); + CheckResult(listeners, listeners.PreCollectionRemove, parent, index++); + CheckResult(listeners, listeners.PostCollectionRemove, parent, index++); + CheckNumberOfResults(listeners, index); + } + + [Test] + public void DeleteParentAndChild() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + IChild child = GetFirstChild(parent.Children); + listeners.Clear(); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + IEntity e = child as IEntity; + if (e != null) + { + child = (IChild) s.Get(child.GetType(), e.Id); + } + parent.RemoveChild(child); + if (e != null) + { + s.Delete(child); + } + s.Delete(parent); + tx.Commit(); + s.Close(); + int index = 0; + CheckResult(listeners, listeners.InitializeCollection, parent, index++); + ChildWithBidirectionalManyToMany childWithManyToMany = child as ChildWithBidirectionalManyToMany; + if (childWithManyToMany != null) + { + CheckResult(listeners, listeners.InitializeCollection, childWithManyToMany, index++); + } + CheckResult(listeners, listeners.PreCollectionRemove, parent, index++); + CheckResult(listeners, listeners.PostCollectionRemove, parent, index++); + if (childWithManyToMany != null) + { + CheckResult(listeners, listeners.PreCollectionRemove, childWithManyToMany, index++); + CheckResult(listeners, listeners.PostCollectionRemove, childWithManyToMany, index++); + } + CheckNumberOfResults(listeners, index); + } + + [Test] + public void MoveChildToDifferentParent() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + IParentWithCollection otherParent = CreateParentWithOneChild("otherParent", "otherChild"); + IChild child = GetFirstChild(parent.Children); + listeners.Clear(); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + otherParent = (IParentWithCollection) s.Get(otherParent.GetType(), otherParent.Id); + IEntity e = child as IEntity; + if (e != null) + { + child = (IChild) s.Get(child.GetType(), e.Id); + } + parent.RemoveChild(child); + otherParent.AddChild(child); + tx.Commit(); + s.Close(); + int index = 0; + if (((IPersistentCollection) parent.Children).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, parent, index++); + } + ChildWithBidirectionalManyToMany childWithManyToMany = child as ChildWithBidirectionalManyToMany; + if (childWithManyToMany != null) + { + CheckResult(listeners, listeners.InitializeCollection, childWithManyToMany, index++); + } + if (((IPersistentCollection) otherParent.Children).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, otherParent, index++); + } + CheckResult(listeners, listeners.PreCollectionUpdate, parent, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, parent, index++); + CheckResult(listeners, listeners.PreCollectionUpdate, otherParent, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, otherParent, index++); + if (childWithManyToMany != null) + { + CheckResult(listeners, listeners.PreCollectionUpdate, childWithManyToMany, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, childWithManyToMany, index++); + } + CheckNumberOfResults(listeners, index); + } + + [Test] + public void MoveAllChildrenToDifferentParent() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + IParentWithCollection otherParent = CreateParentWithOneChild("otherParent", "otherChild"); + IChild child = GetFirstChild(parent.Children); + listeners.Clear(); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + otherParent = (IParentWithCollection) s.Get(otherParent.GetType(), otherParent.Id); + IEntity e = child as IEntity; + if (e != null) + { + child = (IChild) s.Get(child.GetType(), e.Id); + } + otherParent.AddAllChildren(parent.Children); + parent.ClearChildren(); + tx.Commit(); + s.Close(); + int index = 0; + if (((IPersistentCollection) parent.Children).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, parent, index++); + } + if (((IPersistentCollection) otherParent.Children).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, otherParent, index++); + } + ChildWithBidirectionalManyToMany childWithManyToMany = child as ChildWithBidirectionalManyToMany; + if (childWithManyToMany != null) + { + CheckResult(listeners, listeners.InitializeCollection, childWithManyToMany, index++); + } + CheckResult(listeners, listeners.PreCollectionUpdate, parent, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, parent, index++); + CheckResult(listeners, listeners.PreCollectionUpdate, otherParent, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, otherParent, index++); + if (childWithManyToMany != null) + { + CheckResult(listeners, listeners.PreCollectionUpdate, childWithManyToMany, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, childWithManyToMany, index++); + } + CheckNumberOfResults(listeners, index); + } + + [Test] + public void MoveCollectionToDifferentParent() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + IParentWithCollection otherParent = CreateParentWithOneChild("otherParent", "otherChild"); + listeners.Clear(); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + otherParent = (IParentWithCollection) s.Get(otherParent.GetType(), otherParent.Id); + ICollection<IChild> otherCollectionOrig = otherParent.Children; + otherParent.NewChildren(parent.Children); + parent.NewChildren(null); + tx.Commit(); + s.Close(); + int index = 0; + ChildWithBidirectionalManyToMany otherChildOrig = null; + if (((IPersistentCollection) otherCollectionOrig).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, otherParent, otherCollectionOrig, index++); + otherChildOrig = GetFirstChild(otherCollectionOrig) as ChildWithBidirectionalManyToMany; + if (otherChildOrig != null) + { + CheckResult(listeners, listeners.InitializeCollection, otherChildOrig, index++); + } + } + CheckResult(listeners, listeners.InitializeCollection, parent, otherParent.Children, index++); + ChildWithBidirectionalManyToMany otherChild = GetFirstChild(otherParent.Children) as ChildWithBidirectionalManyToMany; + if (otherChild != null) + { + CheckResult(listeners, listeners.InitializeCollection, otherChild, index++); + } + CheckResult(listeners, listeners.PreCollectionRemove, parent, otherParent.Children, index++); + CheckResult(listeners, listeners.PostCollectionRemove, parent, otherParent.Children, index++); + CheckResult(listeners, listeners.PreCollectionRemove, otherParent, otherCollectionOrig, index++); + CheckResult(listeners, listeners.PostCollectionRemove, otherParent, otherCollectionOrig, index++); + if (otherChild != null) + { + CheckResult(listeners, listeners.PreCollectionUpdate, otherChildOrig, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, otherChildOrig, index++); + CheckResult(listeners, listeners.PreCollectionUpdate, otherChild, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, otherChild, index++); + } + CheckResult(listeners, listeners.PreCollectionRecreate, otherParent, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, otherParent, index++); + // there should also be pre- and post-recreate collection events for parent, but thats broken now; + // this is covered in BrokenCollectionEventTest + CheckNumberOfResults(listeners, index); + } + + [Test] + public void MoveCollectionToDifferentParentFlushMoveToDifferentParent() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + IParentWithCollection otherParent = CreateParentWithOneChild("otherParent", "otherChild"); + IParentWithCollection otherOtherParent = CreateParentWithNoChildren("otherParent"); + listeners.Clear(); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + otherParent = (IParentWithCollection) s.Get(otherParent.GetType(), otherParent.Id); + otherOtherParent = (IParentWithCollection) s.Get(otherOtherParent.GetType(), otherOtherParent.Id); + ICollection<IChild> otherCollectionOrig = otherParent.Children; + ICollection<IChild> otherOtherCollectionOrig = otherOtherParent.Children; + otherParent.NewChildren(parent.Children); + parent.NewChildren(null); + s.Flush(); + otherOtherParent.NewChildren(otherParent.Children); + otherParent.NewChildren(null); + tx.Commit(); + s.Close(); + int index = 0; + ChildWithBidirectionalManyToMany otherChildOrig = null; + if (((IPersistentCollection) otherCollectionOrig).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, otherParent, otherCollectionOrig, index++); + otherChildOrig = GetFirstChild(otherCollectionOrig) as ChildWithBidirectionalManyToMany; + if (otherChildOrig != null) + { + CheckResult(listeners, listeners.InitializeCollection, otherChildOrig, index++); + } + } + CheckResult(listeners, listeners.InitializeCollection, parent, otherOtherParent.Children, index++); + ChildWithBidirectionalManyToMany otherOtherChild = + GetFirstChild(otherOtherParent.Children) as ChildWithBidirectionalManyToMany; + if (otherOtherChild != null) + { + CheckResult(listeners, listeners.InitializeCollection, otherOtherChild, index++); + } + CheckResult(listeners, listeners.PreCollectionRemove, parent, otherOtherParent.Children, index++); + CheckResult(listeners, listeners.PostCollectionRemove, parent, otherOtherParent.Children, index++); + CheckResult(listeners, listeners.PreCollectionRemove, otherParent, otherCollectionOrig, index++); + CheckResult(listeners, listeners.PostCollectionRemove, otherParent, otherCollectionOrig, index++); + if (otherOtherChild != null) + { + CheckResult(listeners, listeners.PreCollectionUpdate, otherChildOrig, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, otherChildOrig, index++); + CheckResult(listeners, listeners.PreCollectionUpdate, otherOtherChild, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, otherOtherChild, index++); + } + CheckResult(listeners, listeners.PreCollectionRecreate, otherParent, otherOtherParent.Children, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, otherParent, otherOtherParent.Children, index++); + if (((IPersistentCollection) otherOtherCollectionOrig).WasInitialized) + { + CheckResult(listeners, listeners.InitializeCollection, otherOtherParent, otherOtherCollectionOrig, index++); + } + CheckResult(listeners, listeners.PreCollectionRemove, otherParent, otherOtherParent.Children, index++); + CheckResult(listeners, listeners.PostCollectionRemove, otherParent, otherOtherParent.Children, index++); + CheckResult(listeners, listeners.PreCollectionRemove, otherOtherParent, otherOtherCollectionOrig, index++); + CheckResult(listeners, listeners.PostCollectionRemove, otherOtherParent, otherOtherCollectionOrig, index++); + if (otherOtherChild != null) + { + CheckResult(listeners, listeners.PreCollectionUpdate, otherOtherChild, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, otherOtherChild, index++); + } + + CheckResult(listeners, listeners.PreCollectionRecreate, otherOtherParent, index++); + CheckResult(listeners, listeners.PostCollectionRecreate, otherOtherParent, index++); + // there should also be pre- and post-recreate collection events for parent, and otherParent + // but thats broken now; this is covered in BrokenCollectionEventTest + CheckNumberOfResults(listeners, index); + } + + protected IChild GetFirstChild(ICollection<IChild> children) + { + IChild result = null; + IEnumerator<IChild> en = children.GetEnumerator(); + if (en.MoveNext()) + { + result = en.Current; + } + return result; + } + + protected IParentWithCollection CreateParentWithNullChildren(string parentName) + { + using (ISession s = OpenSession()) + { + using (ITransaction tx = s.BeginTransaction()) + { + IParentWithCollection parent = CreateParent(parentName); + s.Save(parent); + tx.Commit(); + return parent; + } + } + } + + protected IParentWithCollection CreateParentWithNoChildren(string parentName) + { + using (ISession s = OpenSession()) + { + using (ITransaction tx = s.BeginTransaction()) + { + IParentWithCollection parent = CreateParent(parentName); + parent.NewChildren(CreateCollection()); + s.Save(parent); + tx.Commit(); + return parent; + } + } + } + + protected IParentWithCollection CreateParentWithOneChild(string parentName, string ChildName) + { + using (ISession s = OpenSession()) + { + using (ITransaction tx = s.BeginTransaction()) + { + IParentWithCollection parent = CreateParent(parentName); + parent.NewChildren(CreateCollection()); + parent.AddChild(ChildName); + s.Save(parent); + tx.Commit(); + return parent; + } + } + } + + protected void CheckResult(CollectionListeners listeners, CollectionListeners.IListener listenerExpected, + IParentWithCollection parent, int index) + { + CheckResult(listeners, listenerExpected, parent, parent.Children, index); + } + + protected void CheckResult(CollectionListeners listeners, CollectionListeners.IListener listenerExpected, + IEntity ownerExpected, object collExpected, int index) + { + Assert.That(listeners.ListenersCalled[index], Is.SameAs(listenerExpected)); + Assert.That(((AbstractCollectionEvent) listeners.Events[index]).AffectedOwnerOrNull, Is.SameAs(ownerExpected)); + Assert.That(((AbstractCollectionEvent) listeners.Events[index]).AffectedOwnerIdOrNull, Is.EqualTo(ownerExpected.Id)); + Assert.That(((AbstractCollectionEvent) listeners.Events[index]).GetAffectedOwnerEntityName(), + Is.EqualTo(ownerExpected.GetType().FullName)); + Assert.That(((AbstractCollectionEvent) listeners.Events[index]).Collection, Is.SameAs(collExpected)); + } + + protected void CheckNumberOfResults(CollectionListeners listeners, int nEventsExpected) + { + Assert.That(listeners.ListenersCalled.Count, Is.EqualTo(nEventsExpected)); + Assert.That(listeners.Events.Count, Is.EqualTo(nEventsExpected)); + } + + protected void CheckResult(CollectionListeners listeners, CollectionListeners.IListener listenerExpected, + ChildWithBidirectionalManyToMany child, int index) + { + CheckResult(listeners, listenerExpected, child, child.Parents, index); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Events/Collections/AbstractParentWithCollection.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Events/Collections/AbstractParentWithCollection.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Events/Collections/AbstractParentWithCollection.cs 2008-08-20 20:07:55 UTC (rev 3721) @@ -0,0 +1,90 @@ +using System.Collections.Generic; + +namespace NHibernate.Test.Events.Collections +{ + public abstract class AbstractParentWithCollection : IParentWithCollection + { + private ICollection<IChild> children; + private long id; + private string name; + protected AbstractParentWithCollection() {} + + protected AbstractParentWithCollection(string name) + { + this.name = name; + } + + #region IParentWithCollection Members + + public virtual long Id + { + get { return id; } + set { id = value; } + } + + public virtual void NewChildren(ICollection<IChild> collection) + { + Children = collection; + } + + public abstract IChild CreateChild(string name); + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual ICollection<IChild> Children + { + get { return children; } + set { children = value; } + } + + public virtual IChild AddChild(string childName) + { + IChild c = CreateChild(childName); + AddChild(c); + return c; + } + + public virtual void AddChild(IChild child) + { + if (child != null) + { + children.Add(child); + } + } + + public virtual void AddAllChildren(ICollection<IChild> children) + { + foreach (IChild child in children) + { + this.children.Add(child); + } + } + + public virtual void RemoveChild(IChild child) + { + children.Remove(child); + } + + public virtual void RemoveAllChildren(ICollection<IChild> children) + { + foreach (IChild child in children) + { + this.children.Remove(child); + } + } + + public virtual void ClearChildren() + { + if (children != null) + { + children.Clear(); + } + } + + #endregion + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/AbstractAssociationCollectionEventFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/AbstractAssociationCollectionEventFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/AbstractAssociationCollectionEventFixture.cs 2008-08-20 20:07:55 UTC (rev 3721) @@ -0,0 +1,39 @@ +using NHibernate.Test.Events.Collections.Association.Bidirectional.ManyToMany; +using NUnit.Framework; + +namespace NHibernate.Test.Events.Collections.Association +{ + public abstract class AbstractAssociationCollectionEventFixture : AbstractCollectionEventFixture + { + [Test] + public void DeleteParentButNotChild() + { + CollectionListeners listeners = new CollectionListeners(sessions); + IParentWithCollection parent = CreateParentWithOneChild("parent", "child"); + ChildEntity child = (ChildEntity) GetFirstChild(parent.Children); + listeners.Clear(); + ISession s = OpenSession(); + ITransaction tx = s.BeginTransaction(); + parent = (IParentWithCollection) s.Get(parent.GetType(), parent.Id); + child = (ChildEntity) s.Get(child.GetType(), child.Id); + parent.RemoveChild(child); + s.Delete(parent); + tx.Commit(); + s.Close(); + int index = 0; + CheckResult(listeners, listeners.InitializeCollection, parent, index++); + if (child is ChildWithBidirectionalManyToMany) + { + CheckResult(listeners, listeners.InitializeCollection, (ChildWithBidirectionalManyToMany) child, index++); + } + CheckResult(listeners, listeners.PreCollectionRemove, parent, index++); + CheckResult(listeners, listeners.PostCollectionRemove, parent, index++); + if (child is ChildWithBidirectionalManyToMany) + { + CheckResult(listeners, listeners.PreCollectionUpdate, (ChildWithBidirectionalManyToMany) child, index++); + CheckResult(listeners, listeners.PostCollectionUpdate, (ChildWithBidirectionalManyToMany) child, index++); + } + CheckNumberOfResults(listeners, index); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/BidirectionalManyToManyBagToSetCollectionEventFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/BidirectionalManyToManyBagToSetCollectionEventFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/BidirectionalManyToManyBagToSetCollectionEventFixture.cs 2008-08-20 20:07:55 UTC (rev 3721) @@ -0,0 +1,25 @@ +using System.Collections; +using System.Collections.Generic; +using NUnit.Framework; + +namespace NHibernate.Test.Events.Collections.Association.Bidirectional.ManyToMany +{ + [TestFixture, Ignore("Need some more check for timeouts.")] + public class BidirectionalManyToManyBagToSetCollectionEventFixture : AbstractAssociationCollectionEventFixture + { + protected override IList Mappings + { + get { return new string[] { "Events.Collections.Association.Bidirectional.ManyToMany.BidirectionalManyToManyBagToSetMapping.hbm.xml" }; } + } + + public override IParentWithCollection CreateParent(string name) + { + return new ParentWithBidirectionalManyToMany(name); + } + + public override ICollection<IChild> CreateCollection() + { + return new List<IChild>(); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/BidirectionalManyToManyBagToSetMapping.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/BidirectionalManyToManyBagToSetMapping.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/BidirectionalManyToManyBagToSetMapping.hbm.xml 2008-08-20 20:07:55 UTC (rev 3721) @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.Events.Collections.Association.Bidirectional.ManyToMany"> + + <class name="ParentWithBidirectionalManyToMany" table="PARENT"> + <id name="Id" column="ID" type="long"> + <generator class="native"/> + </id> + <bag name="Children" table="PARENT_CHILD" inverse="false" cascade="all"> + <key column="parent_id"/> + <many-to-many column="child_id" class="ChildWithBidirectionalManyToMany"/> + </bag> + </class> + + <class name="ChildWithBidirectionalManyToMany" table="CHILD"> + <id name="Id" column="ID" type="long"> + <generator class="native"/> + </id> + <property name="Name" column="NAME" type="string"/> + <set name="Parents" table="PARENT_CHILD" inverse="true"> + <key column="child_id"/> + <many-to-many column="parent_id" class="ParentWithBidirectionalManyToMany"/> + </set> + </class> + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bidirectional/ManyToMany/BidirectionalManyToManySetToSetCollectionEventFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Events/Collections/Association/Bid... [truncated message content] |