📄 abstractentitypersister.cs
字号:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Text;
using Iesi.Collections;
using Iesi.Collections.Generic;
using log4net;
using NHibernate.AdoNet;
using NHibernate.Cache;
using NHibernate.Cache.Entry;
using NHibernate.Dialect.Lock;
using NHibernate.Engine;
using NHibernate.Exceptions;
using NHibernate.Id;
using NHibernate.Id.Insert;
using NHibernate.Impl;
using NHibernate.Intercept;
using NHibernate.Loader.Entity;
using NHibernate.Mapping;
using NHibernate.Metadata;
using NHibernate.Properties;
using NHibernate.SqlCommand;
using NHibernate.Tuple;
using NHibernate.Tuple.Entity;
using NHibernate.Type;
using NHibernate.Util;
using Array=System.Array;
using Property=NHibernate.Mapping.Property;
using NHibernate.SqlTypes;
namespace NHibernate.Persister.Entity
{
/// <summary>
/// Superclass for built-in mapping strategies. Implements functionalty common to both mapping
/// strategies
/// </summary>
/// <remarks>
/// May be considered an immutable view of the mapping object
/// </remarks>
public abstract class AbstractEntityPersister : IOuterJoinLoadable, IQueryable, IClassMetadata,
IUniqueKeyLoadable, ISqlLoadable, ILazyPropertyInitializer,
IPostInsertIdentityPersister, ILockable
{
#region InclusionChecker
protected internal interface IInclusionChecker
{
bool IncludeProperty(int propertyNumber);
}
private class NoneInclusionChecker : IInclusionChecker
{
private readonly ValueInclusion[] inclusions;
public NoneInclusionChecker(ValueInclusion[] inclusions)
{
this.inclusions = inclusions;
}
// TODO : currently we really do not handle ValueInclusion.PARTIAL...
// ValueInclusion.PARTIAL would indicate parts of a component need to
// be included in the select; currently we then just render the entire
// component into the select clause in that case.
public bool IncludeProperty(int propertyNumber)
{
return inclusions[propertyNumber] != ValueInclusion.None;
}
}
private class FullInclusionChecker : IInclusionChecker
{
private readonly bool[] includeProperty;
public FullInclusionChecker(bool[] includeProperty)
{
this.includeProperty = includeProperty;
}
public bool IncludeProperty(int propertyNumber)
{
return includeProperty[propertyNumber];
}
}
#endregion
private class GeneratedIdentifierBinder : IBinder
{
private readonly object[] fields;
private readonly bool[] notNull;
private readonly ISessionImplementor session;
private readonly object entity;
private readonly AbstractEntityPersister entityPersister;
public GeneratedIdentifierBinder(object[] fields, bool[] notNull, ISessionImplementor session, object entity, AbstractEntityPersister entityPersister)
{
this.fields = fields;
this.notNull = notNull;
this.session = session;
this.entity = entity;
this.entityPersister = entityPersister;
}
public object Entity
{
get { return entity; }
}
public virtual void BindValues(IDbCommand ps)
{
entityPersister.Dehydrate(null, fields, notNull, entityPersister.propertyColumnInsertable, 0, ps, session);
}
}
private static readonly ILog log = LogManager.GetLogger(typeof(AbstractEntityPersister));
public const string EntityClass = "class";
protected const string Discriminator_Alias = "clazz_";
private readonly ISessionFactoryImplementor factory;
private readonly ICacheConcurrencyStrategy cache;
private readonly bool isLazyPropertiesCacheable;
private readonly ICacheEntryStructure cacheEntryStructure;
private readonly EntityMetamodel entityMetamodel;
private readonly Dictionary<System.Type, string> entityNameBySubclass = new Dictionary<System.Type, string>();
private readonly string[] rootTableKeyColumnNames;
private readonly string[] identifierAliases;
private readonly int identifierColumnSpan;
private readonly string versionColumnName;
private readonly bool hasFormulaProperties;
private readonly int batchSize;
private readonly bool hasSubselectLoadableCollections;
protected internal string rowIdName;
private readonly ISet<string> lazyProperties;
private readonly string sqlWhereString;
private readonly string sqlWhereStringTemplate;
#region Information about properties of this class
//including inherited properties
//(only really needed for updatable/insertable properties)
private readonly int[] propertyColumnSpans;
// the names of the columns for the property
// the array is indexed as propertyColumnNames[propertyIndex][columnIndex] = "columnName"
private readonly string[] propertySubclassNames;
private readonly string[][] propertyColumnAliases;
private readonly string[][] propertyColumnNames;
// the alias names for the columns of the property. This is used in the AS portion for
// selecting a column. It is indexed the same as propertyColumnNames
// private readonly string[ ] propertyFormulaTemplates;
private readonly string[][] propertyColumnFormulaTemplates;
private readonly bool[][] propertyColumnUpdateable;
private readonly bool[][] propertyColumnInsertable;
private readonly bool[] propertyUniqueness;
private readonly bool[] propertySelectable;
#endregion
#region Information about lazy properties of this class
private readonly string[] lazyPropertyNames;
private readonly int[] lazyPropertyNumbers;
private readonly IType[] lazyPropertyTypes;
private readonly string[][] lazyPropertyColumnAliases;
#endregion
#region Information about all properties in class hierarchy
private readonly string[] subclassPropertyNameClosure;
private readonly string[] subclassPropertySubclassNameClosure;
private readonly IType[] subclassPropertyTypeClosure;
private readonly string[][] subclassPropertyFormulaTemplateClosure;
private readonly string[][] subclassPropertyColumnNameClosure;
private readonly FetchMode[] subclassPropertyFetchModeClosure;
private readonly bool[] subclassPropertyNullabilityClosure;
protected bool[] propertyDefinedOnSubclass;
private readonly int[][] subclassPropertyColumnNumberClosure;
private readonly int[][] subclassPropertyFormulaNumberClosure;
private readonly CascadeStyle[] subclassPropertyCascadeStyleClosure;
#endregion
#region Information about all columns/formulas in class hierarchy
private readonly string[] subclassColumnClosure;
private readonly bool[] subclassColumnLazyClosure;
private readonly string[] subclassColumnAliasClosure;
private readonly bool[] subclassColumnSelectableClosure;
private readonly string[] subclassFormulaClosure;
private readonly string[] subclassFormulaTemplateClosure;
private readonly string[] subclassFormulaAliasClosure;
private readonly bool[] subclassFormulaLazyClosure;
#endregion
#region Dynamic filters attached to the class-level
private readonly FilterHelper filterHelper;
#endregion
private readonly Hashtable uniqueKeyLoaders = new Hashtable();
private readonly Dictionary<LockMode, ILockingStrategy> lockers = new Dictionary<LockMode, ILockingStrategy>();
private readonly Dictionary<string, IUniqueEntityLoader> loaders = new Dictionary<string, IUniqueEntityLoader>();
#region SQL strings
private SqlString sqlVersionSelectString;
private SqlString sqlSnapshotSelectString;
private SqlString sqlLazySelectString;
private SqlCommandInfo sqlIdentityInsertString;
private SqlCommandInfo sqlUpdateByRowIdString;
private SqlCommandInfo sqlLazyUpdateByRowIdString;
private SqlCommandInfo[] sqlDeleteStrings;
private SqlCommandInfo[] sqlInsertStrings;
private SqlCommandInfo[] sqlUpdateStrings;
private SqlCommandInfo[] sqlLazyUpdateStrings;
private SqlString sqlInsertGeneratedValuesSelectString;
private SqlString sqlUpdateGeneratedValuesSelectString;
private string identitySelectString;
#endregion
#region Custom SQL
protected internal bool[] insertCallable;
protected internal bool[] updateCallable;
protected internal bool[] deleteCallable;
protected internal SqlString[] customSQLInsert;
protected internal SqlString[] customSQLUpdate;
protected internal SqlString[] customSQLDelete;
protected internal ExecuteUpdateResultCheckStyle[] insertResultCheckStyles;
protected internal ExecuteUpdateResultCheckStyle[] updateResultCheckStyles;
protected internal ExecuteUpdateResultCheckStyle[] deleteResultCheckStyles;
#endregion
private IInsertGeneratedIdentifierDelegate identityDelegate;
private bool[] tableHasColumns;
private readonly string loaderName;
private IUniqueEntityLoader queryLoader;
private readonly string temporaryIdTableName;
private readonly string temporaryIdTableDDL;
private readonly Dictionary<string, string[]> subclassPropertyAliases = new Dictionary<string, string[]>();
private readonly Dictionary<string, string[]> subclassPropertyColumnNames = new Dictionary<string, string[]>();
protected readonly BasicEntityPropertyMapping propertyMapping;
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;
}
}
int batch = persistentClass.BatchSize;
if (batch == -1)
batch = factory.Settings.DefaultBatchFetchSize;
batchSize = batch;
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
bool lazyAvailable = IsInstrumented(EntityMode.Poco);
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][];
ISet thisClassProperties = new HashedSet();
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -