Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PostgreSQL BulkUpdate action thowing: System.ArgumentNullException: Value cannot be null. (Parameter 'key') #97

Open
eymenkhater opened this issue Jul 29, 2021 · 5 comments
Assignees

Comments

@eymenkhater
Copy link

Hello there!
Trying to execute BulkUpdate action but getting the following error:

fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
An unhandled exception has occurred while executing the request.
System.Exception: An error occured while retrieving the InformationSchemaTable information. See the inner exception for details.
---> System.ArgumentNullException: Value cannot be null. (Parameter 'key')
at System.Collections.Generic.Dictionary2.TryInsert(TKey key, TValue value, InsertionBehavior behavior) at System.Collections.Generic.Dictionary2.Add(TKey key, TValue value)
at System.Linq.Enumerable.ToDictionary[TSource,TKey](List1 source, Func2 keySelector, IEqualityComparer1 comparer) at System.Linq.Enumerable.ToDictionary[TSource,TKey](IEnumerable1 source, Func2 keySelector, IEqualityComparer1 comparer)
at .(Boolean , String[] )
at .()
at Z.BulkOperations.BulkOperation.()
--- End of inner exception stack trace ---
at Z.BulkOperations.BulkOperation.()
at Z.BulkOperations.BulkOperation.Execute()
at Z.BulkOperations.BulkOperation.BulkUpdate()
at Z.Dapper.Plus.DapperPlusAction.Execute()
at Z.Dapper.Plus.DapperPlusActionSet1.AddAction(String mapperKey, DapperPlusActionKind actionKind, TEntity item) at Z.Dapper.Plus.DapperPlusActionSet1.DapperPlusActionSetBuilder(DapperPlusContext context, IDbConnection connection, IDbTransaction transaction, String mapperKey, DapperPlusActionKind actionKind, TEntity item, Func2[] selectors) at Z.Dapper.Plus.DapperPlusActionSet1..ctor(DapperPlusContext context, IDbConnection connection, String mapperKey, DapperPlusActionKind actionKind, TEntity item, Func2[] selectors) at Z.Dapper.Plus.DapperPlusExtensions.BulkUpdate[T](IDbConnection connection, String mapperKey, T item, Func2[] selectors)
at Z.Dapper.Plus.DapperPlusExtensions.BulkUpdate[T](IDbConnection connection, T item, Func`2[] selectors)

The method

   public async Task<bool> BulkUpdateAsync(List<ProductItemStock> productItemStocks)
    {
        DapperPlusManager.Entity<ProductItemStock>().Table("ProductItemStocks").Identity(q => q.Id).Ignore(q => q.StoragePath);
        using (var connection = await _postgreSQLDbConnectionFactory.CreateAsync())
        {
            connection.BulkUpdate(productItemStocks);
        }
        return true;
    }

Details of object

public abstract class _Domain<TKey> : IDomain<TKey>
{
    public TKey Id { get; set; }
    public bool IsDeleted { get; set; }
}

public class ProductItemStock : _Domain<int>
{
    public ProductItemStock() { }
    public ProductItemStock(int productItemId, int storagePathId, int stock)
    {
        this.ProductItemId = productItemId;
        this.StoragePathId = storagePathId;
        this.Stock = stock;
    }
    public int ProductItemId { get; set; }
    public int StoragePathId { get; set; }
    public int Stock { get; set; }
    public int ReservedStock { get; set; }
    public StoragePath StoragePath { get; set; }
  }

I tried the update action with Dapper.Contrib and was able to successfully update.

The object values:

Screen Shot 2021-07-29 at 18 30 03

Packages which I using:
Z.Dapper.Plus version 4.0.9
Npgsql version 5.0.7

@JonathanMagnan JonathanMagnan self-assigned this Jul 29, 2021
@JonathanMagnan
Copy link
Member

Hello @eymenkhater ,

The issue happens because you are currently using a global mapping inside a method. This means every time the method is called, you currently rewrite this mapping and an error happens due to concurrency.

When using a global mapping, the code should be called only once such as during the application startup. This is still possible to use a mapping inside a method but you need to use an Instance Context Mapping for this.

See the following documentation to learn more about the mapping: https://dapper-plus.net/getting-started-mapping

You will find out the difference between:

  • Global Context Mapping
  • Inheritance Context Mapping
  • Instance Context Mapping

and mapper key for handling more special scenarios such as this one you wish to ignore the StoragePath.

Let me know if that explains correctly why this happens and how you can fix it.

Best Regards,

Jon

@eymenkhater
Copy link
Author

eymenkhater commented Jul 30, 2021

Hello @JonathanMagnan,

I have updated the method. I moved the global method into a static class (DapperPlusGlobalMapping) inside the SetGlobalMapping method and called the method from Startup but I still get the same error. Is there a point I missed?

    public async Task<bool> BulkUpdateAsync(List<ProductItemStock> productItemStocks)
    {
        using (var connection = await _postgreSQLDbConnectionFactory.CreateAsync())
        {
            connection.BulkUpdate(productItemStocks);
        }
        return true;
    }

DapperPlusGlobalMapping.cs

    public static void SetGlobalMapping()
    {
        DapperPlusManager.Entity<ProductItemStock>().Identity(q => q.Id, true).Ignore(q => q.StoragePath);
    }

StartupSetup.cs

    public static IServiceCollection AddOrderModuleInfrastructure(this IServiceCollection services, IConfiguration configuration)
    {
        DapperPlusGlobalMapping.SetGlobalMapping();
        return services;
    }

@JonathanMagnan
Copy link
Member

Hello @eymenkhater ,

I don't think you miss anything. But perhaps there is a little piece of the puzzle we are missing.

Here is a quick fiddle I made with your mapping: https://dotnetfiddle.net/SDfDZ1

Is it possible for you to update it or provide us a project with the minimum code required to reproduce this error? You can send it in private if needed here: [email protected]

There is a good chance that indeed our library has an issue with your inheritance for example but I'm not sure how is done your _Domain interface and StoragePath class.

Best Regards,

Jon

@eymenkhater
Copy link
Author

Hello @JonathanMagnan,

Sounds good. I will send you soon.

@JonathanMagnan
Copy link
Member

Hello @eymenkhater ,

Thank you for the project, we indeed have an error on our side.

The problem is that the entity ProductItemStock is mapped to the table to productitemstock (singular) but your table name is productitemstocks (plural).

To fix it, you can specify the table mapping to fix this issue this way:

DapperPlusManager.Entity<ProductItemStock>().Table("productitemstocks").Identity(q => q.Id, true).Ignore(q => q.StoragePath);

On our side, my developer will work on the error message to make sure we make it more explicit about what is happening. We might also look to try to map information to a table name in the plural form when the table name in the singular form (default) is not found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants