使用Dapper Extensions消息“没有列映射”的异常

时间:2017-07-11 10:39:03

标签: c# dapper sqlconnection dapper-extensions

我有class实现了一些interface

public interface IDb {}
public class DbModel : IDb {}

在此之后,我使用Dapper Extensions将对象插入数据库。这段代码效果很好:

var obj = new DbModel();
sqlConnection.Insert(obj); 

但是当我尝试插入这个class的实例,在相应的interface上进行投射时,它会产生例外:

IDb obj = new DbModel();
sqlConnection.Insert(obj); // exception here
  

System.ArgumentException:'没有列映射。'

1 个答案:

答案 0 :(得分:0)

无效的原因:

DapperExtensions.Insert方法是通用的事实开始,DapperExstensions无法找到IDb的相应地图

<强>解决方案:

IDb创建mapper类并注册DbModel属性

public sealed class IDbMapper : ClassMapper<IDb>
{
    public IDbMapper()
    {
        base.Table("TableName");
        Map(m => new DbModel().Title);
        // and such mapping for other properties
    }
}

在此之后它将起作用:

IDb obj = new DbModel();
sqlConnection.Insert(obj);
  

但是当我们有许多IDb的实现时,这是一个问题   接口,在IDbMapper配置中我们无法将列映射到相应的   这里的表格:

base.Table("TableName");
Map(m => new DbModel().Title);
     

因为我们在进行映射时不知道对象实例的类型。

修改

经过一些调试后,我注意到,在每个Insert方法调用中,dapper都会进行映射,并构造相应的ClassMapper<>类。我们可以使用这种古怪。

为此,我们应该在调用Insert方法之前创建SharedState并在其中存储实例类型。

public static class DapperExstensionsExstensions
{
    public static Type SharedState_ModelInstanceType { get; set; }
    ...
}

IDb obj = new DbModel();
DapperExstensionsExstensions.SharedState_ModelInstanceType = obj.GetType();
sqlConnection.Insert(obj);

在此之后,我们可以在Dapper进行映射时访问此属性

public sealed class IDbMapper : ClassMapper<IDb>
{
    public IDbMapper()
    {
         // here we can retrieve Type of model instance and do mapping using reflection
         DapperExstensionsExstensions.SharedState_ModelInstanceType
    }
}

整个代码段:

public interface IDb { }

[MapConfig("TableName", "Schema")]
public class DbTemp : IDb
{
    public string Title { get; set; }
}

public class MapConfigAttribute : Attribute
{
    public MapConfigAttribute(string name, string schema)
    {
        Name = name;
        Schema = schema;
    }
    public string Name { get; }
    public string Schema { get; }
}

public sealed class DbMapper : ClassMapper<IDb>
{
    public DbMapper()
    {
        DapperExstensionsExstensions.CorrespondingTypeMapper<IDb>((tableName, sechemaName, exprs) =>
        {
            Table(tableName);
            Schema(SchemaName);
            return exprs.Select(Map);
        });
    }
}

public static class DapperExstensionsExstensions
{
    private static readonly object _LOCK = new object();
    public static Type SharedState_ModelInstanceType { get; set; }
    public static List<PropertyMap> CorrespondingTypeMapper<T>(Func<string, string, IEnumerable<Expression<Func<T, object>>>, IEnumerable<PropertyMap>> callback)
    {
        var tableNameAttribute = (MapConfigAttribute)SharedState_ModelInstanceType.GetCustomAttribute(typeof(MapConfigAttribute));
        var tableName = tableNameAttribute.Name;
        var schemaName = tableNameAttribute.Schema;
        var result = callback(tableName, schemaName, new GetPropertyExpressions<T>(SharedState_ModelInstanceType));
        Monitor.Exit(_LOCK);
        return result.ToList();
    }
    public static object Insert<TInput>(this IDbConnection connection, TInput entity) where TInput : class
    {
        Monitor.Enter(_LOCK);
        SharedState_ModelInstanceType = entity.GetType();
        return DapperExtensions.DapperExtensions.Insert(connection, entity);
    }
}

public class GetPropertyExpressions<TInput> : IEnumerable<Expression<Func<TInput, object>>>
{
    private readonly Type _instanceType;

    public GetPropertyExpressions(Type instanceType)
    {
        _instanceType = instanceType;
    }
    public IEnumerator<Expression<Func<TInput, object>>> GetEnumerator()
    {
        return _instanceType
            .GetProperties()
            .Select(p => new GetPropertyExpression<TInput>(_instanceType, p.Name).Content()).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

public class GetPropertyExpression<TInput> : IContent<Expression<Func<TInput, object>>>
{
    private readonly Type _instanceType;
    private readonly string _propertyName;
    public GetPropertyExpression(Type instanceType, string propertyName)
    {
        _instanceType = instanceType;
        _propertyName = propertyName;
    }
    public Expression<Func<TInput, object>> Content()
    {
        // Expression<Func<IDb, object>> :: model => (object)(new DbModel().Title)

        var newInstance = Expression.New(_instanceType);
        var parameter = Expression.Parameter(typeof(TInput), "model");

        var getPropertyExpression = Expression.Property(newInstance, _propertyName);
        var convertedProperty = Expression.Convert(getPropertyExpression, typeof(object));
        var lambdaExpression = Expression.Lambda(convertedProperty, parameter);

        return (Expression<Func<TInput, object>>)lambdaExpression;
    }
}

它对我有用

IDb obj = new DbModel();
sqlConnection.Insert(obj);