Skip to content

Commit 7aea361

Browse files
authored
Merge pull request #11538 from umbraco/v9/feature/merge-v8_29-10-2021
V9: Merge v8 29-10-2021
2 parents e9ae567 + bf5f136 commit 7aea361

File tree

69 files changed

+1674
-1394
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1674
-1394
lines changed
Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,39 @@
11
using System.Collections.Generic;
22

3-
namespace Umbraco.Core.Collections
3+
namespace Umbraco.Cms.Core.Collections
44
{
55
/// <summary>
6-
/// Collection that can be both a queue and a stack.
6+
/// Collection that can be both a queue and a stack.
77
/// </summary>
88
/// <typeparam name="T"></typeparam>
99
public class StackQueue<T>
1010
{
11-
private readonly LinkedList<T> _linkedList = new LinkedList<T>();
11+
private readonly LinkedList<T> _linkedList = new();
1212

13-
public void Clear()
14-
{
15-
_linkedList.Clear();
16-
}
13+
public int Count => _linkedList.Count;
1714

18-
public void Push(T obj)
19-
{
20-
_linkedList.AddFirst(obj);
21-
}
15+
public void Clear() => _linkedList.Clear();
2216

23-
public void Enqueue(T obj)
24-
{
25-
_linkedList.AddFirst(obj);
26-
}
17+
public void Push(T obj) => _linkedList.AddFirst(obj);
18+
19+
public void Enqueue(T obj) => _linkedList.AddFirst(obj);
2720

2821
public T Pop()
2922
{
30-
var obj = _linkedList.First.Value;
23+
T obj = _linkedList.First.Value;
3124
_linkedList.RemoveFirst();
3225
return obj;
3326
}
3427

3528
public T Dequeue()
3629
{
37-
var obj = _linkedList.Last.Value;
30+
T obj = _linkedList.Last.Value;
3831
_linkedList.RemoveLast();
3932
return obj;
4033
}
4134

42-
public T PeekStack()
43-
{
44-
return _linkedList.First.Value;
45-
}
35+
public T PeekStack() => _linkedList.First.Value;
4636

47-
public T PeekQueue()
48-
{
49-
return _linkedList.Last.Value;
50-
}
51-
52-
public int Count
53-
{
54-
get
55-
{
56-
return _linkedList.Count;
57-
}
58-
}
37+
public T PeekQueue() => _linkedList.Last.Value;
5938
}
6039
}

src/Umbraco.Core/Constants-Sql.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace Umbraco.Cms.Core
2+
{
3+
public static partial class Constants
4+
{
5+
public static class Sql
6+
{
7+
/// <summary>
8+
/// The maximum amount of parameters that can be used in a query.
9+
/// </summary>
10+
/// <remarks>
11+
/// The actual limit is 2100
12+
/// (https://docs.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server),
13+
/// but we want to ensure there's room for additional parameters if this value is used to create groups/batches.
14+
/// </remarks>
15+
public const int MaxParameterCount = 2000;
16+
}
17+
}
18+
}

src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ private void Map(IUserGroup source, UserGroupDisplay target, MapperContext conte
251251
// the entity service due to too many Sql parameters.
252252

253253
var list = new List<IEntitySlim>();
254-
foreach (var idGroup in allContentPermissions.Keys.InGroupsOf(2000))
254+
foreach (var idGroup in allContentPermissions.Keys.InGroupsOf(Constants.Sql.MaxParameterCount))
255255
list.AddRange(_entityService.GetAll(UmbracoObjectTypes.Document, idGroup.ToArray()));
256256
contentEntities = list.ToArray();
257257
}

src/Umbraco.Core/Umbraco.Core.csproj

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,61 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

