Skip to content
This repository has been archived by the owner on Apr 7, 2024. It is now read-only.

Commit

Permalink
Merge branch 'feature/NET6+C#10'
Browse files Browse the repository at this point in the history
  • Loading branch information
xin9le committed Nov 10, 2021
2 parents bf974d9 + 6112a6c commit 4f45ec8
Show file tree
Hide file tree
Showing 70 changed files with 8,229 additions and 8,290 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,140 +10,139 @@
using FastMember;
using Microsoft.Data.SqlClient;

namespace DeclarativeSql.DbOperations;


namespace DeclarativeSql.DbOperations

/// <summary>
/// Provides Microsoft.Data.SqlClient specific database operation.
/// </summary>
internal class MicrosoftSqlClientOperation : SqlServerOperation
{
#region Constructors
/// <summary>
/// Creates instance.
/// </summary>
/// <param name="connection"></param>
/// <param name="transaction"></param>
/// <param name="provider"></param>
/// <param name="timeout"></param>
private MicrosoftSqlClientOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout)
: base(connection, transaction, provider, timeout)
{ }


/// <summary>
/// Creates instance.
/// </summary>
/// <param name="connection"></param>
/// <param name="transaction"></param>
/// <param name="timeout"></param>
/// <returns></returns>
public static DbOperation Create(IDbConnection connection, IDbTransaction? transaction, int? timeout)
=> new MicrosoftSqlClientOperation(connection, transaction, DbProvider.SqlServer, timeout);
#endregion


#region BulkInsert
/// <summary>
/// Provides Microsoft.Data.SqlClient specific database operation.
/// Inserts the specified data into the table using the bulk method.
/// </summary>
internal class MicrosoftSqlClientOperation : SqlServerOperation
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <param name="createdAt"></param>
/// <returns>Effected rows count</returns>
public override int BulkInsert<T>(IEnumerable<T> data, ValuePriority createdAt)
{
#region Constructors
/// <summary>
/// Creates instance.
/// </summary>
/// <param name="connection"></param>
/// <param name="transaction"></param>
/// <param name="provider"></param>
/// <param name="timeout"></param>
private MicrosoftSqlClientOperation(IDbConnection connection, IDbTransaction? transaction, DbProvider provider, int? timeout)
: base(connection, transaction, provider, timeout)
{ }


/// <summary>
/// Creates instance.
/// </summary>
/// <param name="connection"></param>
/// <param name="transaction"></param>
/// <param name="timeout"></param>
/// <returns></returns>
public static DbOperation Create(IDbConnection connection, IDbTransaction? transaction, int? timeout)
=> new MicrosoftSqlClientOperation(connection, transaction, DbProvider.SqlServer, timeout);
#endregion


#region BulkInsert
/// <summary>
/// Inserts the specified data into the table using the bulk method.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <param name="createdAt"></param>
/// <returns>Effected rows count</returns>
public override int BulkInsert<T>(IEnumerable<T> data, ValuePriority createdAt)
{
using var executor = new SqlBulkCopy(this.Connection as SqlConnection, SqlBulkCopyOptions.Default, this.Transaction as SqlTransaction);
data = data.Materialize();
var param = this.SetupBulkInsert(executor, data, createdAt);
executor.WriteToServer(param);
return data.Count();
}
using var executor = new SqlBulkCopy(this.Connection as SqlConnection, SqlBulkCopyOptions.Default, this.Transaction as SqlTransaction);
data = data.Materialize();
var param = this.SetupBulkInsert(executor, data, createdAt);
executor.WriteToServer(param);
return data.Count();
}


/// <summary>
/// Inserts the specified data into the table using the bulk method.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <param name="createdAt"></param>
/// <param name="cancellationToken"></param>
/// <returns>Effected rows count</returns>
public override async Task<int> BulkInsertAsync<T>(IEnumerable<T> data, ValuePriority createdAt, CancellationToken cancellationToken = default)
{
using var executor = new SqlBulkCopy(this.Connection as SqlConnection, SqlBulkCopyOptions.Default, this.Transaction as SqlTransaction);
data = data.Materialize();
var param = this.SetupBulkInsert(executor, data, createdAt);
await executor.WriteToServerAsync(param, cancellationToken).ConfigureAwait(false);
return data.Count();
}
/// <summary>
/// Inserts the specified data into the table using the bulk method.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <param name="createdAt"></param>
/// <param name="cancellationToken"></param>
/// <returns>Effected rows count</returns>
public override async Task<int> BulkInsertAsync<T>(IEnumerable<T> data, ValuePriority createdAt, CancellationToken cancellationToken = default)
{
using var executor = new SqlBulkCopy(this.Connection as SqlConnection, SqlBulkCopyOptions.Default, this.Transaction as SqlTransaction);
data = data.Materialize();
var param = this.SetupBulkInsert(executor, data, createdAt);
await executor.WriteToServerAsync(param, cancellationToken).ConfigureAwait(false);
return data.Count();
}


/// <summary>
/// Prepares for bulk insertion processing.
/// </summary>
/// <typeparam name="T">Mapped type to table.</typeparam>
/// <param name="executor">Bulk executor.</param>
/// <param name="data">Inserting target data.</param>
/// <param name="createdAt"></param>
/// <returns>Data reader</returns>
private DataTable SetupBulkInsert<T>(SqlBulkCopy executor, IEnumerable<T> data, ValuePriority createdAt)
{
//--- Timeout -> CommandTimeout -> BulkCopyTimeout
executor.BulkCopyTimeout = this.Timeout ?? SqlMapper.Settings.CommandTimeout ?? executor.BulkCopyTimeout;

//--- Target table
var tableMappings = TableInfo.Get<T>(this.DbProvider.Database);
executor.DestinationTableName = tableMappings.FullName;

//--- Extract mapping columns
var columnMappings
= tableMappings.Columns
.Where(x => !x.IsAutoIncrement)
.Where(x =>
{
if (createdAt == ValuePriority.Default)
{
if ((x.IsCreatedAt && x.DefaultValue is not null)
|| (x.IsModifiedAt && x.DefaultValue is not null))
return false;
}
return true;
})
.ToArray();

//--- Setup columns
var columns
= columnMappings
.Select(x =>
{
var isNullable = x.MemberType.IsNullable();
return new DataColumn
{
ColumnName = x.ColumnName,
AllowDBNull = isNullable || x.AllowNull,
DataType = isNullable ? Nullable.GetUnderlyingType(x.MemberType)! : x.MemberType,
};
});
var table = new DataTable();
foreach (var x in columns)
/// <summary>
/// Prepares for bulk insertion processing.
/// </summary>
/// <typeparam name="T">Mapped type to table.</typeparam>
/// <param name="executor">Bulk executor.</param>
/// <param name="data">Inserting target data.</param>
/// <param name="createdAt"></param>
/// <returns>Data reader</returns>
private DataTable SetupBulkInsert<T>(SqlBulkCopy executor, IEnumerable<T> data, ValuePriority createdAt)
{
//--- Timeout -> CommandTimeout -> BulkCopyTimeout
executor.BulkCopyTimeout = this.Timeout ?? SqlMapper.Settings.CommandTimeout ?? executor.BulkCopyTimeout;

//--- Target table
var tableMappings = TableInfo.Get<T>(this.DbProvider.Database);
executor.DestinationTableName = tableMappings.FullName;

//--- Extract mapping columns
var columnMappings
= tableMappings.Columns
.Where(x => !x.IsAutoIncrement)
.Where(x =>
{
executor.ColumnMappings.Add(x.ColumnName, x.ColumnName);
table.Columns.Add(x);
}
if (createdAt == ValuePriority.Default)
{
if ((x.IsCreatedAt && x.DefaultValue is not null)
|| (x.IsModifiedAt && x.DefaultValue is not null))
return false;
}
return true;
})
.ToArray();

//--- Setup rows
foreach (var x in data)
//--- Setup columns
var columns
= columnMappings
.Select(x =>
{
var row = table.NewRow();
var accessor = ObjectAccessor.Create(x);
foreach (var y in columnMappings)
row[y.ColumnName] = accessor[y.MemberName] ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
var isNullable = x.MemberType.IsNullable();
return new DataColumn
{
ColumnName = x.ColumnName,
AllowDBNull = isNullable || x.AllowNull,
DataType = isNullable ? Nullable.GetUnderlyingType(x.MemberType)! : x.MemberType,
};
});
var table = new DataTable();
foreach (var x in columns)
{
executor.ColumnMappings.Add(x.ColumnName, x.ColumnName);
table.Columns.Add(x);
}

//--- Setup rows
foreach (var x in data)
{
var row = table.NewRow();
var accessor = ObjectAccessor.Create(x);
foreach (var y in columnMappings)
row[y.ColumnName] = accessor[y.MemberName] ?? DBNull.Value;
table.Rows.Add(row);
}
#endregion
return table;
}
#endregion
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net461;net5</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net461;net5;net6</TargetFrameworks>
<RootNamespace>DeclarativeSql</RootNamespace>
<LangVersion>9.0</LangVersion>
<LangVersion>10.0</LangVersion>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!-- NuGet -->
Expand All @@ -24,7 +24,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient" Version="2.1.2" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="3.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Runtime.CompilerServices
{
internal sealed class IsExternalInit
{ }
}
namespace System.Runtime.CompilerServices;

internal sealed class IsExternalInit
{ }
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Runtime.CompilerServices
{
/// <summary>
/// Used to indicate to the compiler that a method should be called
/// in its containing module's initializer.
/// </summary>
/// <remarks>
/// When one or more valid methods
/// with this attribute are found in a compilation, the compiler will
/// emit a module initializer which calls each of the attributed methods.
///
/// Certain requirements are imposed on any method targeted with this attribute:
/// - The method must be `static`.
/// - The method must be an ordinary member method, as opposed to a property accessor, constructor, local function, etc.
/// - The method must be parameterless.
/// - The method must return `void`.
/// - The method must not be generic or be contained in a generic type.
/// - The method's effective accessibility must be `internal` or `public`.
///
/// The specification for module initializers in the .NET runtime can be found here:
/// https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md#module-initializer
/// </remarks>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
internal sealed class ModuleInitializerAttribute : Attribute
{ }
}
namespace System.Runtime.CompilerServices;

/// <summary>
/// Used to indicate to the compiler that a method should be called
/// in its containing module's initializer.
/// </summary>
/// <remarks>
/// When one or more valid methods
/// with this attribute are found in a compilation, the compiler will
/// emit a module initializer which calls each of the attributed methods.
///
/// Certain requirements are imposed on any method targeted with this attribute:
/// - The method must be `static`.
/// - The method must be an ordinary member method, as opposed to a property accessor, constructor, local function, etc.
/// - The method must be parameterless.
/// - The method must return `void`.
/// - The method must not be generic or be contained in a generic type.
/// - The method's effective accessibility must be `internal` or `public`.
///
/// The specification for module initializers in the .NET runtime can be found here:
/// https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md#module-initializer
/// </remarks>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
internal sealed class ModuleInitializerAttribute : Attribute
{ }
#endif
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
using System.Runtime.CompilerServices;
using DeclarativeSql.DbOperations;
using DeclarativeSql.DbOperations;
using Microsoft.Data.SqlClient;

namespace DeclarativeSql;


namespace DeclarativeSql

/// <summary>
/// Provides initializer to use Microsoft.Data.SqlClient specific feature.
/// </summary>
public static class MicrosoftSqlClientInitializer
{
/// <summary>
/// Provides initializer to use Microsoft.Data.SqlClient specific feature.
/// Initialize.
/// </summary>
public static class MicrosoftSqlClientInitializer
{
/// <summary>
/// Initialize.
/// </summary>
[ModuleInitializer]
public static void Initialize()
=> DbOperation.Factory[typeof(SqlConnection)] = MicrosoftSqlClientOperation.Create;
}
public static void Initialize()
=> DbOperation.Factory[typeof(SqlConnection)] = MicrosoftSqlClientOperation.Create;
}
Loading

0 comments on commit 4f45ec8

Please sign in to comment.