From: <aye...@us...> - 2009-09-16 01:57:47
|
Revision: 4715 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4715&view=rev Author: ayenderahien Date: 2009-09-16 01:57:36 +0000 (Wed, 16 Sep 2009) Log Message: ----------- Fixing NHibernate's ability to use Criteria Queries on composites. Based in part on an unapplied patch from David Mansfield for Hibernate Modified Paths: -------------- branches/2.1.x/nhibernate/src/NHibernate/Hql/Ast/ANTLR/SessionFactoryHelperExtensions.cs branches/2.1.x/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs branches/2.1.x/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs branches/2.1.x/nhibernate/src/NHibernate/Hql/Classic/WhereParser.cs branches/2.1.x/nhibernate/src/NHibernate/Hql/QuerySplitter.cs branches/2.1.x/nhibernate/src/NHibernate/Hql/Util/SessionFactoryHelper.cs branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/CriteriaJoinWalker.cs branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs branches/2.1.x/nhibernate/src/NHibernate/Loader/JoinWalker.cs branches/2.1.x/nhibernate/src/NHibernate/Loader/Loader.cs branches/2.1.x/nhibernate/src/NHibernate/NHibernate.csproj branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH830/AutoFlushTestFixture.cs branches/2.1.x/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/ComponentCollectionCriteriaInfoProvider.cs branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/EntityCriteriaInfoProvider.cs branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/ICriteriaInfoProvider.cs branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/ScalarCollectionCriteriaInfoProvider.cs branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/ branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Employee.cs branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Fixture.cs branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Mappings.hbm.xml branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Money.cs Modified: branches/2.1.x/nhibernate/src/NHibernate/Hql/Ast/ANTLR/SessionFactoryHelperExtensions.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Hql/Ast/ANTLR/SessionFactoryHelperExtensions.cs 2009-09-15 21:41:03 UTC (rev 4714) +++ branches/2.1.x/nhibernate/src/NHibernate/Hql/Ast/ANTLR/SessionFactoryHelperExtensions.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -17,6 +17,7 @@ { private readonly ISessionFactoryImplementor _sfi; private readonly NullableDictionary<string, IPropertyMapping> _collectionPropertyMappingByRole; + private readonly SessionFactoryHelper helper; /// <summary> /// Construct a new SessionFactoryHelperExtensions instance. @@ -25,6 +26,7 @@ public SessionFactoryHelperExtensions(ISessionFactoryImplementor sfi) { _sfi = sfi; + helper = new SessionFactoryHelper(_sfi); _collectionPropertyMappingByRole = new NullableDictionary<string, IPropertyMapping>(); } @@ -251,7 +253,7 @@ /// <returns>The defined persister for this class, or null if none found.</returns> private static IQueryable FindQueryableUsingImports(ISessionFactoryImplementor sfi, string className) { - return SessionFactoryHelper.FindQueryableUsingImports(sfi, className); + return new SessionFactoryHelper(sfi).FindQueryableUsingImports(className); } /// <summary> @@ -261,7 +263,7 @@ /// <returns>The defined persister for this entity, or null if none found.</returns> private IEntityPersister FindEntityPersisterByName(string name) { - return SessionFactoryHelper.FindEntityPersisterUsingImports(_sfi, name); + return helper.FindEntityPersisterUsingImports(name); } /// <summary> Modified: branches/2.1.x/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2009-09-15 21:41:03 UTC (rev 4714) +++ branches/2.1.x/nhibernate/src/NHibernate/Hql/Classic/QueryTranslator.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -537,7 +537,7 @@ internal IQueryable GetPersisterUsingImports(string className) { - return SessionFactoryHelper.FindQueryableUsingImports(Factory, className); + return helper.FindQueryableUsingImports(className); } internal IQueryable GetPersister(string clazz) @@ -1320,7 +1320,7 @@ return result; } - public static string[] ConcreteQueries(string query, ISessionFactoryImplementor factory) + public string[] ConcreteQueries(string query, ISessionFactoryImplementor factory) { // TODO H3.2 check if the QuerySplitter can do the work (this method is not present in H3.2) @@ -1374,7 +1374,7 @@ ((last != null && beforeClassTokens.Contains(last)) && (next == null || !notAfterClassTokens.Contains(next))) || PathExpressionParser.EntityClass.Equals(last)) { - System.Type clazz = SessionFactoryHelper.GetImportedClass(factory, token); + System.Type clazz = helper.GetImportedClass(token); if (clazz != null) { string[] implementors = factory.GetImplementors(clazz.FullName); Modified: branches/2.1.x/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs 2009-09-15 21:41:03 UTC (rev 4714) +++ branches/2.1.x/nhibernate/src/NHibernate/Hql/Classic/SelectParser.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -35,6 +35,7 @@ public void Token(string token, QueryTranslator q) { + SessionFactoryHelper helper = new SessionFactoryHelper(q.Factory); string lctoken = token.ToLowerInvariant(); if (first) @@ -55,7 +56,7 @@ if (afterNew) { afterNew = false; - holderClass = SessionFactoryHelper.GetImportedClass(q.Factory, token); + holderClass = helper.GetImportedClass(token); if (holderClass == null) { throw new QueryException("class not found: " + token); Modified: branches/2.1.x/nhibernate/src/NHibernate/Hql/Classic/WhereParser.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Hql/Classic/WhereParser.cs 2009-09-15 21:41:03 UTC (rev 4714) +++ branches/2.1.x/nhibernate/src/NHibernate/Hql/Classic/WhereParser.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -463,6 +463,7 @@ private void DoToken(string token, QueryTranslator q) { + SessionFactoryHelper helper = new SessionFactoryHelper(q.Factory); if (q.IsName(StringHelper.Root(token))) //path expression { DoPathExpression(q.Unalias(token), q); @@ -508,7 +509,7 @@ { fieldName = StringHelper.Unqualify(token); string typeName = StringHelper.Qualifier(token); - importedType = SessionFactoryHelper.GetImportedClass(q.Factory, typeName); + importedType = helper.GetImportedClass(typeName); } if (indexOfDot > -1 && importedType != null && Modified: branches/2.1.x/nhibernate/src/NHibernate/Hql/QuerySplitter.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Hql/QuerySplitter.cs 2009-09-15 21:41:03 UTC (rev 4714) +++ branches/2.1.x/nhibernate/src/NHibernate/Hql/QuerySplitter.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -46,6 +46,8 @@ //TODO: this is one of the ugliest and most fragile pieces of code in Hibernate.... + SessionFactoryHelper helper = new SessionFactoryHelper(factory); + string[] tokens = StringHelper.Split(StringHelper.WhiteSpace + "(),", query, true); if (tokens.Length == 0) { @@ -95,7 +97,7 @@ (next == null || !notAfterClassTokens.Contains(next))) || PathExpressionParser.EntityClass.Equals(last)) { - System.Type clazz = SessionFactoryHelper.GetImportedClass(factory, token); + System.Type clazz = helper.GetImportedClass(token); if (clazz != null) { string[] implementors = factory.GetImplementors(clazz.FullName); Modified: branches/2.1.x/nhibernate/src/NHibernate/Hql/Util/SessionFactoryHelper.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Hql/Util/SessionFactoryHelper.cs 2009-09-15 21:41:03 UTC (rev 4714) +++ branches/2.1.x/nhibernate/src/NHibernate/Hql/Util/SessionFactoryHelper.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -1,4 +1,8 @@ +using System; +using System.Collections.Generic; using NHibernate.Engine; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Persister.Collection; using NHibernate.Persister.Entity; using NHibernate.Util; @@ -9,13 +13,22 @@ /// </summary> public class SessionFactoryHelper { - public static IQueryable FindQueryableUsingImports(ISessionFactoryImplementor sfi, string className) + private readonly ISessionFactoryImplementor sfi; + private readonly IDictionary<string,CollectionPropertyMapping> collectionPropertyMappingByRole = + new Dictionary<string,CollectionPropertyMapping>(); + + public SessionFactoryHelper(ISessionFactoryImplementor sfi) { - return FindEntityPersisterUsingImports(sfi, className) as IQueryable; + this.sfi = sfi; } - public static IEntityPersister FindEntityPersisterUsingImports(ISessionFactoryImplementor sfi, string className) + public IQueryable FindQueryableUsingImports(string className) { + return FindEntityPersisterUsingImports(className) as IQueryable; + } + + public IEntityPersister FindEntityPersisterUsingImports(string className) + { // NH : short cut if (string.IsNullOrEmpty(className)) { @@ -61,8 +74,75 @@ return TypeNameParser.Parse(assemblyQualifiedName).Type; } - public static System.Type GetImportedClass(ISessionFactoryImplementor sfi, string className) + + + /// <summary> + /// Locate the collection persister by the collection role. + /// </summary> + /// <param name="role">The collection role name.</param> + /// <returns>The defined CollectionPersister for this collection role, or null.</returns> + public IQueryableCollection GetCollectionPersister(String role) { + try + { + return (IQueryableCollection)sfi.GetCollectionPersister(role); + } + catch (InvalidCastException cce) + { + throw new QueryException("collection is not queryable: " + role); + } + catch (Exception e) + { + throw new QueryException("collection not found: " + role); + } + } + + /// <summary> + /// Locate the persister by class or entity name, requiring that such a persister + /// exists + /// </summary> + /// <param name="name">The class or entity name</param> + /// <returns>The defined persister for this entity</returns> + public IEntityPersister RequireClassPersister(String name) + { + IEntityPersister cp = FindEntityPersisterByName(name); + if (cp == null) + { + throw new QuerySyntaxException(name + " is not mapped"); + } + + return cp; + } + + /// <summary> + /// Locate the persister by class or entity name. + /// </summary> + /// <param name="name">The class or entity name</param> + /// <returns>The defined persister for this entity, or null if none found.</returns> + private IEntityPersister FindEntityPersisterByName(String name) + { + // First, try to get the persister using the given name directly. + try + { + return sfi.GetEntityPersister(name); + } + catch (MappingException ignore) + { + // unable to locate it using this name + } + + // If that didn't work, try using the 'import' name. + String importedClassName = sfi.GetImportedClassName(name); + if (importedClassName == null) + { + return null; + } + return sfi.GetEntityPersister(importedClassName); + } + + + public System.Type GetImportedClass(string className) + { string importedName = sfi.GetImportedClassName(className); if (importedName == null) @@ -73,5 +153,49 @@ // NH Different implementation: our sessionFactory.Imports hold AssemblyQualifiedName return System.Type.GetType(importedName, false); } + + + /// <summary> + /// Retreive a PropertyMapping describing the given collection role. + /// </summary> + /// <param name="role">The collection role for whcih to retrieve the property mapping.</param> + /// <returns>The property mapping.</returns> + public IPropertyMapping GetCollectionPropertyMapping(String role) + { + return collectionPropertyMappingByRole[role]; + } + + + /* Locate the collection persister by the collection role, requiring that + * such a persister exist. + * + * @param role The collection role name. + * @return The defined CollectionPersister for this collection role. + * @throws QueryException Indicates that the collection persister could not be found. + */ + public IQueryableCollection RequireQueryableCollection(String role) + { + try + { + IQueryableCollection queryableCollection = (IQueryableCollection)sfi + .GetCollectionPersister(role); + if (queryableCollection != null) + { + collectionPropertyMappingByRole.Add(role, + new CollectionPropertyMapping(queryableCollection)); + } + return queryableCollection; + } + catch (InvalidCastException) + { + throw new QueryException( + "collection role is not queryable: " + role); + } + catch (Exception) + { + throw new QueryException("collection role not found: " + + role); + } + } } } \ No newline at end of file Added: branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/ComponentCollectionCriteriaInfoProvider.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/ComponentCollectionCriteriaInfoProvider.cs (rev 0) +++ branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/ComponentCollectionCriteriaInfoProvider.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using NHibernate.Persister.Collection; +using NHibernate.Persister.Entity; +using NHibernate.Type; + +namespace NHibernate.Loader.Criteria +{ + public class ComponentCollectionCriteriaInfoProvider : ICriteriaInfoProvider + { + private readonly IQueryableCollection persister; + private readonly IDictionary<String, IType> subTypes = new Dictionary<string, IType>(); + + public ComponentCollectionCriteriaInfoProvider(IQueryableCollection persister) + { + this.persister = persister; + if (!persister.ElementType.IsComponentType) + { + throw new ArgumentException("persister for role " + persister.Role + " is not a collection-of-component"); + } + + var componentType = (ComponentType)persister.ElementType; + var names = componentType.PropertyNames; + var types = componentType.Subtypes; + + for (var i = 0; i < names.Length; i++) + { + subTypes.Add(names[i], types[i]); + } + + } + + public String Name + { + get + { + return persister.Role; + } + } + + public string[] Spaces + { + get + { + return persister.CollectionSpaces; + } + } + + public IPropertyMapping PropertyMapping + { + get + { + return persister; + } + } + + public IType GetType(String relativePath) + { + // TODO: can a component have a nested component? then we may need to do something more here... + if (relativePath.IndexOf('.') >= 0) + throw new ArgumentException("dotted paths not handled (yet?!) for collection-of-component"); + + IType type; + + if (subTypes.TryGetValue(relativePath, out type) == false) + throw new ArgumentException("property " + relativePath + " not found in component of collection " + Name); + + return type; + } + } +} \ No newline at end of file Modified: branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/CriteriaJoinWalker.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/CriteriaJoinWalker.cs 2009-09-15 21:41:03 UTC (rev 4714) +++ branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/CriteriaJoinWalker.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -1,6 +1,8 @@ using System.Collections.Generic; using Iesi.Collections.Generic; +using log4net; using NHibernate.Engine; +using NHibernate.Persister.Collection; using NHibernate.Persister.Entity; using NHibernate.SqlCommand; using NHibernate.Type; @@ -25,6 +27,8 @@ private readonly string[] userAliases; private readonly IList<string> userAliasList = new List<string>(); + private static readonly ILog logger = LogManager.GetLogger(typeof (CriteriaJoinWalker)); + public CriteriaJoinWalker(IOuterJoinLoadable persister, CriteriaQueryTranslator translator, ISessionFactoryImplementor factory, ICriteria criteria, string rootEntityName, IDictionary<string, IFilter> enabledFilters) @@ -126,8 +130,15 @@ protected override string GenerateTableAlias(int n, string path, IJoinable joinable) { - if (joinable.ConsumesEntityAlias()) + bool shouldCreateUserAlias = joinable.ConsumesEntityAlias(); + if(shouldCreateUserAlias == false && joinable.IsCollection) { + var elementType = ((ICollectionPersister)joinable).ElementType; + if (elementType != null) + shouldCreateUserAlias = elementType.IsComponentType; + } + if (shouldCreateUserAlias) + { ICriteria subcriteria = translator.GetCriteria(path); string sqlAlias = subcriteria == null ? null : translator.GetSQLAlias(subcriteria); if (sqlAlias != null) @@ -135,10 +146,8 @@ userAliasList.Add(subcriteria.Alias); //alias may be null return sqlAlias; //EARLY EXIT } - else - { - userAliasList.Add(null); - } + + userAliasList.Add(null); } return base.GenerateTableAlias(n + translator.SQLAliasCount, path, joinable); } Modified: branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs 2009-09-15 21:41:03 UTC (rev 4714) +++ branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Text; using Iesi.Collections.Generic; +using log4net; using NHibernate.Criterion; using NHibernate.Engine; using NHibernate.Hql.Util; @@ -24,9 +25,14 @@ private readonly CriteriaImpl rootCriteria; private readonly string rootEntityName; private readonly string rootSQLAlias; - private readonly int aliasCount = 0; + private const int aliasCount = 0; - private readonly IDictionary<ICriteria, string> criteriaEntityNames = new LinkedHashMap<ICriteria, string>(); + private readonly IDictionary<ICriteria, ICriteriaInfoProvider> criteriaInfoMap = + new Dictionary<ICriteria, ICriteriaInfoProvider>(); + + private readonly IDictionary<String, ICriteriaInfoProvider> nameCriteriaInfoMap = + new Dictionary<string, ICriteriaInfoProvider>(); + private readonly ISet<ICollectionPersister> criteriaCollectionPersisters = new HashedSet<ICollectionPersister>(); private readonly IDictionary<ICriteria, string> criteriaSQLAliasMap = new Dictionary<ICriteria, string>(); @@ -36,23 +42,26 @@ private readonly ISessionFactoryImplementor sessionFactory; private int indexForAlias = 0; + private static readonly ILog logger = LogManager.GetLogger(typeof(CriteriaQueryTranslator)); private readonly List<TypedValue> usedTypedValues = new List<TypedValue>(); + private SessionFactoryHelper helper; public CriteriaQueryTranslator(ISessionFactoryImplementor factory, CriteriaImpl criteria, string rootEntityName, - string rootSQLAlias, ICriteriaQuery outerQuery) + string rootSQLAlias, ICriteriaQuery outerQuery) : this(factory, criteria, rootEntityName, rootSQLAlias) { outerQueryTranslator = outerQuery; } public CriteriaQueryTranslator(ISessionFactoryImplementor factory, CriteriaImpl criteria, string rootEntityName, - string rootSQLAlias) + string rootSQLAlias) { rootCriteria = criteria; this.rootEntityName = rootEntityName; sessionFactory = factory; this.rootSQLAlias = rootSQLAlias; + helper = new SessionFactoryHelper(factory); CreateAliasCriteriaMap(); CreateAssociationPathCriteriaMap(); @@ -62,7 +71,7 @@ } [CLSCompliant(false)] // TODO: Why does this cause a problem in 1.1 - public string RootSQLAlias + public string RootSQLAlias { get { return rootSQLAlias; } } @@ -71,9 +80,9 @@ { ISet<string> result = new HashedSet<string>(); - foreach (string entityName in criteriaEntityNames.Values) + foreach (ICriteriaInfoProvider info in criteriaInfoMap.Values) { - result.AddAll(Factory.GetEntityPersister(entityName).QuerySpaces); + result.AddAll(info.Spaces); } foreach (ICollectionPersister collectionPersister in criteriaCollectionPersisters) @@ -131,7 +140,7 @@ return new QueryParameters(typeArray, valueArray, lockModes, selection, rootCriteria.Cacheable, rootCriteria.CacheRegion, - rootCriteria.Comment, rootCriteria.LookupByNaturalKey, rootCriteria.ResultTransformer); + rootCriteria.Comment, rootCriteria.LookupByNaturalKey, rootCriteria.ResultTransformer); } public SqlString GetGroupBy() @@ -140,7 +149,7 @@ { return rootCriteria.Projection.ToGroupSqlString(rootCriteria.ProjectionCriteria, this, - new CollectionHelper.EmptyMapClass<string, IFilter>()); + new CollectionHelper.EmptyMapClass<string, IFilter>()); } else { @@ -245,6 +254,7 @@ { ICriteria result; associationPathCriteriaMap.TryGetValue(path, out result); + logger.DebugFormat("getCriteria for path={0} crit={1}", path, result); return result; } @@ -330,33 +340,119 @@ else { // otherwise, recurse - return GetWholeAssociationPath((CriteriaImpl.Subcriteria) parent) + '.' + path; + return GetWholeAssociationPath((CriteriaImpl.Subcriteria)parent) + '.' + path; } } private void CreateCriteriaEntityNameMap() { - criteriaEntityNames[rootCriteria] = rootEntityName; + // initialize the rootProvider first + ICriteriaInfoProvider rootProvider = new EntityCriteriaInfoProvider((IQueryable)sessionFactory.GetEntityPersister(rootEntityName)); + criteriaInfoMap.Add(rootCriteria, rootProvider); + nameCriteriaInfoMap.Add(rootProvider.Name, rootProvider); + foreach (KeyValuePair<string, ICriteria> me in associationPathCriteriaMap) { - criteriaEntityNames[me.Value] = GetPathEntityName(me.Key); + ICriteriaInfoProvider info = GetPathInfo(me.Key); + criteriaInfoMap.Add(me.Value, info); + nameCriteriaInfoMap[info.Name] = info; } } - private string GetPathEntityName(string path) + + private void CreateCriteriaCollectionPersisters() { - IQueryable persister = (IQueryable) sessionFactory.GetEntityPersister(rootEntityName); + foreach (KeyValuePair<string, ICriteria> me in associationPathCriteriaMap) + { + IJoinable joinable = GetPathJoinable(me.Key); + if (joinable != null && joinable.IsCollection) + { + criteriaCollectionPersisters.Add((ICollectionPersister)joinable); + } + } + } + + private IJoinable GetPathJoinable(string path) + { + IJoinable last = (IJoinable)Factory.GetEntityPersister(rootEntityName); + IPropertyMapping lastEntity = (IPropertyMapping)last; + + string componentPath = ""; + StringTokenizer tokens = new StringTokenizer(path, ".", false); + foreach (string token in tokens) + { + componentPath += token; + IType type = lastEntity.ToType(componentPath); + if (type.IsAssociationType) + { + if(type.IsCollectionType) + { + // ignore joinables for composite collections + var collectionType = (CollectionType)type; + var persister = Factory.GetCollectionPersister(collectionType.Role); + if(persister.ElementType.IsEntityType==false) + return null; + } + IAssociationType atype = (IAssociationType)type; + + last = atype.GetAssociatedJoinable(Factory); + lastEntity = (IPropertyMapping)Factory.GetEntityPersister(atype.GetAssociatedEntityName(Factory)); + componentPath = ""; + } + else if (type.IsComponentType) + { + componentPath += '.'; + } + else + { + throw new QueryException("not an association: " + componentPath); + } + } + return last; + } + + private ICriteriaInfoProvider GetPathInfo(string path) + { + StringTokenizer tokens = new StringTokenizer(path, ".", false); string componentPath = string.Empty; + + // start with the 'rootProvider' + ICriteriaInfoProvider provider; + if (nameCriteriaInfoMap.TryGetValue(rootEntityName, out provider) == false) + throw new ArgumentException("Could not find ICriteriaInfoProvider for: " + path); + + foreach (string token in tokens) { componentPath += token; - IType type = persister.ToType(componentPath); + logger.DebugFormat("searching for {0}", componentPath); + IType type = provider.GetType(componentPath); if (type.IsAssociationType) { - IAssociationType atype = (IAssociationType) type; - persister = (IQueryable) sessionFactory.GetEntityPersister(atype.GetAssociatedEntityName(sessionFactory)); + // CollectionTypes are always also AssociationTypes - but there's not always an associated entity... + IAssociationType atype = (IAssociationType)type; + + CollectionType ctype = type.IsCollectionType ? (CollectionType)type : null; + IType elementType = (ctype != null) ? ctype.GetElementType(sessionFactory) : null; + // is the association a collection of components or value-types? (i.e a colloction of valued types?) + if (ctype != null && elementType.IsComponentType) + { + provider = new ComponentCollectionCriteriaInfoProvider(helper.GetCollectionPersister(ctype.Role)); + } + else if (ctype != null && !elementType.IsEntityType) + { + provider = new ScalarCollectionCriteriaInfoProvider(helper, ctype.Role); + } + else + { + provider = new EntityCriteriaInfoProvider((IQueryable)sessionFactory.GetEntityPersister( + atype.GetAssociatedEntityName( + sessionFactory) + )); + } + componentPath = string.Empty; } else if (type.IsComponentType) @@ -368,22 +464,27 @@ throw new QueryException("not an association: " + componentPath); } } - return persister.EntityName; + + logger.DebugFormat("returning entity name={0} for path={1} class={2}", + provider.Name, path, provider.GetType().Name); + return provider; } private void CreateCriteriaSQLAliasMap() { int i = 0; - foreach (KeyValuePair<ICriteria, string> me in criteriaEntityNames) + foreach (KeyValuePair<ICriteria, ICriteriaInfoProvider> me in criteriaInfoMap) { ICriteria crit = me.Key; string alias = crit.Alias; if (alias == null) { - alias = me.Value; // the entity name + alias = me.Value.Name; // the entity name } criteriaSQLAliasMap[crit] = StringHelper.GenerateAlias(alias, i++); + logger.DebugFormat("put criteria={0} alias={1}", + crit, criteriaSQLAliasMap[crit]); } criteriaSQLAliasMap[rootCriteria] = rootSQLAlias; } @@ -395,14 +496,17 @@ public string GetSQLAlias(ICriteria criteria) { - return criteriaSQLAliasMap[criteria]; + String alias = criteriaSQLAliasMap[criteria]; + logger.DebugFormat("returning alias={0} for criteria={1}", alias, criteria); + return alias; } public string GetEntityName(ICriteria criteria) { - string result; - criteriaEntityNames.TryGetValue(criteria, out result); - return result; + ICriteriaInfoProvider result; + if(criteriaInfoMap.TryGetValue(criteria, out result)==false) + throw new ArgumentException("Could not find a matching criteria info provider to: " + criteria); + return result.Name; } public string GetColumn(ICriteria criteria, string propertyName) @@ -442,18 +546,18 @@ public string[] GetIdentifierColumns(ICriteria subcriteria) { - string[] idcols = ((ILoadable) GetPropertyMapping(GetEntityName(subcriteria))).IdentifierColumnNames; + string[] idcols = ((ILoadable)GetPropertyMapping(GetEntityName(subcriteria))).IdentifierColumnNames; return StringHelper.Qualify(GetSQLAlias(subcriteria), idcols); } public IType GetIdentifierType(ICriteria subcriteria) { - return ((ILoadable) GetPropertyMapping(GetEntityName(subcriteria))).IdentifierType; + return ((ILoadable)GetPropertyMapping(GetEntityName(subcriteria))).IdentifierType; } public TypedValue GetTypedIdentifierValue(ICriteria subcriteria, object value) { - ILoadable loadable = (ILoadable) GetPropertyMapping(GetEntityName(subcriteria)); + ILoadable loadable = (ILoadable)GetPropertyMapping(GetEntityName(subcriteria)); return new TypedValue(loadable.IdentifierType, value, EntityMode.Poco); } @@ -518,8 +622,8 @@ // Detect discriminator values... if (value is System.Type) { - System.Type entityClass = (System.Type) value; - IQueryable q = SessionFactoryHelper.FindQueryableUsingImports(sessionFactory, entityClass.FullName); + System.Type entityClass = (System.Type)value; + IQueryable q = helper.FindQueryableUsingImports(entityClass.FullName); if (q != null) { @@ -533,7 +637,10 @@ private IPropertyMapping GetPropertyMapping(string entityName) { - return (IPropertyMapping) sessionFactory.GetEntityPersister(entityName); + ICriteriaInfoProvider info ; + if (nameCriteriaInfoMap.TryGetValue(entityName, out info)==false) + throw new InvalidOperationException("Could not find criteria info provider for: " + entityName); + return info.PropertyMapping; } public string GetEntityName(ICriteria subcriteria, string propertyName) @@ -600,49 +707,7 @@ } } - private void CreateCriteriaCollectionPersisters() - { - foreach (KeyValuePair<string, ICriteria> me in associationPathCriteriaMap) - { - IJoinable joinable = GetPathJoinable(me.Key); - if (joinable.IsCollection) - { - criteriaCollectionPersisters.Add((ICollectionPersister) joinable); - } - } - } - private IJoinable GetPathJoinable(string path) - { - IJoinable last = (IJoinable) Factory.GetEntityPersister(rootEntityName); - IPropertyMapping lastEntity = (IPropertyMapping) last; - - string componentPath = ""; - - StringTokenizer tokens = new StringTokenizer(path, ".", false); - foreach (string token in tokens) - { - componentPath += token; - IType type = lastEntity.ToType(componentPath); - if (type.IsAssociationType) - { - IAssociationType atype = (IAssociationType) type; - last = atype.GetAssociatedJoinable(Factory); - lastEntity = (IPropertyMapping) Factory.GetEntityPersister(atype.GetAssociatedEntityName(Factory)); - componentPath = ""; - } - else if (type.IsComponentType) - { - componentPath += '.'; - } - else - { - throw new QueryException("not an association: " + componentPath); - } - } - return last; - } - public SqlString GetHavingCondition(IDictionary<string, IFilter> enabledFilters) { SqlStringBuilder condition = new SqlStringBuilder(30); Added: branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/EntityCriteriaInfoProvider.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/EntityCriteriaInfoProvider.cs (rev 0) +++ branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/EntityCriteriaInfoProvider.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -0,0 +1,45 @@ +using System; +using NHibernate.Persister.Entity; +using NHibernate.Type; + +namespace NHibernate.Loader.Criteria +{ + public class EntityCriteriaInfoProvider : ICriteriaInfoProvider + { + readonly IQueryable persister; + + public EntityCriteriaInfoProvider(IQueryable persister) + { + this.persister = persister; + } + + public String Name + { + get + { + return persister.EntityName; + } + } + + public string[] Spaces + { + get + { + return persister.QuerySpaces; + } + } + + public IPropertyMapping PropertyMapping + { + get + { + return persister; + } + } + + public IType GetType(String relativePath) + { + return persister.ToType(relativePath); + } + } +} \ No newline at end of file Added: branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/ICriteriaInfoProvider.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/ICriteriaInfoProvider.cs (rev 0) +++ branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/ICriteriaInfoProvider.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -0,0 +1,14 @@ +using System; +using NHibernate.Persister.Entity; +using NHibernate.Type; + +namespace NHibernate.Loader.Criteria +{ + public interface ICriteriaInfoProvider + { + string Name { get; } + string[] Spaces { get; } + IPropertyMapping PropertyMapping { get; } + IType GetType(String relativePath); + } +} \ No newline at end of file Added: branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/ScalarCollectionCriteriaInfoProvider.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/ScalarCollectionCriteriaInfoProvider.cs (rev 0) +++ branches/2.1.x/nhibernate/src/NHibernate/Loader/Criteria/ScalarCollectionCriteriaInfoProvider.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -0,0 +1,52 @@ +using System; +using NHibernate.Hql.Util; +using NHibernate.Persister.Collection; +using NHibernate.Persister.Entity; +using NHibernate.Type; + +namespace NHibernate.Loader.Criteria +{ + public class ScalarCollectionCriteriaInfoProvider : ICriteriaInfoProvider + { + private readonly String role; + private readonly IQueryableCollection persister; + private readonly SessionFactoryHelper helper; + public ScalarCollectionCriteriaInfoProvider(SessionFactoryHelper helper, String role) + { + this.role = role; + this.helper = helper; + this.persister = helper.RequireQueryableCollection(role); + } + + public String Name + { + get + { + return role; + } + } + + public string[] Spaces + { + get + { + return persister.CollectionSpaces; + } + } + + public IPropertyMapping PropertyMapping + { + get + { + return helper.GetCollectionPropertyMapping(role); + } + } + + public IType GetType(String relativePath) + { + //not sure what things are going to be passed here, how about 'id', maybe 'index' or 'key' or 'elements' ??? + return PropertyMapping.ToType(relativePath); + } + + } +} \ No newline at end of file Modified: branches/2.1.x/nhibernate/src/NHibernate/Loader/JoinWalker.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Loader/JoinWalker.cs 2009-09-15 21:41:03 UTC (rev 4714) +++ branches/2.1.x/nhibernate/src/NHibernate/Loader/JoinWalker.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -783,7 +783,6 @@ else { SqlStringBuilder buf = new SqlStringBuilder(associations.Count * 3); - buf.Add(StringHelper.CommaSpace); int entityAliasCount = 0; int collectionAliasCount = 0; @@ -804,16 +803,16 @@ joinable.SelectFragment(next == null ? null : next.Joinable, next == null ? null : next.RHSAlias, join.RHSAlias, entitySuffix, collectionSuffix, join.JoinType == JoinType.LeftOuterJoin); - buf.Add(selectFragment); - + if (selectFragment.Trim().Length > 0) + { + buf.Add(StringHelper.CommaSpace) + .Add(selectFragment); + } if (joinable.ConsumesEntityAlias()) entityAliasCount++; if (joinable.ConsumesCollectionAlias() && join.JoinType == JoinType.LeftOuterJoin) collectionAliasCount++; - - if (i < associations.Count - 1 && selectFragment.Trim().Length > 0) - buf.Add(StringHelper.CommaSpace); } return buf.ToSqlString().ToString(); Modified: branches/2.1.x/nhibernate/src/NHibernate/Loader/Loader.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Loader/Loader.cs 2009-09-15 21:41:03 UTC (rev 4714) +++ branches/2.1.x/nhibernate/src/NHibernate/Loader/Loader.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -13,6 +13,7 @@ using NHibernate.Engine; using NHibernate.Event; using NHibernate.Exceptions; +using NHibernate.Hql.Util; using NHibernate.Impl; using NHibernate.Persister.Collection; using NHibernate.Persister.Entity; @@ -48,10 +49,12 @@ private readonly ISessionFactoryImplementor factory; private ColumnNameCache columnNameCache; + protected SessionFactoryHelper helper; public Loader(ISessionFactoryImplementor factory) { this.factory = factory; + helper = new SessionFactoryHelper(factory); } /// <summary> Modified: branches/2.1.x/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/NHibernate.csproj 2009-09-15 21:41:03 UTC (rev 4714) +++ branches/2.1.x/nhibernate/src/NHibernate/NHibernate.csproj 2009-09-16 01:57:36 UTC (rev 4715) @@ -514,6 +514,10 @@ <Compile Include="Hql\Ast\ANTLR\Tree\InsertStatement.cs" /> <Compile Include="Hql\Ast\ANTLR\Tree\UpdateStatement.cs" /> <Compile Include="Impl\SessionIdLoggingContext.cs" /> + <Compile Include="Loader\Criteria\ComponentCollectionCriteriaInfoProvider.cs" /> + <Compile Include="Loader\Criteria\EntityCriteriaInfoProvider.cs" /> + <Compile Include="Loader\Criteria\ICriteriaInfoProvider.cs" /> + <Compile Include="Loader\Criteria\ScalarCollectionCriteriaInfoProvider.cs" /> <Compile Include="Param\AbstractExplicitParameterSpecification.cs" /> <Compile Include="Param\AggregatedIndexCollectionSelectorParameterSpecifications.cs" /> <Compile Include="Param\CollectionFilterKeyParameterSpecification.cs" /> Property changes on: branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection ___________________________________________________________________ Added: bugtraq:url + http://jira.nhibernate.org/browse/%BUGID% Added: bugtraq:logregex + NH-\d+ Added: branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Employee.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Employee.cs (rev 0) +++ branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Employee.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NHibernate.Test.NHSpecificTest.CriteriaQueryOnComponentCollection +{ + public class Employee + { + public virtual int Id { get; set; } + public virtual ICollection<Money> Amounts { get; set; } + public virtual ICollection<ManagedEmployee> ManagedEmployees { get; set; } + } + + public class ManagedEmployee + { + public virtual Employee Employee { get; set; } + public virtual string Position { get; set; } + } +} Added: branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Fixture.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Fixture.cs (rev 0) +++ branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Fixture.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -0,0 +1,118 @@ +using System.Collections; +using Iesi.Collections.Generic; +using NHibernate.Cfg; +using NHibernate.Criterion; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.CriteriaQueryOnComponentCollection +{ + [TestFixture] + public class Fixture : TestCase + { + protected override void Configure(Configuration configuration) + { + configuration.SetProperty(Environment.FormatSql, "false"); + } + + protected override void OnSetUp() + { + using (var s = sessions.OpenSession()) + using (s.BeginTransaction()) + { + var parent = new Employee + { + Id = 2, + }; + var emp = new Employee + { + Id = 1, + Amounts = new HashedSet<Money> + { + new Money {Amount = 9, Currency = "USD"}, + new Money {Amount = 3, Currency = "EUR"}, + }, + ManagedEmployees = new HashedSet<ManagedEmployee> + { + new ManagedEmployee + { + Position = "parent", + Employee = parent + } + } + }; + s.Save(parent); + s.Save(emp); + + s.Transaction.Commit(); + } + } + + protected override void OnTearDown() + { + using (var s = sessions.OpenSession()) + using(s.BeginTransaction()) + { + s.Delete("from System.Object"); + + s.Transaction.Commit(); + } + } + + [Test] + public void CanQueryByCriteriaOnSetOfCompositeElement() + { + using(var s = sessions.OpenSession()) + { + var list = s.CreateCriteria<Employee>() + .CreateCriteria("ManagedEmployees") + .Add(Restrictions.Eq("Position", "parent")) + .SetResultTransformer(new RootEntityResultTransformer()) + .List(); + Assert.IsNotEmpty(list); + } + } + + [Test] + public void CanQueryByCriteriaOnSetOfElement() + { + using (var s = sessions.OpenSession()) + { + var list = s.CreateCriteria<Employee>() + .CreateCriteria("Amounts") + .Add(Restrictions.Gt("Amount", 5m)) + .SetResultTransformer(new RootEntityResultTransformer()) + .List(); + Assert.IsNotEmpty(list); + } + } + + [Test] + public void CanQueryByCriteriaOnSetOfCompositeElement_UsingDetachedCriteria() + { + using (var s = sessions.OpenSession()) + { + var list = s.CreateCriteria<Employee>() + .Add(Subqueries.PropertyIn("id", + DetachedCriteria.For<Employee>() + .SetProjection(Projections.Id()) + .CreateCriteria("Amounts") + .Add(Restrictions.Gt("Amount", 5m)))) + .List(); + Assert.IsNotEmpty(list); + } + } + + + protected override IList Mappings + { + get { return new [] { "NHSpecificTest.CriteriaQueryOnComponentCollection.Mappings.hbm.xml" }; } + } + + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + } +} Added: branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Mappings.hbm.xml =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Mappings.hbm.xml (rev 0) +++ branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Mappings.hbm.xml 2009-09-16 01:57:36 UTC (rev 4715) @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + namespace="NHibernate.Test.NHSpecificTest.CriteriaQueryOnComponentCollection" + assembly="NHibernate.Test"> + + <class name="Employee" table="Employees" lazy="false"> + <id name="Id" type="Int32"> + <generator class="assigned" /> + </id> + + <set name="Amounts" table="Amounts"> + <key column="EmployeeId"/> + <composite-element class="Money"> + <property name="Amount" type="Decimal" not-null="true"/> + <property name="Currency" type="String" not-null="true"/> + </composite-element> + </set> + + <set name="ManagedEmployees" table="ManagedEmployees"> + <key column="EmployeeId"/> + <composite-element class="ManagedEmployee"> + <property name="Position" type="string" not-null="true"/> + <many-to-one name="Employee" class="Employee"/> + </composite-element> + </set> + + </class> +</hibernate-mapping> Added: branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Money.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Money.cs (rev 0) +++ branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/CriteriaQueryOnComponentCollection/Money.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -0,0 +1,8 @@ +namespace NHibernate.Test.NHSpecificTest.CriteriaQueryOnComponentCollection +{ + public class Money + { + public virtual string Currency { get; set; } + public virtual decimal Amount { get; set; } + } +} \ No newline at end of file Modified: branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH830/AutoFlushTestFixture.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH830/AutoFlushTestFixture.cs 2009-09-15 21:41:03 UTC (rev 4714) +++ branches/2.1.x/nhibernate/src/NHibernate.Test/NHSpecificTest/NH830/AutoFlushTestFixture.cs 2009-09-16 01:57:36 UTC (rev 4715) @@ -20,13 +20,13 @@ sess.Flush(); //reload the data and then setup the many-to-many association - mum = (Cat) sess.Get(typeof(Cat), mum.Id); - son = (Cat) sess.Get(typeof(Cat), son.Id); + mum = (Cat) sess.Get(typeof (Cat), mum.Id); + son = (Cat) sess.Get(typeof (Cat), son.Id); mum.Children.Add(son); son.Parents.Add(mum); //Use criteria API to search first - IList result = sess.CreateCriteria(typeof(Cat)) + IList result = sess.CreateCriteria(typeof (Cat)) .CreateAlias("Children", "child") .Add(Expression.Eq("child.Id", son.Id)) .List(); Modified: branches/2.1.x/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-09-15 21:41:03 UTC (rev 4714) +++ branches/2.1.x/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-09-16 01:57:36 UTC (rev 4715) @@ -46,6 +46,10 @@ <SpecificVersion>False</SpecificVersion> <HintPath>..\..\lib\net\2.0\Antlr3.Runtime.dll</HintPath> </Reference> + <Reference Include="HibernatingRhinos.NHibernate.Profiler.Appender, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0774796e73ebf640, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\Hibernating.Rhinos\NHibernate.Profiler\HibernatingRhinos.NHibernate.Profiler.Appender\bin\Debug\HibernatingRhinos.NHibernate.Profiler.Appender.dll</HintPath> + </Reference> <Reference Include="Iesi.Collections, Version=1.0.0.1, Culture=neutral, PublicKeyToken=154fdcb44c4484fc"> <SpecificVersion>False</SpecificVersion> <HintPath>..\..\lib\net\2.0\Iesi.Collections.dll</HintPath> @@ -354,6 +358,9 @@ <Compile Include="LazyProperty\LazyPropertyFixture.cs" /> <Compile Include="MappingTest\NonReflectiveBinderFixture.cs" /> <Compile Include="MappingTest\Wicked.cs" /> + <Compile Include="NHSpecificTest\CriteriaQueryOnComponentCollection\Employee.cs" /> + <Compile Include="NHSpecificTest\CriteriaQueryOnComponentCollection\Fixture.cs" /> + <Compile Include="NHSpecificTest\CriteriaQueryOnComponentCollection\Money.cs" /> <Compile Include="NHSpecificTest\ElementsEnums\AbstractIntEnumsBagFixture.cs" /> <Compile Include="NHSpecificTest\ElementsEnums\IntEnumsBagNoNameFixture.cs" /> <Compile Include="NHSpecificTest\ElementsEnums\IntEnumsBagPartialNameFixture.cs" /> @@ -1981,6 +1988,7 @@ <EmbeddedResource Include="Bytecode\Lightweight\ProductLine.hbm.xml" /> <EmbeddedResource Include="DriverTest\MultiTypeEntity.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="NHSpecificTest\CriteriaQueryOnComponentCollection\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1908ThreadSafety\Mappings.hbm.xml" /> <EmbeddedResource Include="Tools\hbm2ddl\SchemaUpdate\1_Person.hbm.xml" /> <EmbeddedResource Include="Tools\hbm2ddl\SchemaUpdate\2_Person.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |