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