コード例 #1
0
        protected IDbJob <int?> BuildInsertOrUpdateProducts(IEnumerable <Product> products)
        {
            if (products == null || !products.Any())
            {
                throw new ArgumentException($"{nameof(products)} is null or empty.", nameof(products));
            }

            string sql = $@"
                MERGE INTO {Product.TableName} target
                USING
                (
                    VALUES (
                        @{nameof(Product.ProductKey)},
                        @{nameof(Product.ProductName)},
                        @{nameof(Product.ProductLineKey)},
                        @{nameof(Product.ShippingWeight)},
                        @{nameof(Product.ProductWeight)}
                    )
                ) source (
                            {nameof(Product.ProductKey)},
                            {nameof(Product.ProductName)},
                            {nameof(Product.ProductLineKey)},
                            {nameof(Product.ShippingWeight)},
                            {nameof(Product.ProductWeight)}
                         )
                ON target.ProductKey = source.{nameof(Product.ProductKey)}
                WHEN MATCHED THEN
                    UPDATE SET ProductName = source.{nameof(Product.ProductName)},
                               ProductLineKey = source.{nameof(Product.ProductLineKey)},
                               ShippingWeight = source.{nameof(Product.ShippingWeight)},
                               ProductWeight = source.{nameof(Product.ProductWeight)}
                WHEN NOT MATCHED THEN
                    INSERT
                    (
                        ProductName,
                        ProductLineKey,
                        ShippingWeight,
                        ProductWeight
                    )
                    VALUES
                    (
                        source.{nameof(Product.ProductName)},
                        source.{nameof(Product.ProductLineKey)},
                        source.{nameof(Product.ShippingWeight)},
                        source.{nameof(Product.ProductWeight)}
                    )
                OUTPUT Inserted.ProductKey;";

            Product firstProd = products.First();

            //Best approach for unlimited inserts since SQL server has parameter amount restrictions
            //https://docs.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server?redirectedfrom=MSDN&view=sql-server-ver15
            return(DbConnector.Build <int?>(
                       sql: sql,
                       param: firstProd,
                       onExecute: (int?result, IDbExecutionModel em) =>
            {
                //Set the command
                DbCommand command = em.Command;

                //Execute first row.
                firstProd.ProductKey = (int)command.ExecuteScalar();
                em.NumberOfRowsAffected = 1;

                //Set and execute remaining rows.
                foreach (var prod in products.Skip(1))
                {
                    command.Parameters[nameof(Product.ProductKey)].Value = prod.ProductKey;
                    command.Parameters[nameof(Product.ProductName)].Value = prod.ProductName ?? (object)DBNull.Value;
                    command.Parameters[nameof(Product.ProductLineKey)].Value = prod.ProductLineKey;
                    command.Parameters[nameof(Product.ShippingWeight)].Value = prod.ShippingWeight ?? (object)DBNull.Value;
                    command.Parameters[nameof(Product.ProductWeight)].Value = prod.ProductWeight ?? (object)DBNull.Value;

                    prod.ProductKey = (int)command.ExecuteScalar();
                    em.NumberOfRowsAffected += 1;
                }

                return em.NumberOfRowsAffected;
            }
                       )
                   .WithIsolationLevel(IsolationLevel.ReadCommitted));//Use a transaction
        }