diff --git a/DynamORM.Tests/DynamORM.Tests.csproj b/DynamORM.Tests/DynamORM.Tests.csproj
index b34fc80..2772e40 100644
--- a/DynamORM.Tests/DynamORM.Tests.csproj
+++ b/DynamORM.Tests/DynamORM.Tests.csproj
@@ -77,7 +77,6 @@
-
diff --git a/DynamORM.Tests/Modify/DynamicTypeSchemaModificationTests.cs b/DynamORM.Tests/Modify/DynamicTypeSchemaModificationTests.cs
index 6e1ef5f..f29d559 100644
--- a/DynamORM.Tests/Modify/DynamicTypeSchemaModificationTests.cs
+++ b/DynamORM.Tests/Modify/DynamicTypeSchemaModificationTests.cs
@@ -42,25 +42,28 @@ namespace DynamORM.Tests.Modify
{
return Database.Table();
}
-
+
+ ///
+ /// Tests the bulk insert.
+ ///
[Test]
public void TestBulkInsert()
{
- Assert.AreEqual(2, Database.Insert(new List
- {
+ Assert.AreEqual(2, Database.Insert(new List
+ {
new users
{
- id = 1001,
- login = "a",
+ id = 1001,
+ login = "a",
},
new users
{
- id = 1002,
- login = "b",
+ id = 1002,
+ login = "b",
}
- }));
-
- Assert.AreEqual(2, Database.Delete().Where(u => u.users.id.In(1001, 1002)).Execute());
+ }));
+
+ Assert.AreEqual(2, Database.Delete().Where(u => u.users.id.In(1001, 1002)).Execute());
}
}
}
\ No newline at end of file
diff --git a/DynamORM/DynamicDatabase.cs b/DynamORM/DynamicDatabase.cs
index c26ed97..fa3157a 100644
--- a/DynamORM/DynamicDatabase.cs
+++ b/DynamORM/DynamicDatabase.cs
@@ -286,59 +286,106 @@ namespace DynamORM
{
return new DynamicInsertQueryBuilder(this).Table(typeof(T));
}
-
+
+ /// Bulk insert objects into database.
+ /// Type of objects to insert.
+ /// Enumerable containing instances of objects to insert.
+ /// Number of inserted rows.
public virtual int Insert(IEnumerable e) where T : class
{
- int affected = 0;
- var mapper = DynamicMapperCache.GetMapper(typeof(T));
-
- if (mapper != null)
- using (var con = Open())
- using (var tra = con.BeginTransaction())
- using (var cmd = con.CreateCommand())
- {
- try
- {
- DynamicPropertyInvoker currentprop = null;
- var temp = new Dictionary();
- var parameters = new Dictionary();
-
- var ib = Insert()
- .SetVirtualMode(true)
- .CreateTemporaryParameterAction(p => temp[p.Name] = currentprop)
- .CreateParameterAction((p, cp) => parameters[cp] = temp[p.Name]);
-
- foreach (var prop in mapper.PropertyMap)
- if (!mapper.Ignored.Contains(prop.Key))
- {
- var col = mapper.PropertyMap.TryGetValue(prop.Key) ?? prop.Key;
- currentprop = mapper.ColumnsMap.TryGetValue(col.ToLower());
-
- if (currentprop.Get != null)
- ib.Insert(col, null);
- }
-
- ib.FillCommand(cmd);
-
- foreach (var o in e)
- {
- foreach (var m in parameters)
- m.Key.Value = m.Value.Get(o);
-
- affected += cmd.ExecuteNonQuery();
- }
-
- tra.Commit();
- }
- catch
- {
- if (tra != null)
- tra.Rollback();
-
- throw;
- }
- }
-
+ int affected = 0;
+ var mapper = DynamicMapperCache.GetMapper(typeof(T));
+
+ if (mapper != null)
+ {
+ using (var con = Open())
+ using (var tra = con.BeginTransaction())
+ using (var cmd = con.CreateCommand())
+ {
+ try
+ {
+ var parameters = new Dictionary();
+
+ if (!string.IsNullOrEmpty(mapper.InsertCommandText))
+ {
+ cmd.CommandText = mapper.InsertCommandText;
+
+ foreach (var col in mapper.ColumnsMap.Values
+ .Where(di => !di.Ignore && di.InsertCommandParameter != null)
+ .OrderBy(di => di.InsertCommandParameter.Ordinal))
+ {
+ var para = cmd.CreateParameter();
+ para.ParameterName = col.InsertCommandParameter.Name;
+ para.DbType = col.InsertCommandParameter.Type;
+ cmd.Parameters.Add(para);
+
+ parameters[para] = col;
+ }
+ }
+ else
+ {
+ DynamicPropertyInvoker currentprop = null;
+ var temp = new Dictionary();
+ int ord = 0;
+
+ var ib = Insert()
+ .SetVirtualMode(true)
+ .CreateTemporaryParameterAction(p => temp[p.Name] = currentprop)
+ .CreateParameterAction((p, cp) =>
+ {
+ parameters[cp] = temp[p.Name];
+ parameters[cp].InsertCommandParameter = new DynamicPropertyInvoker.ParameterSpec
+ {
+ Name = cp.ParameterName,
+ Type = cp.DbType,
+ Ordinal = ord++,
+ };
+ });
+
+ foreach (var prop in mapper.PropertyMap)
+ if (!mapper.Ignored.Contains(prop.Key))
+ {
+ var col = mapper.PropertyMap.TryGetValue(prop.Key) ?? prop.Key;
+ currentprop = mapper.ColumnsMap.TryGetValue(col.ToLower());
+
+ if (currentprop.Ignore)
+ continue;
+
+ if (currentprop.Get != null)
+ ib.Insert(col, null);
+ }
+
+ ib.FillCommand(cmd);
+
+ // Cache command
+ mapper.InsertCommandText = cmd.CommandText;
+ }
+
+ foreach (var o in e)
+ {
+ foreach (var m in parameters)
+ m.Key.Value = m.Value.Get(o);
+
+ affected += cmd.ExecuteNonQuery();
+ }
+
+ tra.Commit();
+ }
+ catch (Exception ex)
+ {
+ if (tra != null)
+ tra.Rollback();
+
+ affected = 0;
+
+ var exCmd = new StringBuilder();
+ cmd.Dump(exCmd);
+
+ throw new InvalidOperationException(exCmd.ToString(), ex);
+ }
+ }
+ }
+
return affected;
}
@@ -366,6 +413,113 @@ namespace DynamORM
return new DynamicUpdateQueryBuilder(this).Table(typeof(T));
}
+ /// Bulk update objects into database.
+ /// Type of objects to update.
+ /// Enumerable containing instances of objects to update.
+ /// Number of updated rows.
+ public virtual int Update(IEnumerable e) where T : class
+ {
+ int affected = 0;
+ var mapper = DynamicMapperCache.GetMapper(typeof(T));
+
+ if (mapper != null)
+ {
+ using (var con = Open())
+ using (var tra = con.BeginTransaction())
+ using (var cmd = con.CreateCommand())
+ {
+ try
+ {
+ var parameters = new Dictionary();
+
+ if (!string.IsNullOrEmpty(mapper.UpdateCommandText))
+ {
+ cmd.CommandText = mapper.UpdateCommandText;
+
+ foreach (var col in mapper.ColumnsMap.Values
+ .Where(di => !di.Ignore && di.UpdateCommandParameter != null)
+ .OrderBy(di => di.UpdateCommandParameter.Ordinal))
+ {
+ var para = cmd.CreateParameter();
+ para.ParameterName = col.UpdateCommandParameter.Name;
+ para.DbType = col.UpdateCommandParameter.Type;
+ cmd.Parameters.Add(para);
+
+ parameters[para] = col;
+ }
+ }
+ else
+ {
+ DynamicPropertyInvoker currentprop = null;
+ var temp = new Dictionary();
+ int ord = 0;
+
+ var ib = Update()
+ .SetVirtualMode(true)
+ .CreateTemporaryParameterAction(p => temp[p.Name] = currentprop)
+ .CreateParameterAction((p, cp) =>
+ {
+ parameters[cp] = temp[p.Name];
+ parameters[cp].UpdateCommandParameter = new DynamicPropertyInvoker.ParameterSpec
+ {
+ Name = cp.ParameterName,
+ Type = cp.DbType,
+ Ordinal = ord++,
+ };
+ });
+
+ foreach (var prop in mapper.PropertyMap)
+ if (!mapper.Ignored.Contains(prop.Key))
+ {
+ var col = mapper.PropertyMap.TryGetValue(prop.Key) ?? prop.Key;
+ currentprop = mapper.ColumnsMap.TryGetValue(col.ToLower());
+
+ if (currentprop.Ignore)
+ continue;
+
+ if (currentprop.Get != null)
+ {
+ if (currentprop.Column != null && currentprop.Column.IsKey)
+ ib.Where(col, null);
+ else
+ ib.Values(col, null);
+ }
+ }
+
+ ib.FillCommand(cmd);
+
+ // Cache command
+ mapper.UpdateCommandText = cmd.CommandText;
+ }
+
+ foreach (var o in e)
+ {
+ foreach (var m in parameters)
+ m.Key.Value = m.Value.Get(o);
+
+ affected += cmd.ExecuteNonQuery();
+ }
+
+ tra.Commit();
+ }
+ catch (Exception ex)
+ {
+ if (tra != null)
+ tra.Rollback();
+
+ affected = 0;
+
+ var exCmd = new StringBuilder();
+ cmd.Dump(exCmd);
+
+ throw new InvalidOperationException(exCmd.ToString(), ex);
+ }
+ }
+ }
+
+ return affected;
+ }
+
///
/// Adds to the DELETE FROM clause the contents obtained by parsing the dynamic lambda expressions given. The supported
/// formats are:
diff --git a/DynamORM/Mapper/DynamicPropertyInvoker.cs b/DynamORM/Mapper/DynamicPropertyInvoker.cs
index 13fd773..ebeb599 100644
--- a/DynamORM/Mapper/DynamicPropertyInvoker.cs
+++ b/DynamORM/Mapper/DynamicPropertyInvoker.cs
@@ -27,6 +27,7 @@
*/
using System;
+using System.Data;
using System.Linq.Expressions;
using System.Reflection;
@@ -35,6 +36,15 @@ namespace DynamORM.Mapper
/// Dynamic property invoker.
public class DynamicPropertyInvoker
{
+ internal class ParameterSpec
+ {
+ public string Name { get; set; }
+
+ public DbType Type { get; set; }
+
+ public int Ordinal { get; set; }
+ }
+
/// Gets the type of property.
public Type Type { get; private set; }
@@ -105,5 +115,13 @@ namespace DynamORM.Mapper
Expression.Convert(valueParm, property.PropertyType)),
objParm, valueParm).Compile();
}
+
+ #region Type command cache
+
+ internal ParameterSpec InsertCommandParameter { get; set; }
+
+ internal ParameterSpec UpdateCommandParameter { get; set; }
+
+ #endregion Type command cache
}
}
\ No newline at end of file
diff --git a/DynamORM/Mapper/DynamicTypeMap.cs b/DynamORM/Mapper/DynamicTypeMap.cs
index b3b2eb9..f6ade3f 100644
--- a/DynamORM/Mapper/DynamicTypeMap.cs
+++ b/DynamORM/Mapper/DynamicTypeMap.cs
@@ -28,7 +28,6 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Linq.Expressions;
namespace DynamORM.Mapper
@@ -92,9 +91,9 @@ namespace DynamORM.Mapper
columnMap.Add(col.ToLower(), val);
propertyMap.Add(pi.Name, col);
-
+
if (val.Ignore)
- ignored.Add(pi.Name);
+ ignored.Add(pi.Name);
}
ColumnsMap = columnMap;
@@ -136,5 +135,13 @@ namespace DynamORM.Mapper
return destination;
}
+
+ #region Type command cache
+
+ internal string InsertCommandText { get; set; }
+
+ internal string UpdateCommandText { get; set; }
+
+ #endregion Type command cache
}
}
\ No newline at end of file