📄 abstractcollectionpersister.cs
字号:
using System;
using System.Collections;
using System.Data;
using System.Text;
using Iesi.Collections;
using log4net;
using NHibernate.AdoNet;
using NHibernate.Cache;
using NHibernate.Cache.Entry;
using NHibernate.Cfg;
using NHibernate.Collection;
using NHibernate.Engine;
using NHibernate.Exceptions;
using NHibernate.Id;
using NHibernate.Impl;
using NHibernate.Loader.Collection;
using NHibernate.Mapping;
using NHibernate.Metadata;
using NHibernate.Persister.Entity;
using NHibernate.SqlCommand;
using NHibernate.Type;
using NHibernate.Util;
using Array=NHibernate.Mapping.Array;
using System.Collections.Generic;
using NHibernate.SqlTypes;
using System.Data.Common;
namespace NHibernate.Persister.Collection
{
/// <summary>
/// Summary description for AbstractCollectionPersister.
/// </summary>
public abstract class AbstractCollectionPersister : ICollectionMetadata, ISqlLoadableCollection
{
private readonly string role;
#region SQL statements
private readonly SqlCommandInfo sqlDeleteString;
private readonly SqlCommandInfo sqlInsertRowString;
private readonly SqlCommandInfo sqlUpdateRowString;
private readonly SqlCommandInfo sqlDeleteRowString;
private readonly SqlString sqlSelectSizeString;
private readonly SqlString sqlSelectRowByIndexString;
private readonly SqlString sqlDetectRowByIndexString;
private readonly SqlString sqlDetectRowByElementString;
private readonly string sqlOrderByString;
protected readonly string sqlWhereString;
private readonly string sqlOrderByStringTemplate;
private readonly string sqlWhereStringTemplate;
private readonly bool hasOrder;
private readonly bool hasWhere;
private readonly int baseIndex;
private readonly string nodeName;
private readonly string elementNodeName;
private readonly string indexNodeName;
protected internal bool indexContainsFormula;
protected internal bool elementIsPureFormula;
#endregion
#region Types
private readonly IType keyType;
private readonly IType indexType;
private readonly IType elementType;
private readonly IType identifierType;
#endregion
#region Columns
protected readonly string[] keyColumnNames;
protected readonly string[] indexColumnNames;
protected readonly string[] indexFormulaTemplates;
protected readonly string[] indexFormulas;
protected readonly bool[] indexColumnIsSettable;
protected readonly string[] elementColumnNames;
protected readonly string[] elementFormulaTemplates;
protected readonly string[] elementFormulas;
protected readonly bool[] elementColumnIsSettable;
protected readonly bool[] elementColumnIsInPrimaryKey;
private readonly string[] indexColumnAliases;
protected readonly string[] elementColumnAliases;
private readonly string[] keyColumnAliases;
private readonly string identifierColumnName;
private readonly string identifierColumnAlias;
#endregion
protected readonly string qualifiedTableName;
private readonly string queryLoaderName;
private readonly bool isPrimitiveArray;
private readonly bool isArray;
private readonly bool hasIndex;
protected readonly bool hasIdentifier;
protected readonly bool isPostInsertIdentifier;
private readonly bool isLazy;
private readonly bool isExtraLazy;
private readonly bool isInverse;
private readonly bool isMutable;
private readonly bool isVersioned;
protected readonly int batchSize;
private readonly FetchMode fetchMode;
private readonly bool hasOrphanDelete;
private readonly bool subselectLoadable;
#region Extra information about the element type
private readonly System.Type elementClass;
private readonly string entityName;
#endregion
private readonly Dialect.Dialect dialect;
private readonly ISQLExceptionConverter sqlExceptionConverter;
private readonly ISessionFactoryImplementor factory;
private readonly IEntityPersister ownerPersister;
private readonly IIdentifierGenerator identifierGenerator;
private readonly IPropertyMapping elementPropertyMapping;
private readonly IEntityPersister elementPersister;
private readonly ICacheConcurrencyStrategy cache;
private readonly CollectionType collectionType;
private ICollectionInitializer initializer;
private readonly ICacheEntryStructure cacheEntryStructure;
// dynamic filters for the collection
private readonly FilterHelper filterHelper;
#region Dynamic filters specifically for many-to-many inside the collection
private readonly FilterHelper manyToManyFilterHelper;
private readonly string manyToManyWhereString;
private readonly string manyToManyWhereTemplate;
private readonly string manyToManyOrderByString;
private readonly string manyToManyOrderByTemplate;
#endregion
#region Custom SQL
private readonly bool insertCallable;
private readonly bool updateCallable;
private readonly bool deleteCallable;
private readonly bool deleteAllCallable;
private readonly ExecuteUpdateResultCheckStyle insertCheckStyle;
private readonly ExecuteUpdateResultCheckStyle updateCheckStyle;
private readonly ExecuteUpdateResultCheckStyle deleteCheckStyle;
private readonly ExecuteUpdateResultCheckStyle deleteAllCheckStyle;
#endregion
private readonly string[] spaces;
private readonly IDictionary collectionPropertyColumnAliases = new Hashtable();
private readonly IDictionary collectionPropertyColumnNames = new Hashtable();
private static readonly ILog log = LogManager.GetLogger(typeof(ICollectionPersister));
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.DefaultSchema);
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);
isPostInsertIdentifier = (identifierGenerator as IPostInsertIdentifierGenerator) != null;
CheckColumnDuplication(distinctColumns, idColl.Identifier.ColumnIterator);
}
else
{
identifierType = null;
identifierColumnName = null;
identifierColumnAlias = null;
identifierGenerator = null;
}
#endregion
#region GENERATE THE SQL
//shouldInsertIdentifier = hasIdentifier && !(identifierGenerator is NHibernate.Id.IdentityGenerator);
sqlInsertRowString = GenerateInsertRowString();
if (collection.CustomSQLInsert == null)
{
insertCallable = false;
insertCheckStyle = ExecuteUpdateResultCheckStyle.Count;
}
else
{
sqlInsertRowString = new SqlCommandInfo(collection.CustomSQLInsert, sqlInsertRowString.ParameterTypes);
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;
}
sqlSelectSizeString = GenerateSelectSizeString(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
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -