/// <summary> /// 指定されたレコードをバルク方式でテーブルに非同期的に挿入します。 /// </summary> /// <typeparam name="T">テーブルにマッピングされた型</typeparam> /// <param name="data">挿入するデータ</param> /// <returns>影響した行数</returns> public override async Task <int> BulkInsertAsync <T>(IEnumerable <T> data) { //--- 挿入処理本体 Func <IEnumerable <T>, IDbTransaction, Task <int> > insert = async(collection, transaction) => { var result = 0; var sql = PrimitiveSql.CreateInsert <T>(this.DbKind, false, true); foreach (var x in collection) { var value = await this.Connection.ExecuteAsync(sql, x, transaction, this.Timeout).ConfigureAwait(false); Interlocked.Add(ref result, value); } return(result); }; //--- トランザクションが外部から指定されている場合はそれを利用 if (this.Transaction != null) { return(await insert(data, this.Transaction).ConfigureAwait(false)); } //--- トランザクションが外部から指定されていない場合は新規に作成 //--- SQLiteにおけるバルクインサートの魔法 using (var transaction = this.Connection.StartTransaction()) { var result = await insert(data, transaction.Raw).ConfigureAwait(false); transaction.Complete(); return(result); } }
/// <summary> /// バルク方式で指定のデータを挿入するためのコマンドを生成します。 /// </summary> /// <typeparam name="T">テーブルにマッピングされた型</typeparam> /// <param name="data">挿入するデータ</param> /// <returns>コマンド</returns> private DbCommand CreateBulkInsertCommand <T>(IEnumerable <T> data) { //--- 実体化 data = data.Materialize(); //--- build DbCommand var factory = DbProvider.GetFactory(this.DbKind); dynamic command = factory.CreateCommand(); command.Connection = (dynamic)this.Connection; command.CommandText = PrimitiveSql.CreateInsert <T>(this.DbKind, false, true); command.BindByName = true; command.ArrayBindCount = data.Count(); if (this.Timeout.HasValue) { command.CommandTimeout = this.Timeout.Value; } //--- bind params foreach (var x in TableMappingInfo.Create <T>().Columns) { var getter = AccessorCache <T> .LookupGet(x.PropertyName); dynamic parameter = factory.CreateParameter(); parameter.ParameterName = x.PropertyName; parameter.DbType = x.ColumnType; parameter.Value = data.Select(y => getter(y)).ToArray(); command.Parameters.Add(parameter); } return(command); }
/// <summary> /// 指定されたレコードをテーブルに非同期的に挿入します。 /// </summary> /// <typeparam name="T">テーブルにマッピングされた型</typeparam> /// <param name="data">挿入するデータ</param> /// <param name="useSequence">シーケンスを利用するかどうか</param> /// <param name="setIdentity">自動採番のID列に値を設定するかどうか</param> /// <returns>影響した行数</returns> public virtual Task <int> InsertAsync <T>(T data, bool useSequence, bool setIdentity) { var type = TypeHelper.GetElementType <T>() ?? typeof(T); var sql = PrimitiveSql.CreateInsert(this.DbKind, type, useSequence, setIdentity); return(this.Connection.ExecuteAsync(sql, data, this.Transaction, this.Timeout)); }
/// <summary> /// レコードを挿入し、そのレコードに自動採番されたIDを取得するSQLを生成します。 /// </summary> /// <typeparam name="T">テーブルにマッピングされた型</typeparam> /// <returns>SQL文</returns> protected override string CreateInsertAndGetSql <T>() { var sequence = TableMappingInfo.Create <T>().Columns.First(x => x.IsPrimaryKey).Sequence; return ($@"{PrimitiveSql.CreateInsert<T>(this.DbKind)}; select currval({sequence.FullName}) as Id;"); }
public void シーケンスを利用するInsert文生成() { var actual1 = PrimitiveSql.CreateInsert(DbKind.SqlServer, typeof(Person)); var actual2 = PrimitiveSql.CreateInsert <Person>(DbKind.SqlServer); var expect = @"insert into dbo.Person ( 名前, Age, HasChildren ) values ( @Name, next value for dbo.AgeSeq, @HasChildren )"; actual1.Is(expect); actual2.Is(expect); }
/// <summary> /// InsertAndGetするためのパラメーターを生成します。 /// </summary> /// <typeparam name="T">テーブルにマッピングされた型</typeparam> /// <param name="data">挿入するデータ</param> /// <returns>パラメーター</returns> private Tuple <DbCommand, DbParameter> CreateInsertAndGetParameter <T>(T data) { //--- command var factory = DbProvider.GetFactory(this.DbKind); dynamic command = factory.CreateCommand(); command.BindByName = true; command.Connection = (dynamic)this.Connection; if (this.Timeout.HasValue) { command.CommandTimeout = this.Timeout.Value; } //--- parameters DbParameter output = null; foreach (var x in TableMappingInfo.Create <T>().Columns) { dynamic parameter = factory.CreateParameter(); parameter.ParameterName = x.PropertyName; parameter.DbType = x.ColumnType; if (x.IsPrimaryKey) { parameter.Direction = ParameterDirection.Output; output = parameter; command.CommandText = $@"{PrimitiveSql.CreateInsert<T>(this.DbKind)} returning {x.ColumnName} into :{x.PropertyName}"; } else { parameter.Direction = ParameterDirection.Input; parameter.Value = AccessorCache <T> .LookupGet(x.PropertyName)(data); } command.Parameters.Add(parameter); } //--- ok return(Tuple.Create((DbCommand)command, output)); }
public void IDを設定するInsert文生成() { var actual1 = PrimitiveSql.CreateInsert(DbKind.SqlServer, typeof(Person), setIdentity: true); var actual2 = PrimitiveSql.CreateInsert <Person>(DbKind.SqlServer, setIdentity: true); var expect = @"insert into dbo.Person ( Id, 名前, Age, HasChildren ) values ( @Id, @Name, next value for dbo.AgeSeq, @HasChildren )"; actual1.Is(expect); actual2.Is(expect); }
/// <summary> /// レコードを挿入し、そのレコードに自動採番されたIDを取得するSQLを生成します。 /// </summary> /// <typeparam name="T">テーブルにマッピングされた型</typeparam> /// <returns>SQL文</returns> protected override string CreateInsertAndGetSql <T>() => $@"{PrimitiveSql.CreateInsert<T>(this.DbKind)}; select last_insert_rowid() as Id;";
/// <summary> /// レコードを挿入し、そのレコードに自動採番されたIDを取得するSQLを生成します。 /// </summary> /// <typeparam name="T">テーブルにマッピングされた型</typeparam> /// <returns>SQL文</returns> protected override string CreateInsertAndGetSql <T>() => $@"{PrimitiveSql.CreateInsert<T>(this.DbKind)}; select cast(scope_identity() as bigint) as Id;";
/// <summary> /// レコードを挿入し、そのレコードに自動採番されたIDを取得するSQLを生成します。 /// </summary> /// <typeparam name="T">テーブルにマッピングされた型</typeparam> /// <returns>SQL文</returns> protected override string CreateInsertAndGetSql <T>() => $@"{PrimitiveSql.CreateInsert<T>(this.DbKind)}; select @@IDENTITY as Id;";