diff --git a/SqlBulkTools.IntegrationTests/App.config b/SqlBulkTools.IntegrationTests/App.config index 029df70..86b4cd1 100644 --- a/SqlBulkTools.IntegrationTests/App.config +++ b/SqlBulkTools.IntegrationTests/App.config @@ -4,8 +4,9 @@
- - + + + diff --git a/SqlBulkTools.IntegrationTests/Model/Book.cs b/SqlBulkTools.IntegrationTests/Model/Book.cs index b8f95b1..c97b798 100644 --- a/SqlBulkTools.IntegrationTests/Model/Book.cs +++ b/SqlBulkTools.IntegrationTests/Model/Book.cs @@ -26,6 +26,8 @@ public class Book [Required] [Index] public decimal? Price { get; set; } + + public float? TestFloat { get; set; } } } diff --git a/SqlBulkTools.IntegrationTests/Scripts/TestDataTypesTable.sql b/SqlBulkTools.IntegrationTests/Scripts/TestDataTypesTable.sql new file mode 100644 index 0000000..10245b9 --- /dev/null +++ b/SqlBulkTools.IntegrationTests/Scripts/TestDataTypesTable.sql @@ -0,0 +1,21 @@ +CREATE TABLE [dbo].[TestDataTypes] +( +FloatTest float(24), +FloatTest2 float, +DecimalTest decimal(14,2), +MoneyTest money, +SmallMoneyTest smallmoney, +NumericTest numeric(30,2), +RealTest real, +DateTimeTest datetime, +DateTime2Test datetime2, +SmallDateTimeTest smalldatetime, +DateTest date, +TimeTest time, +GuidTest uniqueidentifier, +TextTest text, +VarBinaryTest varbinary(20), +BinaryTest binary(10), +TinyIntTest tinyint, +BigIntTest bigint +); \ No newline at end of file diff --git a/SqlBulkTools.IntegrationTests/SqlBulkToolsIT.cs b/SqlBulkTools.IntegrationTests/SqlBulkToolsIT.cs index 6d635e1..1c2b32a 100644 --- a/SqlBulkTools.IntegrationTests/SqlBulkToolsIT.cs +++ b/SqlBulkTools.IntegrationTests/SqlBulkToolsIT.cs @@ -607,6 +607,54 @@ public void SqlBulkTools_WhenUsingReservedSqlKeywords() } + [Test] + public void SqlBulkTools_BulkInsertOrUpdate_DecimalValueCorrectlySet() + { + + _db.Books.RemoveRange(_db.Books.ToList()); + _db.SaveChanges(); + + decimal? expectedPrice = (decimal?)1.33; + + BulkOperations bulk = new BulkOperations(); + List books = new List() { new Book() { Description = "Test", ISBN = "12345678910", Price = expectedPrice } }; + + bulk.Setup(x => x.ForCollection(books)) + .WithTable("Books") + .AddAllColumns() + .BulkInsertOrUpdate() + .MatchTargetOn(x => x.ISBN) + .SetIdentityColumn(x => x.Id); + + bulk.CommitTransaction("SqlBulkToolsTest"); + + Assert.AreEqual(_db.Books.First().Price, expectedPrice); + + } + + [Test] + public void SqlBulkTools_BulkInsertOrUpdae_FloatValueCorrectlySet() + { + _db.Books.RemoveRange(_db.Books.ToList()); + _db.SaveChanges(); + + float? expectedFloat = (float?)1.33; + + BulkOperations bulk = new BulkOperations(); + List books = new List() { new Book() { Description = "Test", ISBN = "12345678910", Price = 30, TestFloat = expectedFloat} }; + + bulk.Setup(x => x.ForCollection(books)) + .WithTable("Books") + .AddAllColumns() + .BulkInsertOrUpdate() + .MatchTargetOn(x => x.ISBN) + .SetIdentityColumn(x => x.Id); + + bulk.CommitTransaction("SqlBulkToolsTest"); + + Assert.AreEqual(_db.Books.First().TestFloat, expectedFloat); + } + private void AppendToLogFile(string text) { diff --git a/SqlBulkTools/BulkOperationsHelpers.cs b/SqlBulkTools/BulkOperationsHelpers.cs index d03e6ed..2c4f494 100644 --- a/SqlBulkTools/BulkOperationsHelpers.cs +++ b/SqlBulkTools/BulkOperationsHelpers.cs @@ -17,22 +17,49 @@ namespace SqlBulkTools { internal class BulkOperationsHelpers { + internal struct PrecisionType + { + public string NumericPrecision { get; set; } + public string NumericScale { get; set; } + } + internal string BuildCreateTempTable(HashSet columns, DataTable schema, bool? outputIdentity = null) { Dictionary actualColumns = new Dictionary(); Dictionary actualColumnsMaxCharLength = new Dictionary(); + Dictionary actualColumnsPrecision = new Dictionary(); foreach (DataRow row in schema.Rows) { + string columnType = row["DATA_TYPE"].ToString(); + string columnName = row["COLUMN_NAME"].ToString(); + actualColumns.Add(row["COLUMN_NAME"].ToString(), row["DATA_TYPE"].ToString()); - actualColumnsMaxCharLength.Add(row["COLUMN_NAME"].ToString(), - row["CHARACTER_MAXIMUM_LENGTH"].ToString()); + + if (columnType == "varchar" || columnType == "nvarchar" || + columnType == "char" || columnType == "binary" || + columnType == "varbinary") + + { + actualColumnsMaxCharLength.Add(row["COLUMN_NAME"].ToString(), + row["CHARACTER_MAXIMUM_LENGTH"].ToString()); + } + + if (columnType == "numeric" || columnType == "decimal") + { + PrecisionType p = new PrecisionType + { + NumericPrecision = row["NUMERIC_PRECISION"].ToString(), + NumericScale = row["NUMERIC_SCALE"].ToString() + }; + actualColumnsPrecision.Add(columnName, p); + } + } StringBuilder command = new StringBuilder(); - command.Append("CREATE TABLE #TmpTable("); List paramList = new List(); @@ -44,17 +71,8 @@ internal string BuildCreateTempTable(HashSet columns, DataTable schema, string columnType; if (actualColumns.TryGetValue(column, out columnType)) { - if (columnType == "varchar" || columnType == "nvarchar") - { - string maxCharLength; - if (actualColumnsMaxCharLength.TryGetValue(column, out maxCharLength)) - { - if (maxCharLength == "-1") - maxCharLength = "max"; - - columnType = columnType + "(" + maxCharLength + ")"; - } - } + columnType = GetVariableCharType(column, columnType, actualColumnsMaxCharLength); + columnType = GetDecimalPrecisionAndScaleType(column, columnType, actualColumnsPrecision); } paramList.Add("[" + column + "]" + " " + columnType); @@ -73,6 +91,38 @@ internal string BuildCreateTempTable(HashSet columns, DataTable schema, return command.ToString(); } + private string GetVariableCharType(string column, string columnType, Dictionary actualColumnsMaxCharLength) + { + if (columnType == "varchar" || columnType == "nvarchar") + { + string maxCharLength; + if (actualColumnsMaxCharLength.TryGetValue(column, out maxCharLength)) + { + if (maxCharLength == "-1") + maxCharLength = "max"; + + columnType = columnType + "(" + maxCharLength + ")"; + } + } + + return columnType; + } + + private string GetDecimalPrecisionAndScaleType(string column, string columnType, Dictionary actualColumnsPrecision) + { + if (columnType == "decimal" || columnType == "numeric") + { + PrecisionType p; + + if (actualColumnsPrecision.TryGetValue(column, out p)) + { + columnType = columnType + "(" + p.NumericPrecision + ", " + p.NumericScale + ")"; + } + } + + return columnType; + } + internal string BuildJoinConditionsForUpdateOrInsert(string[] updateOn, string sourceAlias, string targetAlias) { StringBuilder command = new StringBuilder();