📄 singletableentitypersister.cs
字号:
using System;
using System.Collections.Generic;
using System.Text;
using Iesi.Collections.Generic;
using NHibernate.Cache;
using NHibernate.Engine;
using NHibernate.Mapping;
using NHibernate.SqlCommand;
using NHibernate.Type;
using NHibernate.Util;
namespace NHibernate.Persister.Entity
{
/// <summary>
/// Default implementation of the <c>ClassPersister</c> interface. Implements the
/// "table-per-class hierarchy" mapping strategy for an entity class.
/// </summary>
public class SingleTableEntityPersister : AbstractEntityPersister, IQueryable
{
// the class hierarchy structure
private readonly int joinSpan;
private readonly string[] qualifiedTableNames;
private readonly bool[] isInverseTable;
private readonly bool[] isNullableTable;
private readonly string[][] keyColumnNames;
private readonly bool[] cascadeDeleteEnabled;
private readonly bool hasSequentialSelects;
private readonly string[] spaces;
private readonly string[] subclassClosure;
private readonly string[] subclassTableNameClosure;
private readonly bool[] subclassTableIsLazyClosure;
private readonly bool[] isInverseSubclassTable;
private readonly bool[] isNullableSubclassTable;
private readonly bool[] subclassTableSequentialSelect;
private readonly string[][] subclassTableKeyColumnClosure;
private readonly bool[] isClassOrSuperclassTable;
// properties of this class, including inherited properties
private readonly int[] propertyTableNumbers;
// the closure of all columns used by the entire hierarchy including
// subclasses and superclasses of this class
private readonly int[] subclassPropertyTableNumberClosure;
private readonly int[] subclassColumnTableNumberClosure;
private readonly int[] subclassFormulaTableNumberClosure;
// discriminator column
private readonly Dictionary<object, string> subclassesByDiscriminatorValue = new Dictionary<object, string>();
private readonly bool forceDiscriminator;
private readonly string discriminatorColumnName;
private readonly string discriminatorFormula;
private readonly string discriminatorFormulaTemplate;
private readonly string discriminatorAlias;
private readonly IType discriminatorType;
private readonly string discriminatorSQLValue;
private readonly object discriminatorValue;
private readonly bool discriminatorInsertable;
private readonly string[] constraintOrderedTableNames;
private readonly string[][] constraintOrderedKeyColumnNames;
//private readonly IDictionary propertyTableNumbersByName = new Hashtable();
private readonly Dictionary<string, int> propertyTableNumbersByNameAndSubclass = new Dictionary<string, int>();
private readonly Dictionary<string, SqlString> sequentialSelectStringsByEntityName = new Dictionary<string, SqlString>();
private static readonly object NullDiscriminator = new object();
private static readonly object NotNullDiscriminator = new object();
public SingleTableEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache,
ISessionFactoryImplementor factory, IMapping mapping)
: base(persistentClass, cache, factory)
{
#region CLASS + TABLE
joinSpan = persistentClass.JoinClosureSpan + 1;
qualifiedTableNames = new string[joinSpan];
isInverseTable = new bool[joinSpan];
isNullableTable = new bool[joinSpan];
keyColumnNames = new string[joinSpan][];
Table table = persistentClass.RootTable;
qualifiedTableNames[0] =
table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName);
isInverseTable[0] = false;
isNullableTable[0] = false;
keyColumnNames[0] = IdentifierColumnNames;
cascadeDeleteEnabled = new bool[joinSpan];
// Custom sql
customSQLInsert = new SqlString[joinSpan];
customSQLUpdate = new SqlString[joinSpan];
customSQLDelete = new SqlString[joinSpan];
insertCallable = new bool[joinSpan];
updateCallable = new bool[joinSpan];
deleteCallable = new bool[joinSpan];
insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
customSQLInsert[0] = persistentClass.CustomSQLInsert;
insertCallable[0] = customSQLInsert[0] != null && persistentClass.IsCustomInsertCallable;
insertResultCheckStyles[0] = persistentClass.CustomSQLInsertCheckStyle
?? ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLInsert[0], insertCallable[0]);
customSQLUpdate[0] = persistentClass.CustomSQLUpdate;
updateCallable[0] = customSQLUpdate[0] != null && persistentClass.IsCustomUpdateCallable;
updateResultCheckStyles[0] = persistentClass.CustomSQLUpdateCheckStyle
?? ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLUpdate[0], updateCallable[0]);
customSQLDelete[0] = persistentClass.CustomSQLDelete;
deleteCallable[0] = customSQLDelete[0] != null && persistentClass.IsCustomDeleteCallable;
deleteResultCheckStyles[0] = persistentClass.CustomSQLDeleteCheckStyle
?? ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLDelete[0], deleteCallable[0]);
#endregion
#region JOINS
int j = 1;
foreach (Join join in persistentClass.JoinClosureIterator)
{
qualifiedTableNames[j] = join.Table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName);
isInverseTable[j] = join.IsInverse;
isNullableTable[j] = join.IsOptional;
cascadeDeleteEnabled[j] = join.Key.IsCascadeDeleteEnabled && factory.Dialect.SupportsCascadeDelete;
customSQLInsert[j] = join.CustomSQLInsert;
insertCallable[j] = customSQLInsert[j] != null && join.IsCustomInsertCallable;
insertResultCheckStyles[j] = join.CustomSQLInsertCheckStyle
??
ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLInsert[j], insertCallable[j]);
customSQLUpdate[j] = join.CustomSQLUpdate;
updateCallable[j] = customSQLUpdate[j] != null && join.IsCustomUpdateCallable;
updateResultCheckStyles[j] = join.CustomSQLUpdateCheckStyle
??
ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLUpdate[j], updateCallable[j]);
customSQLDelete[j] = join.CustomSQLDelete;
deleteCallable[j] = customSQLDelete[j] != null && join.IsCustomDeleteCallable;
deleteResultCheckStyles[j] = join.CustomSQLDeleteCheckStyle
??
ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLDelete[j], deleteCallable[j]);
IEnumerable<Column> enumerableKeyCol = new SafetyEnumerable<Column>(join.Key.ColumnIterator);
List<string> kcName = new List<string>(join.Key.ColumnSpan);
foreach (Column col in enumerableKeyCol)
kcName.Add(col.GetQuotedName(factory.Dialect));
keyColumnNames[j] = kcName.ToArray();
j++;
}
constraintOrderedTableNames = new string[qualifiedTableNames.Length];
constraintOrderedKeyColumnNames = new string[qualifiedTableNames.Length][];
for (int i = qualifiedTableNames.Length - 1, position = 0; i >= 0; i--, position++)
{
constraintOrderedTableNames[position] = qualifiedTableNames[i];
constraintOrderedKeyColumnNames[position] = keyColumnNames[i];
}
spaces = ArrayHelper.Join(qualifiedTableNames, ArrayHelper.ToStringArray(persistentClass.SynchronizedTables));
bool lazyAvailable = IsInstrumented(EntityMode.Poco);
bool hasDeferred = false;
List<string> subclassTables = new List<string>();
List<string[]> joinKeyColumns = new List<string[]>();
List<bool> isConcretes = new List<bool>();
List<bool> isDeferreds = new List<bool>();
List<bool> isInverses = new List<bool>();
List<bool> isNullables = new List<bool>();
List<bool> isLazies = new List<bool>();
subclassTables.Add(qualifiedTableNames[0]);
joinKeyColumns.Add(IdentifierColumnNames);
isConcretes.Add(true);
isDeferreds.Add(false);
isInverses.Add(false);
isNullables.Add(false);
isLazies.Add(false);
foreach (Join join in persistentClass.SubclassJoinClosureIterator)
{
isConcretes.Add(persistentClass.IsClassOrSuperclassJoin(join));
isDeferreds.Add(join.IsSequentialSelect);
isInverses.Add(join.IsInverse);
isNullables.Add(join.IsOptional);
isLazies.Add(lazyAvailable && join.IsLazy);
if (join.IsSequentialSelect && !persistentClass.IsClassOrSuperclassJoin(join))
hasDeferred = true;
subclassTables.Add(join.Table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName));
IEnumerable<Column> enumerableKeyCol = new SafetyEnumerable<Column>(join.Key.ColumnIterator);
List<string> keyCols = new List<string>(join.Key.ColumnSpan);
foreach (Column col in enumerableKeyCol)
keyCols.Add(col.GetQuotedName(factory.Dialect));
joinKeyColumns.Add(keyCols.ToArray());
}
subclassTableSequentialSelect = isDeferreds.ToArray();
subclassTableNameClosure = subclassTables.ToArray();
subclassTableIsLazyClosure = isLazies.ToArray();
subclassTableKeyColumnClosure = joinKeyColumns.ToArray();
isClassOrSuperclassTable = isConcretes.ToArray();
isInverseSubclassTable = isInverses.ToArray();
isNullableSubclassTable = isNullables.ToArray();
hasSequentialSelects = hasDeferred;
#endregion
#region DISCRIMINATOR
if (persistentClass.IsPolymorphic)
{
IValue discrimValue = persistentClass.Discriminator;
if (discrimValue == null)
throw new MappingException("Discriminator mapping required for single table polymorphic persistence");
forceDiscriminator = persistentClass.IsForceDiscriminator;
IEnumerator<ISelectable> iSel = discrimValue.ColumnIterator.GetEnumerator();
iSel.MoveNext();
ISelectable selectable = iSel.Current;
if (discrimValue.HasFormula)
{
Formula formula = (Formula)selectable;
discriminatorFormula = formula.FormulaString;
discriminatorFormulaTemplate = formula.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
discriminatorColumnName = null;
discriminatorAlias = Discriminator_Alias;
}
else
{
Column column = (Column)selectable;
discriminatorColumnName = column.GetQuotedName(factory.Dialect);
discriminatorAlias = column.GetAlias(factory.Dialect, persistentClass.RootTable);
discriminatorFormula = null;
discriminatorFormulaTemplate = null;
}
discriminatorType = persistentClass.Discriminator.Type;
if (persistentClass.IsDiscriminatorValueNull)
{
discriminatorValue = NullDiscriminator;
discriminatorSQLValue = InFragment.Null;
discriminatorInsertable = false;
}
else if (persistentClass.IsDiscriminatorValueNotNull)
{
discriminatorValue = NotNullDiscriminator;
discriminatorSQLValue = InFragment.NotNull;
discriminatorInsertable = false;
}
else
{
discriminatorInsertable = persistentClass.IsDiscriminatorInsertable && !discrimValue.HasFormula;
try
{
IDiscriminatorType dtype = (IDiscriminatorType)discriminatorType;
discriminatorValue = dtype.StringToObject(persistentClass.DiscriminatorValue);
discriminatorSQLValue = dtype.ObjectToSQLString(discriminatorValue, factory.Dialect);
}
catch (InvalidCastException cce)
{
throw new MappingException(
string.Format("Illegal discriminator type: {0} of entity {1}", discriminatorType.Name, persistentClass.EntityName), cce);
}
catch (Exception e)
{
throw new MappingException("Could not format discriminator value to SQL string of entity " + persistentClass.EntityName, e);
}
}
}
else
{
forceDiscriminator = false;
discriminatorInsertable = false;
discriminatorColumnName = null;
discriminatorAlias = null;
discriminatorType = null;
discriminatorValue = null;
discriminatorSQLValue = null;
discriminatorFormula = null;
discriminatorFormulaTemplate = null;
}
#endregion
#region PROPERTIES
propertyTableNumbers = new int[PropertySpan];
int i2 = 0;
foreach (Property prop in persistentClass.PropertyClosureIterator)
{
propertyTableNumbers[i2++] = persistentClass.GetJoinNumber(prop);
}
List<int> columnJoinNumbers = new List<int>();
List<int> formulaJoinedNumbers = new List<int>();
List<int> propertyJoinNumbers = new List<int>();
foreach (Property prop in persistentClass.SubclassPropertyClosureIterator)
{
int join = persistentClass.GetJoinNumber(prop);
propertyJoinNumbers.Add(join);
//propertyTableNumbersByName.put( prop.getName(), join );
propertyTableNumbersByNameAndSubclass[prop.PersistentClass.EntityName + '.' + prop.Name] = join;
foreach (ISelectable thing in prop.ColumnIterator)
{
if (thing.IsFormula)
formulaJoinedNumbers.Add(join);
else
columnJoinNumbers.Add(join);
}
}
subclassColumnTableNumberClosure = columnJoinNumbers.ToArray();
subclassFormulaTableNumberClosure = formulaJoinedNumbers.ToArray();
subclassPropertyTableNumberClosure = propertyJoinNumbers.ToArray();
int subclassSpan = persistentClass.SubclassSpan + 1;
subclassClosure = new string[subclassSpan];
subclassClosure[0] = EntityName;
if (persistentClass.IsPolymorphic)
subclassesByDiscriminatorValue[discriminatorValue] = EntityName;
#endregion
#region SUBCLASSES
if (persistentClass.IsPolymorphic)
{
int k = 1;
foreach (Subclass sc in persistentClass.SubclassIterator)
{
subclassClosure[k++] = sc.EntityName;
if (sc.IsDiscriminatorValueNull)
{
subclassesByDiscriminatorValue[NullDiscriminator] = sc.EntityName;
}
else if (sc.IsDiscriminatorValueNotNull)
{
subclassesByDiscriminatorValue[NotNullDiscriminator] = sc.EntityName;
}
else
{
if (discriminatorType == null)
throw new MappingException("Not available discriminator type of entity " + persistentClass.EntityName);
try
{
IDiscriminatorType dtype = (IDiscriminatorType)discriminatorType;
subclassesByDiscriminatorValue[dtype.StringToObject(sc.DiscriminatorValue)] = sc.EntityName;
}
catch (InvalidCastException cce)
{
throw new MappingException(
string.Format("Illegal discriminator type: {0} of entity {1}", discriminatorType.Name, persistentClass.EntityName), cce);
}
catch (Exception e)
{
throw new MappingException("Error parsing discriminator value of entity " + persistentClass.EntityName, e);
}
}
}
}
#endregion
InitLockers();
InitSubclassPropertyAliasesMap(persistentClass);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -