tmsmith / Dapper-Extensions

Dapper Extensions is a small library that complements Dapper by adding basic CRUD operations (Get, Insert, Update, Delete) for your POCOs. For more advanced querying scenarios, Dapper Extensions provides a predicate system. The goal of this library is to keep your POCOs pure by not requiring any attributes or base class inheritance.
1.79k stars 586 forks source link

Insert error about multithreading #303

Closed ellenfier closed 1 year ago

ellenfier commented 2 years ago

I have met the problem:

MySql.Data.MySqlClient.MySqlException:“Fatal error encountered during command execution.” MySqlException: Parameter '@i_1' must be defined.

And I noticed the key of 'dynamicParameters.ParamInfo' isn't correct. some key values are @i_1, @i_2..., and some are the name of the Property, like FirstName, LastName.

So I modified part of the code of 'SqlGeneratorImpl' for myown and now it works fine. Like this: 'SqlGeneratorImpl.Insert(IClassMapper classMapper)'

        AllColumns = GetColumns().Select(c => new Column
        {
            Alias = c.Alias,
            ClassMapper = c.ClassMapper,
            Property = c.Property,
            SimpleAlias = $"{Configuration.Dialect.ParameterPrefix}i_{i++}",
            TableIdentity = c.TableIdentity,
            Table = c.Table
        }).ToList<IColumn>();

        //AllColumns = GetColumns().ToList();
        //AllColumns = AllColumns.Select(c => new Column
        //{
        //    Alias = c.Alias,
        //    ClassMapper = c.ClassMapper,
        //    Property = c.Property,
        //    SimpleAlias = $"{Configuration.Dialect.ParameterPrefix}i_{i++}",
        //    TableIdentity = c.TableIdentity,
        //    Table = c.Table
        //}).ToList<IColumn>();
valfrid-ly commented 2 years ago

Except for changing

AllColumns = GetColumns().ToList(); AllColumns = AllColumns.Select(c => new ColumnAllColumns = GetColumns().Select(c => new Column

for

AllColumns = GetColumns().Select(c => new Column

I see no difference in your code that justifies any change in the key

ellenfier commented 2 years ago

Well, I use a local variable 'allColumns' instead of AllColumns and a ConcurrentDictionary to keep the columns value.

var allColumns = GetColumns().Select(c => new Column()).ToList(); // or _dictionary[classMapper]
//AllColumns = GetColumns().ToList();
//******
AllColumns = allColumns;

The method 'DapperImplementor.GetSimpleAliasFromColumnAlias(string columnAlias)' will return the value of SimpleAlias. And if it is null or empty, the key of DynamicParameter will be the PropertyInfo.Name instead of SimpleAlias. When the method GetSimpleAliasFromColumnAlias is invoked by a thread, and at the same time AllColumns = GetColumns().ToList() is invoked by another thread, the problem happens. It's now thread safe.

I also change the method GetSimpleAliasFromColumnAlias. like SqlGenerator.GetColumnsByClassMapper(prop.ClassMapper).Any(c => c.Alias.Equals....

valfrid-ly commented 2 years ago

Would you be able to send a PR with your changes??

Please, don't forget to update the unit tests too.