我有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:'没有列映射。'
答案 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);