protected AbstractEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache, ISessionFactoryImplementor factory) { this.factory = factory; this.cache = cache; isLazyPropertiesCacheable = persistentClass.IsLazyPropertiesCacheable; cacheEntryStructure = factory.Settings.IsStructuredCacheEntriesEnabled ? (ICacheEntryStructure)new StructuredCacheEntry(this) : (ICacheEntryStructure)new UnstructuredCacheEntry(); entityMetamodel = new EntityMetamodel(persistentClass, factory); if (persistentClass.HasPocoRepresentation) { //TODO: this is currently specific to pojos, but need to be available for all entity-modes foreach (Subclass subclass in persistentClass.SubclassIterator) { entityNameBySubclass[subclass.MappedClass] = subclass.EntityName; } } batchSize = persistentClass.BatchSize.HasValue ? persistentClass.BatchSize.Value : factory.Settings.DefaultBatchFetchSize; hasSubselectLoadableCollections = persistentClass.HasSubselectLoadableCollections; propertyMapping = new BasicEntityPropertyMapping(this); #region IDENTIFIER identifierColumnSpan = persistentClass.Identifier.ColumnSpan; rootTableKeyColumnNames = new string[identifierColumnSpan]; identifierAliases = new string[identifierColumnSpan]; rowIdName = persistentClass.RootTable.RowId; loaderName = persistentClass.LoaderName; // TODO NH: Not safe cast to Column int i = 0; foreach (Column col in persistentClass.Identifier.ColumnIterator) { rootTableKeyColumnNames[i] = col.GetQuotedName(factory.Dialect); identifierAliases[i] = col.GetAlias(factory.Dialect, persistentClass.RootTable); i++; } #endregion #region VERSION if (persistentClass.IsVersioned) { foreach (Column col in persistentClass.Version.ColumnIterator) { versionColumnName = col.GetQuotedName(factory.Dialect); break; //only happens once } } else { versionColumnName = null; } #endregion #region WHERE STRING sqlWhereString = !string.IsNullOrEmpty(persistentClass.Where) ? "( " + persistentClass.Where + ") " : null; sqlWhereStringTemplate = sqlWhereString == null ? null : Template.RenderWhereStringTemplate(sqlWhereString, factory.Dialect, factory.SQLFunctionRegistry); #endregion #region PROPERTIES // NH: see consistence with the implementation on EntityMetamodel where we are disabling lazy-properties for no lazy entities bool lazyAvailable = IsInstrumented(EntityMode.Poco) && entityMetamodel.IsLazy; int hydrateSpan = entityMetamodel.PropertySpan; propertyColumnSpans = new int[hydrateSpan]; propertySubclassNames = new string[hydrateSpan]; propertyColumnAliases = new string[hydrateSpan][]; propertyColumnNames = new string[hydrateSpan][]; propertyColumnFormulaTemplates = new string[hydrateSpan][]; propertyUniqueness = new bool[hydrateSpan]; propertySelectable = new bool[hydrateSpan]; propertyColumnUpdateable = new bool[hydrateSpan][]; propertyColumnInsertable = new bool[hydrateSpan][]; var thisClassProperties = new HashSet<Property>(); lazyProperties = new HashedSet<string>(); List<string> lazyNames = new List<string>(); List<int> lazyNumbers = new List<int>(); List<IType> lazyTypes = new List<IType>(); List<string[]> lazyColAliases = new List<string[]>(); i = 0; bool foundFormula = false; foreach (Property prop in persistentClass.PropertyClosureIterator) { thisClassProperties.Add(prop); int span = prop.ColumnSpan; propertyColumnSpans[i] = span; propertySubclassNames[i] = prop.PersistentClass.EntityName; string[] colNames = new string[span]; string[] colAliases = new string[span]; string[] templates = new string[span]; int k = 0; foreach (ISelectable thing in prop.ColumnIterator) { colAliases[k] = thing.GetAlias(factory.Dialect, prop.Value.Table); if (thing.IsFormula) { foundFormula = true; templates[k] = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry); } else { colNames[k] = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry); } k++; } propertyColumnNames[i] = colNames; propertyColumnFormulaTemplates[i] = templates; propertyColumnAliases[i] = colAliases; if (lazyAvailable && prop.IsLazy) { lazyProperties.Add(prop.Name); lazyNames.Add(prop.Name); lazyNumbers.Add(i); lazyTypes.Add(prop.Value.Type); lazyColAliases.Add(colAliases); } propertyColumnUpdateable[i] = prop.Value.ColumnUpdateability; propertyColumnInsertable[i] = prop.Value.ColumnInsertability; propertySelectable[i] = prop.IsSelectable; propertyUniqueness[i] = prop.Value.IsAlternateUniqueKey; i++; } hasFormulaProperties = foundFormula; lazyPropertyColumnAliases = lazyColAliases.ToArray(); lazyPropertyNames = lazyNames.ToArray(); lazyPropertyNumbers = lazyNumbers.ToArray(); lazyPropertyTypes = lazyTypes.ToArray(); #endregion #region SUBCLASS PROPERTY CLOSURE List<string> columns = new List<string>(); List<bool> columnsLazy = new List<bool>(); List<string> aliases = new List<string>(); List<string> formulas = new List<string>(); List<string> formulaAliases = new List<string>(); List<string> formulaTemplates = new List<string>(); List<bool> formulasLazy = new List<bool>(); List<IType> types = new List<IType>(); List<string> names = new List<string>(); List<string> classes = new List<string>(); List<string[]> templates2 = new List<string[]>(); List<string[]> propColumns = new List<string[]>(); List<FetchMode> joinedFetchesList = new List<FetchMode>(); List<CascadeStyle> cascades = new List<CascadeStyle>(); List<bool> definedBySubclass = new List<bool>(); List<int[]> propColumnNumbers = new List<int[]>(); List<int[]> propFormulaNumbers = new List<int[]>(); List<bool> columnSelectables = new List<bool>(); List<bool> propNullables = new List<bool>(); foreach (Property prop in persistentClass.SubclassPropertyClosureIterator) { names.Add(prop.Name); classes.Add(prop.PersistentClass.EntityName); bool isDefinedBySubclass = !thisClassProperties.Contains(prop); definedBySubclass.Add(isDefinedBySubclass); propNullables.Add(prop.IsOptional || isDefinedBySubclass); //TODO: is this completely correct? types.Add(prop.Type); string[] cols = new string[prop.ColumnSpan]; string[] forms = new string[prop.ColumnSpan]; int[] colnos = new int[prop.ColumnSpan]; int[] formnos = new int[prop.ColumnSpan]; int l = 0; bool lazy = prop.IsLazy && lazyAvailable; foreach (ISelectable thing in prop.ColumnIterator) { if (thing.IsFormula) { string template = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry); formnos[l] = formulaTemplates.Count; colnos[l] = -1; formulaTemplates.Add(template); forms[l] = template; formulas.Add(thing.GetText(factory.Dialect)); formulaAliases.Add(thing.GetAlias(factory.Dialect)); formulasLazy.Add(lazy); } else { string colName = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry); colnos[l] = columns.Count; //before add :-) formnos[l] = -1; columns.Add(colName); cols[l] = colName; aliases.Add(thing.GetAlias(factory.Dialect, prop.Value.Table)); columnsLazy.Add(lazy); columnSelectables.Add(prop.IsSelectable); } l++; } propColumns.Add(cols); templates2.Add(forms); propColumnNumbers.Add(colnos); propFormulaNumbers.Add(formnos); joinedFetchesList.Add(prop.Value.FetchMode); cascades.Add(prop.CascadeStyle); } subclassColumnClosure = columns.ToArray(); subclassColumnAliasClosure = aliases.ToArray(); subclassColumnLazyClosure = columnsLazy.ToArray(); subclassColumnSelectableClosure = columnSelectables.ToArray(); subclassFormulaClosure = formulas.ToArray(); subclassFormulaTemplateClosure = formulaTemplates.ToArray(); subclassFormulaAliasClosure = formulaAliases.ToArray(); subclassFormulaLazyClosure = formulasLazy.ToArray(); subclassPropertyNameClosure = names.ToArray(); subclassPropertySubclassNameClosure = classes.ToArray(); subclassPropertyTypeClosure = types.ToArray(); subclassPropertyNullabilityClosure = propNullables.ToArray(); subclassPropertyFormulaTemplateClosure = templates2.ToArray(); subclassPropertyColumnNameClosure = propColumns.ToArray(); subclassPropertyColumnNumberClosure = propColumnNumbers.ToArray(); subclassPropertyFormulaNumberClosure = propFormulaNumbers.ToArray(); subclassPropertyCascadeStyleClosure = cascades.ToArray(); subclassPropertyFetchModeClosure = joinedFetchesList.ToArray(); propertyDefinedOnSubclass = definedBySubclass.ToArray(); #endregion // Handle any filters applied to the class level filterHelper = new FilterHelper(persistentClass.FilterMap, factory.Dialect, factory.SQLFunctionRegistry); temporaryIdTableName = persistentClass.TemporaryIdTableName; temporaryIdTableDDL = persistentClass.TemporaryIdTableDDL; }
public AbstractCollectionPersister(Mapping.Collection collection, ICacheConcurrencyStrategy cache, Configuration cfg, ISessionFactoryImplementor factory) { this.factory = factory; this.cache = cache; if (factory.Settings.IsStructuredCacheEntriesEnabled) { cacheEntryStructure = collection.IsMap ? (ICacheEntryStructure) new StructuredMapCacheEntry() : (ICacheEntryStructure) new StructuredCollectionCacheEntry(); } else { cacheEntryStructure = new UnstructuredCacheEntry(); } dialect = factory.Dialect; sqlExceptionConverter = factory.SQLExceptionConverter; collectionType = collection.CollectionType; role = collection.Role; entityName = collection.OwnerEntityName; ownerPersister = factory.GetEntityPersister(entityName); queryLoaderName = collection.LoaderName; nodeName = collection.NodeName; isMutable = collection.IsMutable; Table table = collection.CollectionTable; fetchMode = collection.Element.FetchMode; elementType = collection.Element.Type; isPrimitiveArray = collection.IsPrimitiveArray; isArray = collection.IsArray; subselectLoadable = collection.IsSubselectLoadable; qualifiedTableName = table.GetQualifiedName(dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName); int spacesSize = 1 + collection.SynchronizedTables.Count; spaces = new string[spacesSize]; int ispa = 0; spaces[ispa++] = qualifiedTableName; foreach (string s in collection.SynchronizedTables) { spaces[ispa++] = s; } sqlOrderByString = collection.OrderBy; hasOrder = sqlOrderByString != null; sqlOrderByStringTemplate = hasOrder ? Template.RenderOrderByStringTemplate(sqlOrderByString, dialect, factory.SQLFunctionRegistry) : null; sqlWhereString = !string.IsNullOrEmpty(collection.Where) ? '(' + collection.Where + ')' : null; hasWhere = sqlWhereString != null; sqlWhereStringTemplate = hasWhere ? Template.RenderWhereStringTemplate(sqlWhereString, dialect, factory.SQLFunctionRegistry) : null; hasOrphanDelete = collection.HasOrphanDelete; int batch = collection.BatchSize; if (batch == -1) { batch = factory.Settings.DefaultBatchFetchSize; } batchSize = batch; isVersioned = collection.IsOptimisticLocked; keyType = collection.Key.Type; int keySpan = collection.Key.ColumnSpan; keyColumnNames = new string[keySpan]; keyColumnAliases = new string[keySpan]; int k = 0; foreach (Column col in collection.Key.ColumnIterator) { keyColumnNames[k] = col.GetQuotedName(dialect); keyColumnAliases[k] = col.GetAlias(dialect); k++; } ISet distinctColumns = new HashedSet(); CheckColumnDuplication(distinctColumns, collection.Key.ColumnIterator); #region Element IValue element = collection.Element; if (!collection.IsOneToMany) { CheckColumnDuplication(distinctColumns, element.ColumnIterator); } string elemNode = collection.ElementNodeName; if (elementType.IsEntityType) { string _entityName = ((EntityType) elementType).GetAssociatedEntityName(); elementPersister = factory.GetEntityPersister(_entityName); if (elemNode == null) { elemNode = cfg.GetClassMapping(_entityName).NodeName; } // NativeSQL: collect element column and auto-aliases } else { elementPersister = null; } elementNodeName = elemNode; int elementSpan = element.ColumnSpan; elementColumnAliases = new string[elementSpan]; elementColumnNames = new string[elementSpan]; elementFormulaTemplates = new string[elementSpan]; elementFormulas = new string[elementSpan]; elementColumnIsSettable = new bool[elementSpan]; elementColumnIsInPrimaryKey = new bool[elementSpan]; bool isPureFormula = true; bool hasNotNullableColumns = false; int j = 0; foreach (ISelectable selectable in element.ColumnIterator) { elementColumnAliases[j] = selectable.GetAlias(dialect); if (selectable.IsFormula) { Formula form = (Formula) selectable; elementFormulaTemplates[j] = form.GetTemplate(dialect, factory.SQLFunctionRegistry); elementFormulas[j] = form.FormulaString; } else { Column col = (Column) selectable; elementColumnNames[j] = col.GetQuotedName(dialect); elementColumnIsSettable[j] = true; elementColumnIsInPrimaryKey[j] = !col.IsNullable; if (!col.IsNullable) { hasNotNullableColumns = true; } isPureFormula = false; } j++; } elementIsPureFormula = isPureFormula; //workaround, for backward compatibility of sets with no //not-null columns, assume all columns are used in the //row locator SQL if (!hasNotNullableColumns) { ArrayHelper.Fill(elementColumnIsInPrimaryKey, true); } #endregion #region INDEX AND ROW SELECT hasIndex = collection.IsIndexed; if (hasIndex) { // NativeSQL: collect index column and auto-aliases IndexedCollection indexedCollection = (IndexedCollection) collection; indexType = indexedCollection.Index.Type; int indexSpan = indexedCollection.Index.ColumnSpan; indexColumnNames = new string[indexSpan]; indexFormulaTemplates = new string[indexSpan]; indexFormulas = new string[indexSpan]; indexColumnIsSettable = new bool[indexSpan]; indexColumnAliases = new string[indexSpan]; bool hasFormula = false; int i = 0; foreach (ISelectable selectable in indexedCollection.Index.ColumnIterator) { indexColumnAliases[i] = selectable.GetAlias(dialect); if (selectable.IsFormula) { Formula indexForm = (Formula) selectable; indexFormulaTemplates[i] = indexForm.GetTemplate(dialect, factory.SQLFunctionRegistry); indexFormulas[i] = indexForm.FormulaString; hasFormula = true; } else { Column indexCol = (Column) selectable; indexColumnNames[i] = indexCol.GetQuotedName(dialect); indexColumnIsSettable[i] = true; } i++; } indexContainsFormula = hasFormula; baseIndex = indexedCollection.IsList ? ((List) indexedCollection).BaseIndex : 0; indexNodeName = indexedCollection.IndexNodeName; CheckColumnDuplication(distinctColumns, indexedCollection.Index.ColumnIterator); } else { indexContainsFormula = false; indexColumnIsSettable = null; indexFormulaTemplates = null; indexFormulas = null; indexType = null; indexColumnNames = null; indexColumnAliases = null; baseIndex = 0; indexNodeName = null; } hasIdentifier = collection.IsIdentified; if (hasIdentifier) { if (collection.IsOneToMany) { throw new MappingException("one-to-many collections with identifiers are not supported."); } IdentifierCollection idColl = (IdentifierCollection) collection; identifierType = idColl.Identifier.Type; Column col = null; foreach (Column column in idColl.Identifier.ColumnIterator) { col = column; break; } identifierColumnName = col.GetQuotedName(dialect); identifierColumnAlias = col.GetAlias(dialect); identifierGenerator = idColl.Identifier.CreateIdentifierGenerator(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName, null); // NH see : identityDelegate declaration IPostInsertIdentifierGenerator pig = (identifierGenerator as IPostInsertIdentifierGenerator); if (pig != null) { identityDelegate = pig.GetInsertGeneratedIdentifierDelegate(this, Factory, UseGetGeneratedKeys()); } else { identityDelegate = null; } CheckColumnDuplication(distinctColumns, idColl.Identifier.ColumnIterator); } else { identifierType = null; identifierColumnName = null; identifierColumnAlias = null; identifierGenerator = null; identityDelegate = null; } #endregion #region GENERATE THE SQL // NH Different behavior : for the Insert SQL we are managing isPostInsertIdentifier (not supported in H3.2.5) if (collection.CustomSQLInsert == null) { if (!IsIdentifierAssignedByInsert) { sqlInsertRowString = GenerateInsertRowString(); } else { sqlInsertRowString = GenerateIdentityInsertRowString(); } insertCallable = false; insertCheckStyle = ExecuteUpdateResultCheckStyle.Count; } else { SqlType[] parmsTypes = GenerateInsertRowString().ParameterTypes; sqlInsertRowString = new SqlCommandInfo(collection.CustomSQLInsert, parmsTypes); insertCallable = collection.IsCustomInsertCallable; insertCheckStyle = collection.CustomSQLInsertCheckStyle ?? ExecuteUpdateResultCheckStyle.DetermineDefault(collection.CustomSQLInsert, insertCallable); } sqlUpdateRowString = GenerateUpdateRowString(); if (collection.CustomSQLUpdate == null) { updateCallable = false; updateCheckStyle = ExecuteUpdateResultCheckStyle.Count; } else { sqlUpdateRowString = new SqlCommandInfo(collection.CustomSQLUpdate, sqlUpdateRowString.ParameterTypes); updateCallable = collection.IsCustomUpdateCallable; updateCheckStyle = collection.CustomSQLUpdateCheckStyle ?? ExecuteUpdateResultCheckStyle.DetermineDefault(collection.CustomSQLUpdate, updateCallable); } sqlDeleteRowString = GenerateDeleteRowString(); if (collection.CustomSQLDelete == null) { deleteCallable = false; deleteCheckStyle = ExecuteUpdateResultCheckStyle.None; } else { sqlDeleteRowString = new SqlCommandInfo(collection.CustomSQLDelete, sqlDeleteRowString.ParameterTypes); deleteCallable = collection.IsCustomDeleteCallable; deleteCheckStyle = ExecuteUpdateResultCheckStyle.None; } sqlDeleteString = GenerateDeleteString(); if (collection.CustomSQLDeleteAll == null) { deleteAllCallable = false; deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.None; } else { sqlDeleteString = new SqlCommandInfo(collection.CustomSQLDeleteAll, sqlDeleteString.ParameterTypes); deleteAllCallable = collection.IsCustomDeleteAllCallable; deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.None; } isCollectionIntegerIndex = collection.IsIndexed && !collection.IsMap; sqlDetectRowByIndexString = GenerateDetectRowByIndexString(); sqlDetectRowByElementString = GenerateDetectRowByElementString(); sqlSelectRowByIndexString = GenerateSelectRowByIndexString(); LogStaticSQL(); #endregion isLazy = collection.IsLazy; isExtraLazy = collection.ExtraLazy; isInverse = collection.IsInverse; if (collection.IsArray) { elementClass = ((Array) collection).ElementClass; } else { // for non-arrays, we don't need to know the element class elementClass = null; } if (elementType.IsComponentType) { elementPropertyMapping = new CompositeElementPropertyMapping(elementColumnNames, elementFormulaTemplates, (IAbstractComponentType) elementType, factory); } else if (!elementType.IsEntityType) { elementPropertyMapping = new ElementPropertyMapping(elementColumnNames, elementType); } else { elementPropertyMapping = elementPersister as IPropertyMapping; if (elementPropertyMapping == null) { elementPropertyMapping = new ElementPropertyMapping(elementColumnNames, elementType); } } // Handle any filters applied to this collection filterHelper = new FilterHelper(collection.FilterMap, dialect, factory.SQLFunctionRegistry); // Handle any filters applied to this collection for many-to-many manyToManyFilterHelper = new FilterHelper(collection.ManyToManyFilterMap, dialect, factory.SQLFunctionRegistry); manyToManyWhereString = !string.IsNullOrEmpty(collection.ManyToManyWhere) ? "( " + collection.ManyToManyWhere + " )" : null; manyToManyWhereTemplate = manyToManyWhereString == null ? null : Template.RenderWhereStringTemplate(manyToManyWhereString, factory.Dialect, factory.SQLFunctionRegistry); manyToManyOrderByString = collection.ManyToManyOrdering; manyToManyOrderByTemplate = manyToManyOrderByString == null ? null : Template.RenderOrderByStringTemplate(manyToManyOrderByString, factory.Dialect, factory.SQLFunctionRegistry); InitCollectionPropertyMap(); }