From cf0fc4dfe06695c4304bb165a9ed28abe4d57b21 Mon Sep 17 00:00:00 2001 From: Alexander Kot Date: Sat, 8 Feb 2025 16:40:47 +0200 Subject: [PATCH 1/6] Improve some sparse arrays --- src/NHibernate/Loader/Loader.cs | 4 ++-- src/NHibernate/Mapping/Constraint.cs | 2 +- src/NHibernate/Mapping/ForeignKey.cs | 25 ++++++++++++++++++------- src/NHibernate/Mapping/Index.cs | 2 +- src/NHibernate/Mapping/SimpleValue.cs | 2 +- src/NHibernate/Mapping/Table.cs | 3 +++ src/NHibernate/SqlCommand/SqlString.cs | 3 +++ 7 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/NHibernate/Loader/Loader.cs b/src/NHibernate/Loader/Loader.cs index ad3b5109021..3fb33d2b0ee 100644 --- a/src/NHibernate/Loader/Loader.cs +++ b/src/NHibernate/Loader/Loader.cs @@ -82,7 +82,7 @@ public sealed class QueryCacheInfo /// /// Caches subclass entity aliases for given persister index in and subclass entity name /// - private readonly ConcurrentDictionary, string[][]> _subclassEntityAliasesMap = new ConcurrentDictionary, string[][]>(); + private readonly Lazy, string[][]>> _subclassEntityAliasesMap = new(()=>new ConcurrentDictionary, string[][]>()); protected Loader(ISessionFactoryImplementor factory) { @@ -1322,7 +1322,7 @@ private void LoadFromResultSet(DbDataReader rs, int i, object obj, ILoadable per private string[][] GetSubclassEntityAliases(int i, ILoadable persister) { var cacheKey = System.Tuple.Create(i, persister.EntityName); - return _subclassEntityAliasesMap.GetOrAdd( + return _subclassEntityAliasesMap.Value.GetOrAdd( cacheKey, k => EntityAliases[i].GetSuffixedPropertyAliases(persister)); } diff --git a/src/NHibernate/Mapping/Constraint.cs b/src/NHibernate/Mapping/Constraint.cs index 5647d4f4906..28ba203fc2b 100644 --- a/src/NHibernate/Mapping/Constraint.cs +++ b/src/NHibernate/Mapping/Constraint.cs @@ -15,7 +15,7 @@ namespace NHibernate.Mapping public abstract class Constraint : IRelationalModel { private string name; - private readonly List columns = new List(); + private readonly List columns = new List(1); private Table table; /// diff --git a/src/NHibernate/Mapping/ForeignKey.cs b/src/NHibernate/Mapping/ForeignKey.cs index 3d33a3423f7..aa49c45ce4c 100644 --- a/src/NHibernate/Mapping/ForeignKey.cs +++ b/src/NHibernate/Mapping/ForeignKey.cs @@ -2,6 +2,7 @@ using System.Text; using NHibernate.Util; using System; +using System.Linq; namespace NHibernate.Mapping { @@ -14,7 +15,7 @@ public class ForeignKey : Constraint private Table referencedTable; private string referencedEntityName; private bool cascadeDeleteEnabled; - private readonly List referencedColumns = new List(); + private List referencedColumns; /// /// Generates the SQL string to create the named Foreign Key Constraint in the database. @@ -35,7 +36,7 @@ public override string SqlConstraintString(Dialect.Dialect d, string constraintN if (IsReferenceToPrimaryKey) refiter = referencedTable.PrimaryKey.ColumnIterator; else - refiter = referencedColumns; + refiter = referencedColumns ?? Enumerable.Empty(); foreach (Column column in ColumnIterator) { cols[i] = column.GetQuotedName(d); @@ -172,13 +173,14 @@ public virtual void AddReferencedColumns(IEnumerable referencedColumnsIt private void AddReferencedColumn(Column column) { + referencedColumns ??= new List(1); if (!referencedColumns.Contains(column)) referencedColumns.Add(column); } internal void AddReferencedTable(PersistentClass referencedClass) { - if (referencedColumns.Count > 0) + if (referencedColumns != null && referencedColumns.Count > 0) { referencedTable = referencedColumns[0].Value.Table; } @@ -199,7 +201,7 @@ public override string ToString() .Append(string.Join(", ", Columns)) .Append(" ref-columns:") .Append('(') - .Append(string.Join(", ", ReferencedColumns)) + .Append(string.Join(", ", ReferencedColumnsReadOnly)) .Append(") as ") .Append(Name); return result.ToString(); @@ -218,7 +220,16 @@ public bool HasPhysicalConstraint public IList ReferencedColumns { - get { return referencedColumns; } + get + { + referencedColumns ??= new List(1); + return referencedColumns; + } + } + + private IEnumerable ReferencedColumnsReadOnly + { + get { return referencedColumns ?? Enumerable.Empty(); } } public string ReferencedEntityName @@ -230,7 +241,7 @@ public string ReferencedEntityName /// Does this foreignkey reference the primary key of the reference table public bool IsReferenceToPrimaryKey { - get { return referencedColumns.Count == 0; } + get { return referencedColumns == null || referencedColumns.Count == 0; } } public string GeneratedConstraintNamePrefix => "FK_"; @@ -242,7 +253,7 @@ public override bool IsGenerated(Dialect.Dialect dialect) if (dialect.SupportsNullInUnique || IsReferenceToPrimaryKey) return true; - foreach (var column in ReferencedColumns) + foreach (var column in ReferencedColumnsReadOnly) { if (column.IsNullable) return false; diff --git a/src/NHibernate/Mapping/Index.cs b/src/NHibernate/Mapping/Index.cs index a29ec92152a..7e8c17a6fd6 100644 --- a/src/NHibernate/Mapping/Index.cs +++ b/src/NHibernate/Mapping/Index.cs @@ -14,7 +14,7 @@ namespace NHibernate.Mapping public class Index : IRelationalModel { private Table table; - private readonly List columns = new List(); + private readonly List columns = new List(1); private string name; public static string BuildSqlCreateIndexString(Dialect.Dialect dialect, string name, Table table, diff --git a/src/NHibernate/Mapping/SimpleValue.cs b/src/NHibernate/Mapping/SimpleValue.cs index 7714f120fd4..263351a0b5d 100644 --- a/src/NHibernate/Mapping/SimpleValue.cs +++ b/src/NHibernate/Mapping/SimpleValue.cs @@ -15,7 +15,7 @@ namespace NHibernate.Mapping [Serializable] public class SimpleValue : IKeyValue { - private readonly List columns = new List(); + private readonly List columns = new List(1); private IType type; private IDictionary typeParameters; diff --git a/src/NHibernate/Mapping/Table.cs b/src/NHibernate/Mapping/Table.cs index 5311ece174d..8c9b9d0f761 100644 --- a/src/NHibernate/Mapping/Table.cs +++ b/src/NHibernate/Mapping/Table.cs @@ -1064,9 +1064,12 @@ internal ForeignKeyKey(IEnumerable columns, string referencedClassName, { this.referencedClassName = referencedClassName; this.columns = new List(columns); + this.columns.TrimExcess(); + if (referencedColumns != null) { this.referencedColumns = new List(referencedColumns); + this.referencedColumns.TrimExcess(); } else { diff --git a/src/NHibernate/SqlCommand/SqlString.cs b/src/NHibernate/SqlCommand/SqlString.cs index b9576d0aa76..8f5a1656382 100644 --- a/src/NHibernate/SqlCommand/SqlString.cs +++ b/src/NHibernate/SqlCommand/SqlString.cs @@ -215,6 +215,9 @@ internal SqlString(IEnumerable parts) _firstPartIndex = _parts.Count > 0 ? 0 : -1; _lastPartIndex = _parts.Count - 1; _length = sqlIndex; + + _parts.TrimExcess(); + _parameters.TrimExcess(); } #endregion From 4b52aa3d7ed89c112ec2c603d4f8cea101f1e2a1 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Tue, 11 Feb 2025 11:16:52 +1000 Subject: [PATCH 2/6] Remove unnecessary ReferencedColumnsReadOnly --- src/NHibernate/Mapping/ForeignKey.cs | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/src/NHibernate/Mapping/ForeignKey.cs b/src/NHibernate/Mapping/ForeignKey.cs index aa49c45ce4c..1bce168c1a3 100644 --- a/src/NHibernate/Mapping/ForeignKey.cs +++ b/src/NHibernate/Mapping/ForeignKey.cs @@ -192,22 +192,12 @@ internal void AddReferencedTable(PersistentClass referencedClass) public override string ToString() { - if (!IsReferenceToPrimaryKey) - { - var result = new StringBuilder(); - result.Append(GetType().FullName) - .Append('(') - .Append(Table.Name) - .Append(string.Join(", ", Columns)) - .Append(" ref-columns:") - .Append('(') - .Append(string.Join(", ", ReferencedColumnsReadOnly)) - .Append(") as ") - .Append(Name); - return result.ToString(); - } + if (IsReferenceToPrimaryKey) + return base.ToString(); - return base.ToString(); + var columns = string.Join(", ", Columns); + var refColumns = string.Join(", ", referencedColumns); + return $"{GetType().FullName}({Table.Name}{columns} ref-columns:({refColumns}) as {Name}"; } public bool HasPhysicalConstraint @@ -227,11 +217,6 @@ public IList ReferencedColumns } } - private IEnumerable ReferencedColumnsReadOnly - { - get { return referencedColumns ?? Enumerable.Empty(); } - } - public string ReferencedEntityName { get { return referencedEntityName; } @@ -253,7 +238,7 @@ public override bool IsGenerated(Dialect.Dialect dialect) if (dialect.SupportsNullInUnique || IsReferenceToPrimaryKey) return true; - foreach (var column in ReferencedColumnsReadOnly) + foreach (var column in referencedColumns) { if (column.IsNullable) return false; From 14823714dbc410822007dc4a869374a9a5cab6dd Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Tue, 11 Feb 2025 11:21:25 +1000 Subject: [PATCH 3/6] format --- src/NHibernate/Loader/Loader.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NHibernate/Loader/Loader.cs b/src/NHibernate/Loader/Loader.cs index 3fb33d2b0ee..3619a767a1c 100644 --- a/src/NHibernate/Loader/Loader.cs +++ b/src/NHibernate/Loader/Loader.cs @@ -82,7 +82,8 @@ public sealed class QueryCacheInfo /// /// Caches subclass entity aliases for given persister index in and subclass entity name /// - private readonly Lazy, string[][]>> _subclassEntityAliasesMap = new(()=>new ConcurrentDictionary, string[][]>()); + private readonly Lazy, string[][]>> _subclassEntityAliasesMap = + new(() => new ConcurrentDictionary, string[][]>()); protected Loader(ISessionFactoryImplementor factory) { From f4c803dcb66bc9009d04b106ced29d0b8001b930 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Tue, 11 Feb 2025 11:25:56 +1000 Subject: [PATCH 4/6] Replace condition to make more expressive --- src/NHibernate/Mapping/ForeignKey.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/NHibernate/Mapping/ForeignKey.cs b/src/NHibernate/Mapping/ForeignKey.cs index 1bce168c1a3..9883631eace 100644 --- a/src/NHibernate/Mapping/ForeignKey.cs +++ b/src/NHibernate/Mapping/ForeignKey.cs @@ -180,14 +180,7 @@ private void AddReferencedColumn(Column column) internal void AddReferencedTable(PersistentClass referencedClass) { - if (referencedColumns != null && referencedColumns.Count > 0) - { - referencedTable = referencedColumns[0].Value.Table; - } - else - { - referencedTable = referencedClass.Table; - } + referencedTable = IsReferenceToPrimaryKey ? referencedClass.Table : referencedColumns[0].Value.Table; } public override string ToString() From 1acea530505f0fab8864783b5740858111bc75f4 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Tue, 11 Feb 2025 11:34:13 +1000 Subject: [PATCH 5/6] Refactor SqlConstraintString --- src/NHibernate/Mapping/ForeignKey.cs | 53 +++++++++++----------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/src/NHibernate/Mapping/ForeignKey.cs b/src/NHibernate/Mapping/ForeignKey.cs index 9883631eace..1359b51c752 100644 --- a/src/NHibernate/Mapping/ForeignKey.cs +++ b/src/NHibernate/Mapping/ForeignKey.cs @@ -27,29 +27,26 @@ public class ForeignKey : Constraint /// /// A string that contains the SQL to create the named Foreign Key Constraint. /// - public override string SqlConstraintString(Dialect.Dialect d, string constraintName, string defaultCatalog, string defaultSchema) - { - string[] cols = new string[ColumnSpan]; - string[] refcols = new string[ColumnSpan]; - int i = 0; - IEnumerable refiter; - if (IsReferenceToPrimaryKey) - refiter = referencedTable.PrimaryKey.ColumnIterator; - else - refiter = referencedColumns ?? Enumerable.Empty(); - foreach (Column column in ColumnIterator) - { - cols[i] = column.GetQuotedName(d); - i++; - } + public override string SqlConstraintString( + Dialect.Dialect d, + string constraintName, + string defaultCatalog, + string defaultSchema) + { + var refiter = IsReferenceToPrimaryKey + ? referencedTable.PrimaryKey.Columns + : referencedColumns; + + var cols = Columns.ToArray(column => column.GetQuotedName(d)); + var refcols = refiter.ToArray(column => column.GetQuotedName(d)); + + string result = d.GetAddForeignKeyConstraintString( + constraintName, + cols, + referencedTable.GetQualifiedName(d, defaultCatalog, defaultSchema), + refcols, + IsReferenceToPrimaryKey); - i = 0; - foreach (Column column in refiter) - { - refcols[i] = column.GetQuotedName(d); - i++; - } - string result = d.GetAddForeignKeyConstraintString(constraintName, cols, referencedTable.GetQualifiedName(d, defaultCatalog, defaultSchema), refcols, IsReferenceToPrimaryKey); return cascadeDeleteEnabled && d.SupportsCascadeDelete ? result + " on delete cascade" : result; } @@ -217,10 +214,7 @@ public string ReferencedEntityName } /// Does this foreignkey reference the primary key of the reference table - public bool IsReferenceToPrimaryKey - { - get { return referencedColumns == null || referencedColumns.Count == 0; } - } + public bool IsReferenceToPrimaryKey => referencedColumns == null || referencedColumns.Count == 0; public string GeneratedConstraintNamePrefix => "FK_"; @@ -231,12 +225,7 @@ public override bool IsGenerated(Dialect.Dialect dialect) if (dialect.SupportsNullInUnique || IsReferenceToPrimaryKey) return true; - foreach (var column in referencedColumns) - { - if (column.IsNullable) - return false; - } - return true; + return referencedColumns.All(column => !column.IsNullable); } } } From 77677cfa50052db0684ab31febd522ba6b162b49 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 18 Mar 2025 06:32:52 +0000 Subject: [PATCH 6/6] Generate async files --- .../NH2898/BinaryFormatterCache.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2898/BinaryFormatterCache.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2898/BinaryFormatterCache.cs index 055df548fcb..c32fcb0ef0c 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2898/BinaryFormatterCache.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2898/BinaryFormatterCache.cs @@ -23,6 +23,31 @@ namespace NHibernate.Test.NHSpecificTest.NH2898 public partial class BinaryFormatterCache : CacheBase { + public override Task GetAsync(object key, CancellationToken cancellationToken) + { + try + { + var entry = _hashtable[key] as byte[]; + if (entry == null) + return Task.FromResult(null); + + var fmt = new BinaryFormatter + { +#if !NETFX + SurrogateSelector = new SerializationHelper.SurrogateSelector() +#endif + }; + using (var stream = new MemoryStream(entry)) + { + return Task.FromResult(fmt.Deserialize(stream)); + } + } + catch (System.Exception ex) + { + return Task.FromException(ex); + } + } + public override Task PutAsync(object key, object value, CancellationToken cancellationToken) { try