3-
<PropertyGroup>
4-
<TargetFramework>netstandard2.0</TargetFramework>
5-
<RootNamespace>Umbraco.Cms.Core</RootNamespace>
6-
<Product>Umbraco CMS</Product>
7-
<PackageId>Umbraco.Cms.Core</PackageId>
8-
<Title>Umbraco CMS Core</Title>
9-
<Description>Contains the core assembly needed to run Umbraco Cms. This package only contains the assembly, and can be used for package development. Use the template in the Umbraco.Templates package to setup Umbraco</Description>
10-
<Product>Umbraco CMS</Product>
11-
</PropertyGroup>
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<RootNamespace>Umbraco.Cms.Core</RootNamespace>
6+
<Product>Umbraco CMS</Product>
7+
<PackageId>Umbraco.Cms.Core</PackageId>
8+
<Title>Umbraco CMS Core</Title>
9+
<Description>Contains the core assembly needed to run Umbraco Cms. This package only contains the assembly, and can be used for package development. Use the template in the Umbraco.Templates package to setup Umbraco</Description>
10+
<Product>Umbraco CMS</Product>
11+
</PropertyGroup>
1212

13-
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
14-
<DocumentationFile>bin\Release\Umbraco.Core.xml</DocumentationFile>
15-
</PropertyGroup>
13+
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
14+
<DocumentationFile>bin\Release\Umbraco.Core.xml</DocumentationFile>
15+
</PropertyGroup>
1616

17-
<ItemGroup>
18-
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
19-
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="5.0.10" />
20-
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
21-
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
22-
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
23-
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0" />
24-
<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" Version="5.0.0" />
25-
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0">
26-
<PrivateAssets>all</PrivateAssets>
27-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
28-
</PackageReference>
29-
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
30-
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
31-
<PackageReference Include="System.Runtime.Caching" Version="5.0.0" />
32-
<PackageReference Include="Umbraco.Code" Version="1.2.0">
33-
<PrivateAssets>all</PrivateAssets>
34-
</PackageReference>
35-
</ItemGroup>
17+
<ItemGroup>
18+
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0"/>
19+
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="5.0.10"/>
20+
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0"/>
21+
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0"/>
22+
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0"/>
23+
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0"/>
24+
<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" Version="5.0.0"/>
25+
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0">
26+
<PrivateAssets>all</PrivateAssets>
27+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
28+
</PackageReference>
29+
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0"/>
30+
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0"/>
31+
<PackageReference Include="System.Runtime.Caching" Version="5.0.0"/>
32+
<PackageReference Include="Umbraco.Code" Version="1.2.0">
33+
<PrivateAssets>all</PrivateAssets>
34+
</PackageReference>
35+
</ItemGroup>
3636

37-
<ItemGroup>
38-
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
39-
<_Parameter1>Umbraco.Tests</_Parameter1>
40-
</AssemblyAttribute>
41-
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
42-
<_Parameter1>Umbraco.Tests.Common</_Parameter1>
43-
</AssemblyAttribute>
44-
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
45-
<_Parameter1>Umbraco.Tests.UnitTests</_Parameter1>
46-
</AssemblyAttribute>
47-
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
48-
<_Parameter1>Umbraco.Tests.Benchmarks</_Parameter1>
49-
</AssemblyAttribute>
50-
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
51-
<_Parameter1>Umbraco.Tests.Integration</_Parameter1>
52-
</AssemblyAttribute>
53-
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
54-
<_Parameter1>DynamicProxyGenAssembly2</_Parameter1>
55-
</AssemblyAttribute>
56-
</ItemGroup>
37+
<ItemGroup>
38+
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
39+
<_Parameter1>Umbraco.Tests</_Parameter1>
40+
</AssemblyAttribute>
41+
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
42+
<_Parameter1>Umbraco.Tests.Common</_Parameter1>
43+
</AssemblyAttribute>
44+
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
45+
<_Parameter1>Umbraco.Tests.UnitTests</_Parameter1>
46+
</AssemblyAttribute>
47+
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
48+
<_Parameter1>Umbraco.Tests.Benchmarks</_Parameter1>
49+
</AssemblyAttribute>
50+
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
51+
<_Parameter1>Umbraco.Tests.Integration</_Parameter1>
52+
</AssemblyAttribute>
53+
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
54+
<_Parameter1>DynamicProxyGenAssembly2</_Parameter1>
55+
</AssemblyAttribute>
56+
</ItemGroup>
5757

58-
<ItemGroup>
59-
<EmbeddedResource Include="EmbeddedResources\**\*" />
60-
</ItemGroup>
58+
<ItemGroup>
59+
<EmbeddedResource Include="EmbeddedResources\**\*"/>
60+
</ItemGroup>
6161
</Project>
Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,76 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Data;
4+
using System.Data.Common;
45
using System.Data.SqlClient;
56
using System.Linq;
67
using NPoco;
8+
using Umbraco.Cms.Core;
79
using Umbraco.Cms.Infrastructure.Persistence;
810

