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 does not respect ignored properties on POCO and tries to insert unmapped types #290

Closed ALMMa closed 2 years ago

ALMMa commented 2 years ago

Affected versions: 1.7.0 (worked on 1.6.3)

Consider the POCO:

public class MyType
{
   public int Id { get; set; }
   public string Name { get; set; }
   public MyOtherType Other { get; set; }
}

public class MyOtherType
{
   public int Id { get; set; }
   public string Name { get; set; }
}

And the class map:

public class MyTypeMap : ClassMap<MyType>
{
   public MyTypeMap()
   {
      Table("Table_1");

      Map(x => x.Id).Column("Id").Key(KeyType.Identity);
      Map(x => x.Name).Column("Name");
      Map(x => x.Other).Ignore();
   }
}

public class MyOtherTypeMap : ClassMap<MyOtherType>
{
   public MyOtherTypeMap()
   {
      Table("Table_2");

      Map(x => x.Id).Column("Id").Key(KeyType.Assigned);
      Map(x => x.Name).Column("Name");
   }
}

When I try to perform an insertion on MyType it gives a Dapper error:

The member i_... of type MyOtherType cannot be used as a parameter value in Dapper.SqlMapper.LookupDbType(Type type, String name, Boolean demand, ITypeHandler& handler) in /_/Dapper/SqlMapper.cs:line 367 in Dapper.DynamicParameters.AddParameters(IDbCommand command, Identity identity) in /_/Dapper/DynamicParameters.cs:line 238 Dapper.CommandDefinition.SetupCommand(IDbConnection cnn, Action2 paramReader) in /\_/Dapper/CommandDefinition.cs:line 129 in Dapper.SqlMapper.<QueryImpl>d__1401.MoveNext() in /_/Dapper/SqlMapper.cs:line 1091

Going step by step on the flow, I have found that InternalInsert<T> builds the dynamic parameters from the type instead of relying on the class map:

https://github.com/tmsmith/Dapper-Extensions/blob/master/DapperExtensions/DapperImplementor.cs#L698

This leads to all public properties from the type being present on the parameters, instead of only the mapped ones.

Changing

dynamicParameters = GetDynamicParameters(entity, dynamicParameters, keyColumn, true);

to

dynamicParameters = GetDynamicParameters(classMap, entity, true);

seems to fix this, but I'm still testing to validate on both simple and complex models, to avoid side effects.

valfrid-ly commented 2 years ago

Duplicate from Issu #289