diff --git a/DapperExtensions.StrongName/DapperExtensions.StrongName.csproj b/DapperExtensions.StrongName/DapperExtensions.StrongName.csproj
index 45853560..31adf7ee 100644
--- a/DapperExtensions.StrongName/DapperExtensions.StrongName.csproj
+++ b/DapperExtensions.StrongName/DapperExtensions.StrongName.csproj
@@ -94,53 +94,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/DapperExtensions.Test/IntegrationTests/Async/DatabaseAsyncTestsFixture.cs b/DapperExtensions.Test/IntegrationTests/Async/DatabaseAsyncTestsFixture.cs
index 6018a39c..d2569ad4 100644
--- a/DapperExtensions.Test/IntegrationTests/Async/DatabaseAsyncTestsFixture.cs
+++ b/DapperExtensions.Test/IntegrationTests/Async/DatabaseAsyncTestsFixture.cs
@@ -19,7 +19,7 @@ protected DatabaseAsyncTestsFixture(string configPath = null) : base(configPath)
protected override void CommonSetup(DbConnection connection, SqlDialectBase sqlDialect)
{
var config = DapperAsyncExtensions.Configure(typeof(AutoClassMapper<>), new List(), sqlDialect);
- var sqlGenerator = new SqlGeneratorImpl(config);
+ var sqlGenerator = new ThreadSafeSqlGeneratorImpl(config);
Db = new AsyncDatabase(connection, sqlGenerator);
}
diff --git a/DapperExtensions.Test/IntegrationTests/Async/Sqlite/CrudFixture.cs b/DapperExtensions.Test/IntegrationTests/Async/Sqlite/CrudFixture.cs
index caba104a..7d44b199 100644
--- a/DapperExtensions.Test/IntegrationTests/Async/Sqlite/CrudFixture.cs
+++ b/DapperExtensions.Test/IntegrationTests/Async/Sqlite/CrudFixture.cs
@@ -245,6 +245,40 @@ public void UsingCompositeKey_UpdatesEntity()
Assert.AreEqual("key", m3.Key2);
Assert.AreEqual("barz", m3.Value);
}
+
+ [Test]
+ public async Task AsyncBatch_UsingKey_UpdatesEntity()
+ {
+ Person p1 = new Person
+ {
+ Active = true,
+ FirstName = "Foo",
+ LastName = "Bar",
+ DateCreated = DateTime.UtcNow
+ };
+ var animal = new Animal
+ {
+ Name = "Fizz"
+ };
+ p1.Id = await Db.Insert(p1);
+ animal.Id = await Db.Insert(animal);
+
+ p1.FirstName = "Baz";
+ p1.Active = false;
+
+ animal.Name = "Buzz";
+
+ var task1 = Task.Run(() => Db.Update(p1, ignoreAllKeyProperties: true));
+ var task2 = Task.Run(() => Db.Update(animal, ignoreAllKeyProperties: true));
+ await Task.WhenAll(task1, task2);
+
+ var p1_3 = await Db.Get(p1.Id);
+ Assert.AreEqual("Baz", p1_3.FirstName);
+ Assert.AreEqual("Bar", p1_3.LastName);
+ Assert.AreEqual(false, p1_3.Active);
+ var a2 = await Db.Get(animal.Id);
+ Assert.AreEqual("Buzz", a2.Name);
+ }
}
[TestFixture]
diff --git a/DapperExtensions/DapperAsyncExtensions.cs b/DapperExtensions/DapperAsyncExtensions.cs
index 781481e0..ef080f13 100644
--- a/DapperExtensions/DapperAsyncExtensions.cs
+++ b/DapperExtensions/DapperAsyncExtensions.cs
@@ -60,7 +60,7 @@ public static Func Inst
{
get
{
- return _instanceFactory ??= config => new DapperAsyncImplementor(new SqlGeneratorImpl(_configuration));
+ return _instanceFactory ??= config => new DapperAsyncImplementor(new ThreadSafeSqlGeneratorImpl(_configuration));
}
set
{
diff --git a/DapperExtensions/DapperExtensions.cs b/DapperExtensions/DapperExtensions.cs
index e98c7809..437ec73f 100644
--- a/DapperExtensions/DapperExtensions.cs
+++ b/DapperExtensions/DapperExtensions.cs
@@ -59,7 +59,7 @@ public static Func InstanceF
{
get
{
- return _instanceFactory ??= config => new DapperImplementor(new SqlGeneratorImpl(config));
+ return _instanceFactory ??= config => new DapperImplementor(new ThreadSafeSqlGeneratorImpl(config));
}
set
{
diff --git a/DapperExtensions/Sql/ThreadSafeSqlGeneratorImpl.cs b/DapperExtensions/Sql/ThreadSafeSqlGeneratorImpl.cs
new file mode 100644
index 00000000..42b86dc5
--- /dev/null
+++ b/DapperExtensions/Sql/ThreadSafeSqlGeneratorImpl.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using DapperExtensions.Mapper;
+using DapperExtensions.Predicate;
+
+namespace DapperExtensions.Sql
+{
+ public class ThreadSafeSqlGeneratorImpl : ISqlGenerator
+ {
+
+ [ThreadStatic]
+ private static SqlGeneratorImpl _sqlGeneratorImpl;
+
+ private SqlGeneratorImpl Current => LazyInitializer.EnsureInitialized(ref _sqlGeneratorImpl, () => new SqlGeneratorImpl(Configuration));
+
+ public ThreadSafeSqlGeneratorImpl(IDapperExtensionsConfiguration configuration)
+ {
+ this.Configuration = configuration;
+ }
+
+ public IDapperExtensionsConfiguration Configuration { get; }
+
+ public IList AllColumns => Current.AllColumns;
+
+ public IList MappedTables => Current.MappedTables;
+
+ public bool SupportsMultipleStatements()
+ {
+ return this.Configuration.Dialect.SupportsMultipleStatements;
+ }
+
+
+ public string Select(IClassMapper classMap, IPredicate predicate, IList sort,
+ IDictionary parameters, IList colsToSelect,
+ IList includedProperties = null)
+ {
+ return this.Current.Select(classMap, predicate, sort, parameters, colsToSelect, includedProperties);
+ }
+
+ public string SelectPaged(IClassMapper classMap, IPredicate predicate, IList sort, int page,
+ int resultsPerPage,
+ IDictionary parameters, IList colsToSelect,
+ IList includedProperties = null)
+ {
+ return this.Current.SelectPaged(classMap, predicate, sort, page, resultsPerPage, parameters,
+ colsToSelect, includedProperties);
+
+ }
+
+ public string SelectSet(IClassMapper classMap, IPredicate predicate, IList sort, int firstResult,
+ int maxResults,
+ IDictionary parameters, IList colsToSelect,
+ IList includedProperties = null)
+ {
+ return this.Current.SelectSet(classMap, predicate, sort, firstResult, maxResults, parameters,
+ colsToSelect, includedProperties);
+
+ }
+
+ public string Count(IClassMapper classMap, IPredicate predicate, IDictionary parameters,
+ IList includedProperties = null)
+ {
+ return this.Current.Count(classMap, predicate, parameters, includedProperties);
+ }
+
+ public string Insert(IClassMapper classMap)
+ {
+ return this.Current.Insert(classMap);
+ }
+
+ public string Update(IClassMapper classMap, IPredicate predicate, IDictionary parameters,
+ bool ignoreAllKeyProperties,
+ IList colsToUpdate)
+ {
+ return this.Current.Update(classMap, predicate, parameters, ignoreAllKeyProperties, colsToUpdate);
+ }
+
+ public string Delete(IClassMapper classMap, IPredicate predicate, IDictionary parameters)
+ {
+ return this.Current.Delete(classMap, predicate, parameters);
+ }
+
+ public string IdentitySql(IClassMapper classMap)
+ {
+ return this.Current.IdentitySql(classMap);
+ }
+
+ public string GetTableName(IClassMapper map, bool useAlias = false)
+ {
+ return this.Current.GetTableName(map, useAlias);
+ }
+
+ public string GetColumnName(IClassMapper map, IMemberMap property, bool includeAlias, bool isDml = false,
+ bool includePrefix = true)
+ {
+ return this.Current.GetColumnName(map, property, includeAlias, isDml, includePrefix);
+ }
+
+ public string GetColumnName(IClassMapper map, string propertyName, bool includeAlias, bool includePrefix = true)
+ {
+ return this.Current.GetColumnName(map, propertyName, includeAlias, includePrefix);
+ }
+
+ public string GetColumnName(IColumn column, bool includeAlias, bool includePrefix = true)
+ {
+ return this.Current.GetColumnName(column, includeAlias, includePrefix);
+ }
+ }
+}
\ No newline at end of file