Skip to content

Refactored DefaultEntityAliases to avoid unnecessary calculations #1482

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 15, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 83 additions & 90 deletions src/NHibernate/Loader/DefaultEntityAliases.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System.Collections.Generic;
using NHibernate.Persister.Entity;
using NHibernate.Util;

namespace NHibernate.Loader
{
Expand All @@ -10,48 +9,75 @@ namespace NHibernate.Loader
/// </summary>
public class DefaultEntityAliases : IEntityAliases
{
private readonly string[] suffixedKeyColumns;
private readonly string[] suffixedVersionColumn;
private readonly string[][] suffixedPropertyColumns;
private readonly string suffixedDiscriminatorColumn;
private readonly string suffix;
private readonly string rowIdAlias;
private readonly IDictionary<string, string[]> userProvidedAliases;
private readonly string _suffix;
private readonly IDictionary<string, string[]> _userProvidedAliases;
private string _rowIdAlias;

public DefaultEntityAliases(ILoadable persister, string suffix)
: this(CollectionHelper.EmptyDictionary<string, string[]>(), persister, suffix) {}
: this(null, persister, suffix)
{
}

/// <summary>
/// Calculate and cache select-clause suffixes.
/// Calculate and cache select-clause aliases.
/// </summary>
public DefaultEntityAliases(IDictionary<string, string[]> userProvidedAliases, ILoadable persister, string suffix)
{
this.suffix = suffix;
this.userProvidedAliases = userProvidedAliases;
_suffix = suffix;
_userProvidedAliases = userProvidedAliases?.Count > 0 ? userProvidedAliases : null;

string[] keyColumnsCandidates = GetUserProvidedAliases(persister.IdentifierPropertyName, null);
if (keyColumnsCandidates == null)
{
suffixedKeyColumns = GetUserProvidedAliases(EntityPersister.EntityID, GetIdentifierAliases(persister, suffix));
}
else
{
suffixedKeyColumns = keyColumnsCandidates;
}
Intern(suffixedKeyColumns);
SuffixedKeyAliases = DetermineKeyAliases(persister);
SuffixedPropertyAliases = DeterminePropertyAliases(persister);
SuffixedDiscriminatorAlias = DetermineDiscriminatorAlias(persister);

SuffixedVersionAliases = persister.IsVersioned ? SuffixedPropertyAliases[persister.VersionProperty] : null;
//rowIdAlias is generated on demand in property
}

suffixedPropertyColumns = GetSuffixedPropertyAliases(persister);
suffixedDiscriminatorColumn =
GetUserProvidedAlias(AbstractEntityPersister.EntityClass, GetDiscriminatorAlias(persister, suffix));
if (persister.IsVersioned)
/// <summary>
/// Returns aliases for subclass persister
/// </summary>
public string[][] GetSuffixedPropertyAliases(ILoadable persister)
{
if (_userProvidedAliases == null)
return GetAllPropertyAliases(persister);

var propertyNames = persister.PropertyNames;
var suffixedPropertyAliases = new string[propertyNames.Length][];
for (var i = 0; i < propertyNames.Length; i++)
{
suffixedVersionColumn = suffixedPropertyColumns[persister.VersionProperty];
suffixedPropertyAliases[i] =
SafeGetUserProvidedAliases(propertyNames[i]) ??
GetPropertyAliases(persister, i);
}
else

return suffixedPropertyAliases;
}

public string[] SuffixedVersionAliases { get; }

public string[][] SuffixedPropertyAliases { get; }

public string SuffixedDiscriminatorAlias { get; }

public string[] SuffixedKeyAliases { get; }

// TODO: not visible to the user!
public string RowIdAlias => _rowIdAlias ?? (_rowIdAlias = Loadable.RowIdAlias + _suffix);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think none of us have realized we were changing a class which instances can be used by concurrent threads. In a concurrent usage situation, this micro-optimization can instead be a micro-performance loss! We would have better not have done it in my opinion.


/// <summary>
/// Returns default aliases for all the properties
/// </summary>
private string[][] GetAllPropertyAliases(ILoadable persister)
{
var propertyNames = persister.PropertyNames;
var suffixedPropertyAliases = new string[propertyNames.Length][];
for (var i = 0; i < propertyNames.Length; i++)
{
suffixedVersionColumn = null;
suffixedPropertyAliases[i] = GetPropertyAliases(persister, i);
}
rowIdAlias = Loadable.RowIdAlias + suffix; // TODO: not visible to the user!

return suffixedPropertyAliases;
}

protected virtual string GetDiscriminatorAlias(ILoadable persister, string suffix)
Expand All @@ -66,85 +92,52 @@ protected virtual string[] GetIdentifierAliases(ILoadable persister, string suff

protected virtual string[] GetPropertyAliases(ILoadable persister, int j)
{
return persister.GetPropertyAliases(suffix, j);
return persister.GetPropertyAliases(_suffix, j);
}

private string[] GetUserProvidedAliases(string propertyPath, string[] defaultAliases)
private string[] DetermineKeyAliases(ILoadable persister)
{
string[] result = propertyPath == null ? null : GetUserProvidedAlias(propertyPath);
if (result == null)
if (_userProvidedAliases != null)
{
return defaultAliases;
}
else
{
return result;
var result = SafeGetUserProvidedAliases(persister.IdentifierPropertyName) ??
GetUserProvidedAliases(EntityPersister.EntityID);

if (result != null)
return result;
}
}

private string[] GetUserProvidedAlias(string propertyPath)
{
string[] result;
userProvidedAliases.TryGetValue(propertyPath, out result);
return result;
return GetIdentifierAliases(persister, _suffix);
}

private string GetUserProvidedAlias(string propertyPath, string defaultAlias)
private string[][] DeterminePropertyAliases(ILoadable persister)
{
string[] columns = propertyPath == null ? null : GetUserProvidedAlias(propertyPath);
if (columns == null)
{
return defaultAlias;
}
else
{
return columns[0];
}
return GetSuffixedPropertyAliases(persister);
}

public string[][] GetSuffixedPropertyAliases(ILoadable persister)
private string DetermineDiscriminatorAlias(ILoadable persister)
{
int size = persister.PropertyNames.Length;
string[][] suffixedPropertyAliases = new string[size][];
for (int j = 0; j < size; j++)
if (_userProvidedAliases != null)
{
suffixedPropertyAliases[j] = GetUserProvidedAliases(persister.PropertyNames[j], GetPropertyAliases(persister, j));
Intern(suffixedPropertyAliases[j]);
var columns = GetUserProvidedAliases(AbstractEntityPersister.EntityClass);
if (columns != null)
return columns[0];
}
return suffixedPropertyAliases;
}

public string[] SuffixedVersionAliases
{
get { return suffixedVersionColumn; }
return GetDiscriminatorAlias(persister, _suffix);
}

public string[][] SuffixedPropertyAliases
private string[] SafeGetUserProvidedAliases(string propertyPath)
{
get { return suffixedPropertyColumns; }
}
if (propertyPath == null)
return null;

public string SuffixedDiscriminatorAlias
{
get { return suffixedDiscriminatorColumn; }
}

public string[] SuffixedKeyAliases
{
get { return suffixedKeyColumns; }
return GetUserProvidedAliases(propertyPath);
}

public string RowIdAlias
private string[] GetUserProvidedAliases(string propertyPath)
{
get { return rowIdAlias; }
}

private static void Intern(string[] strings)
{
for (int i = 0; i < strings.Length; i++)
{
strings[i] = StringHelper.InternedIfPossible(strings[i]);
}
_userProvidedAliases.TryGetValue(propertyPath, out var result);
return result;
}
}
}