911
namespace Umbraco.Extensions
1012
{
1113
/// <summary>
12-
/// Provides extension methods to NPoco Database class.
14+
/// Provides extension methods to NPoco Database class.
1315
/// </summary>
1416
public static partial class NPocoDatabaseExtensions
1517
{
1618
/// <summary>
17-
/// Configures NPoco's SqlBulkCopyHelper to use the correct SqlConnection and SqlTransaction instances from the underlying RetryDbConnection and ProfiledDbTransaction
19+
/// Configures NPoco's SqlBulkCopyHelper to use the correct SqlConnection and SqlTransaction instances from the
20+
/// underlying RetryDbConnection and ProfiledDbTransaction
1821
/// </summary>
1922
/// <remarks>
20-
/// This is required to use NPoco's own <see cref="Database.InsertBulk{T}(IEnumerable{T})" /> method because we use wrapped DbConnection and DbTransaction instances.
21-
/// NPoco's InsertBulk method only caters for efficient bulk inserting records for Sql Server, it does not cater for bulk inserting of records for
22-
/// any other database type and in which case will just insert records one at a time.
23-
/// NPoco's InsertBulk method also deals with updating the passed in entity's PK/ID once it's inserted whereas our own BulkInsertRecords methods
24-
/// do not handle this scenario.
23+
/// This is required to use NPoco's own <see cref="Database.InsertBulk{T}(IEnumerable{T})" /> method because we use
24+
/// wrapped DbConnection and DbTransaction instances.
25+
/// NPoco's InsertBulk method only caters for efficient bulk inserting records for Sql Server, it does not cater for
26+
/// bulk inserting of records for
27+
/// any other database type and in which case will just insert records one at a time.
28+
/// NPoco's InsertBulk method also deals with updating the passed in entity's PK/ID once it's inserted whereas our own
29+
/// BulkInsertRecords methods
30+
/// do not handle this scenario.
2531
/// </remarks>
2632
public static void ConfigureNPocoBulkExtensions()
2733
{
28-
2934
SqlBulkCopyHelper.SqlConnectionResolver = dbConn => GetTypedConnection<SqlConnection>(dbConn);
3035
SqlBulkCopyHelper.SqlTransactionResolver = dbTran => GetTypedTransaction<SqlTransaction>(dbTran);
3136
}
3237

3338

3439
/// <summary>
35-
/// Creates bulk-insert commands.
40+
/// Creates bulk-insert commands.
3641
/// </summary>
3742
/// <typeparam name="T">The type of the records.</typeparam>
3843
/// <param name="database">The database.</param>
3944
/// <param name="records">The records.</param>
4045
/// <returns>The sql commands to execute.</returns>
4146
internal static IDbCommand[] GenerateBulkInsertCommands<T>(this IUmbracoDatabase database, T[] records)
4247
{
43-
if (database?.Connection == null) throw new ArgumentException("Null database?.connection.", nameof(database));
48+
if (database?.Connection == null)
49+
{
50+
throw new ArgumentException("Null database?.connection.", nameof(database));
51+
}
4452

45-
var pocoData = database.PocoDataFactory.ForType(typeof(T));
53+
PocoData pocoData = database.PocoDataFactory.ForType(typeof(T));
4654

4755
// get columns to include, = number of parameters per row
48-
var columns = pocoData.Columns.Where(c => IncludeColumn(pocoData, c)).ToArray();
56+
KeyValuePair<string, PocoColumn>[] columns =
57+
pocoData.Columns.Where(c => IncludeColumn(pocoData, c)).ToArray();
4958
var paramsPerRecord = columns.Length;
5059

5160
// format columns to sql
5261
var tableName = database.DatabaseType.EscapeTableName(pocoData.TableInfo.TableName);
53-
var columnNames = string.Join(", ", columns.Select(c => tableName + "." + database.DatabaseType.EscapeSqlIdentifier(c.Key)));
62+
var columnNames = string.Join(", ",
63+
columns.Select(c => tableName + "." + database.DatabaseType.EscapeSqlIdentifier(c.Key)));
5464

5565
// example:
5666
// assume 4168 records, each record containing 8 fields, ie 8 command parameters
5767
// max 2100 parameter per command
5868
// Math.Floor(2100 / 8) = 262 record per command
5969
// 4168 / 262 = 15.908... = there will be 16 command in total
6070
// (if we have disabled db parameters, then all records will be included, in only one command)
61-
var recordsPerCommand = paramsPerRecord == 0 ? int.MaxValue : Convert.ToInt32(Math.Floor(2000.00 / paramsPerRecord));
71+
var recordsPerCommand = paramsPerRecord == 0
72+
? int.MaxValue
73+
: Convert.ToInt32(Math.Floor((double)Constants.Sql.MaxParameterCount / paramsPerRecord));
6274
var commandsCount = Convert.ToInt32(Math.Ceiling((double)records.Length / recordsPerCommand));
6375

6476
var commands = new IDbCommand[commandsCount];
@@ -67,43 +79,42 @@ internal static IDbCommand[] GenerateBulkInsertCommands<T>(this IUmbracoDatabase
6779
var prefix = database.DatabaseType.GetParameterPrefix(database.ConnectionString);
6880
for (var commandIndex = 0; commandIndex < commandsCount; commandIndex++)
6981
{
70-
var command = database.CreateCommand(database.Connection, CommandType.Text, string.Empty);
82+
DbCommand command = database.CreateCommand(database.Connection, CommandType.Text, string.Empty);
7183
var parameterIndex = 0;
7284
var commandRecords = Math.Min(recordsPerCommand, recordsLeftToInsert);
7385
var recordsValues = new string[commandRecords];
74-
for (var commandRecordIndex = 0; commandRecordIndex < commandRecords; commandRecordIndex++, recordsIndex++, recordsLeftToInsert--)
86+
for (var commandRecordIndex = 0;
87+
commandRecordIndex < commandRecords;
88+
commandRecordIndex++, recordsIndex++, recordsLeftToInsert--)
7589
{
76-
var record = records[recordsIndex];
90+
T record = records[recordsIndex];
7791
var recordValues = new string[columns.Length];
7892
for (var columnIndex = 0; columnIndex < columns.Length; columnIndex++)
7993
{
8094
database.AddParameter(command, columns[columnIndex].Value.GetValue(record));
8195
recordValues[columnIndex] = prefix + parameterIndex++;
8296
}
97+
8398
recordsValues[commandRecordIndex] = "(" + string.Join(",", recordValues) + ")";
8499
}
85100

86-
command.CommandText = $"INSERT INTO {tableName} ({columnNames}) VALUES {string.Join(", ", recordsValues)}";
101+
command.CommandText =
102+
$"INSERT INTO {tableName} ({columnNames}) VALUES {string.Join(", ", recordsValues)}";
87103
commands[commandIndex] = command;
88104
}
89105

90106
return commands;
91107
}
92108

93109
/// <summary>
94-
/// Determines whether a column should be part of a bulk-insert.
110+
/// Determines whether a column should be part of a bulk-insert.
95111
/// </summary>
96112
/// <param name="pocoData">The PocoData object corresponding to the record's type.</param>
97113
/// <param name="column">The column.</param>
98114
/// <returns>A value indicating whether the column should be part of the bulk-insert.</returns>
99115
/// <remarks>Columns that are primary keys and auto-incremental, or result columns, are excluded from bulk-inserts.</remarks>
100-
public static bool IncludeColumn(PocoData pocoData, KeyValuePair<string, PocoColumn> column)
101-
{
102-
return column.Value.ResultColumn == false
103-
&& (pocoData.TableInfo.AutoIncrement == false || column.Key != pocoData.TableInfo.PrimaryKey);
104-
}
105-
106-
107-
116+
public static bool IncludeColumn(PocoData pocoData, KeyValuePair<string, PocoColumn> column) =>
117+
column.Value.ResultColumn == false
118+
&& (pocoData.TableInfo.AutoIncrement == false || column.Key != pocoData.TableInfo.PrimaryKey);
108119
}
109120
}

0 commit comments

Comments
 (0)