diff --git a/ACUtils.SqlDb.Utils/ACUtils.SqlDb.Utils.csproj b/ACUtils.SqlDb.Utils/ACUtils.SqlDb.Utils.csproj index 42c4c6c..2449e96 100644 --- a/ACUtils.SqlDb.Utils/ACUtils.SqlDb.Utils.csproj +++ b/ACUtils.SqlDb.Utils/ACUtils.SqlDb.Utils.csproj @@ -4,8 +4,8 @@ Andrea Cattaneo true false - 1.0.0.147 - 1.0.0.147 + 1.0.0.148 + 1.0.0.148 Utilities per gestione DataTable it true diff --git a/ACUtils.SqlDb.Utils/DBModel.cs b/ACUtils.SqlDb.Utils/DBModel.cs index 9a55a61..22ce1ab 100644 --- a/ACUtils.SqlDb.Utils/DBModel.cs +++ b/ACUtils.SqlDb.Utils/DBModel.cs @@ -118,7 +118,7 @@ public Q GetValueByDbAttribute(string field) { return GetValueBy(field, property => GetDbAttribute(property.Name)?.DbField); } - + public object this[string fieldName] { get @@ -297,6 +297,14 @@ public IDbFieldAttribute GetDbAttribute(string propertyName) return attrs.LastOrDefault() as IDbFieldAttribute; } + public static IDbFieldAttribute GetDbAttribute(string propertyName) + { + var type = typeof(T); + var propr = type.GetProperty(propertyName); + var attrs = propr?.GetCustomAttributes(typeof(IDbFieldAttribute), true); + return attrs?.LastOrDefault() as IDbFieldAttribute; + } + } diff --git a/ACUtils.SqlDb/ACUtils.SqlDb.csproj b/ACUtils.SqlDb/ACUtils.SqlDb.csproj index 794799b..79e0234 100644 --- a/ACUtils.SqlDb/ACUtils.SqlDb.csproj +++ b/ACUtils.SqlDb/ACUtils.SqlDb.csproj @@ -5,8 +5,8 @@ Andrea Cattaneo true false - 1.0.0.154 - 1.0.0.154 + 1.0.0.155 + 1.0.0.155 Utility per interrogazione database MSSQL it true diff --git a/ACUtils.SqlDb/SqlDb.cs b/ACUtils.SqlDb/SqlDb.cs index 5fa0129..8675e2c 100644 --- a/ACUtils.SqlDb/SqlDb.cs +++ b/ACUtils.SqlDb/SqlDb.cs @@ -254,7 +254,7 @@ public static DataTable ToDataTable(IEnumerable l_oItems) int i; //#### Collect the a_oProperties for the passed T - System.Reflection.PropertyInfo[] a_oProperties = typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + System.Reflection.PropertyInfo[] a_oProperties = typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Where(p => p.CanRead && !p.DeclaringType.IsConstructedGenericType).ToArray(); //#### Traverse each oProperty, .Add'ing each .Name/.BaseType into our oReturn value //#### NOTE: The call to .BaseType is required as DataTables/DataSets do not support nullable types, so it's non-nullable counterpart Type is required in the .Column definition diff --git a/ACUtils.SqlDb/SqlDb_BulkInsert.cs b/ACUtils.SqlDb/SqlDb_BulkInsert.cs index e2bae0f..a0d91b1 100644 --- a/ACUtils.SqlDb/SqlDb_BulkInsert.cs +++ b/ACUtils.SqlDb/SqlDb_BulkInsert.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Data; using System.Data.SqlClient; +using System.Linq; namespace ACUtils { @@ -16,6 +17,7 @@ public static void BulkInsert(this SqlDb self, string tablename, IEnumerable< } } } + public static async System.Threading.Tasks.Task BulkInsertAsync(this SqlDb self, string tablename, IEnumerable records) { using (var connection = await self._getConnectionAsync()) @@ -30,10 +32,11 @@ public static async System.Threading.Tasks.Task BulkInsertAsync(this SqlDb se internal static DataTable BulkInsertPrepare(this SqlDb self, SqlBulkCopy bc, string tablename, IEnumerable records) { bc.DestinationTableName = tablename; - var properties = typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + var properties = typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Where(p => p.CanRead && !p.DeclaringType.IsConstructedGenericType); foreach (var property in properties) { - bc.ColumnMappings.Add(property.Name, property.Name); + var attr = DBModel.GetDbAttribute(propertyName: property.Name); + bc.ColumnMappings.Add(property.Name, attr?.DbField ?? property.Name); } return SqlDb.ToDataTable(records); } diff --git a/Tests/SqlDbTest.cs b/Tests/SqlDbTest.cs index b28a15f..a3cf42f 100644 --- a/Tests/SqlDbTest.cs +++ b/Tests/SqlDbTest.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Transactions; @@ -156,9 +157,10 @@ public void TestQueryDictionary() } - class DbPerson: ACUtils.DBModel + class DbPerson : ACUtils.DBModel { - public int BusinessEntityID { get; set; } + [DbField("BusinessEntityID")] + public int Id { get; set; } public string PersonType { get; set; } public string Title { get; set; } public string FirstName { get; set; } @@ -175,5 +177,54 @@ public void TestQueryMany() Assert.AreEqual(count, allPersons.ToList().Count); } + + + [TestCase(100, false)] + [TestCase(100, true)] + public void TestBulkInsert(int rows, bool async) + { + // prepare + var nextId = db.QuerySingleValue("SELECT MAX(BusinessEntityID) + 1 FROM Person.Person"); + var initialCount = db.QuerySingleValue("SELECT COUNT(*) FROM Person.Person"); + var objects = new List(); + for (int i = nextId; i < (nextId + rows); i++) + { + objects.Add(new DbPerson() + { + Id = i, + PersonType = "EM", + Title = "Test", + FirstName = $"FirstName {i}", + MiddleName = $"MiddleName {i}", + LastName = $"LastName {i}", + }); + } + + // execute + if (async) + { + db.BulkInsertAsync("Person.Person", objects).Wait(); + } + else + { + db.BulkInsert("Person.Person", objects); + } + + // test + var finalCount = db.QuerySingleValue("SELECT COUNT(*) FROM Person.Person"); + Assert.AreEqual(initialCount + rows, finalCount); + + foreach (var person in objects) + { + Assert.IsTrue(person.Id > 0); + var dr = db.QueryDataRow("SELECT * FROM Person.Person WHERE BusinessEntityID = @ID", "@ID".WithValue(person.Id)); + Assert.AreEqual(person.Id, dr.Field("BusinessEntityID")); + Assert.AreEqual(person.PersonType, dr.Field("PersonType")); + Assert.AreEqual(person.Title, dr.Field("Title")); + Assert.AreEqual(person.FirstName, dr.Field("FirstName")); + Assert.AreEqual(person.MiddleName, dr.Field("MiddleName")); + Assert.AreEqual(person.LastName, dr.Field("LastName")); + } + } } } diff --git a/Tests/SqlDbUtilsTest.cs b/Tests/SqlDbUtilsTest.cs index d0c2d20..0e3cd0b 100644 --- a/Tests/SqlDbUtilsTest.cs +++ b/Tests/SqlDbUtilsTest.cs @@ -17,11 +17,20 @@ public class TestDbModel : DBModel public int? nullableIntValue { get; set; } public int intValue { get; set; } public decimal decimalValue { get; set; } + [DbField("DB_FILE_NAME_FLOAT")] public float floatValue { get; set; } public DateTime datetimeValue { get; set; } } + internal class TestGetDbAttributeClass: DBModel + { + public decimal decimalValue { get; set; } + [DbField("DB_FILE_NAME_FLOAT")] + public float floatValue { get; set; } + public DateTime datetimeValue { get; set; } + } + [TestFixture] class SqlDbUtilsTest { @@ -41,7 +50,7 @@ void _generateDt() _testDt.Columns.Add("stringValue", typeof(string)); _testDt.Columns.Add("intValue", typeof(int)); _testDt.Columns.Add("decimalValue", typeof(decimal)); - _testDt.Columns.Add("floatValue", typeof(float)); + _testDt.Columns.Add("DB_FILE_NAME_FLOAT", typeof(float)); _testDt.Columns.Add("datetimeValue", typeof(DateTime)); for (int i = 0; i < DT_SIZE; i++) { @@ -49,7 +58,7 @@ void _generateDt() dr["stringValue"] = i.ToString(); dr["intValue"] = i; dr["decimalValue"] = new Decimal(i / 2); - dr["floatValue"] = (float)i / 2; + dr["DB_FILE_NAME_FLOAT"] = (float)i / 2; dr["datetimeValue"] = DateTime.Now; _testDt.Rows.Add(dr); } @@ -79,6 +88,25 @@ public void testIdrateObj() } } + + [Test] + public void testGetDbAttribute() + { + Assert.AreEqual("DB_FILE_NAME_FLOAT", DBModel.GetDbAttribute("floatValue").DbField); + Assert.AreEqual("DB_FILE_NAME_FLOAT", DBModel.GetDbAttribute("floatValue").DbField); + + var model = new TestDbModel(); + Assert.AreEqual("DB_FILE_NAME_FLOAT", model.GetDbAttribute("floatValue").DbField); + + var model2 = new TestGetDbAttributeClass(); + Assert.AreEqual("DB_FILE_NAME_FLOAT", model2.GetDbAttribute("floatValue").DbField); + + + Assert.IsNull(DBModel.GetDbAttribute("stringValue")); + + Assert.IsNull(DBModel.GetDbAttribute("not exists property")); + } + [Test] public void testStaticIdrate() {