投影图给出类型参数错误
projection map giving type arguments error
我正在尝试使用投影图将 属性 值从源映射到目标,如本问题中所述 Projection mapping 如下所示,但在 select 语句附近出现错误
Error is : The type arguments for the method
'Enumerable.Select<TSource, Tresult>(IEnumerable,
Func<Tsource, int, Tresult>)' cannot be inferred from usage.Try
specifying type arguments explicitly
下面是代码示例
public static IQueryable<TDest> ProjectionMap<TSource, TDest>(IQueryable<TSource> sourceModel)
where TDest : new()
{
var sourceProperties = typeof(TSource).GetProperties().Where(p => p.CanRead);
var destProperties = typeof(TDest).GetProperties().Where(p => p.CanWrite);
var propertyMap = from d in destProperties
join s in sourceProperties on new { d.Name, d.PropertyType } equals new { s.Name, s.PropertyType }
select new { Source = s, Dest = d };
var itemParam = Expression.Parameter(typeof(TSource), "item");
var memberBindings = propertyMap.Select(p => (MemberBinding)Expression.Bind(p.Dest, Expression.Property(itemParam, p.Source)));
var newExpression = Expression.New(typeof(TDest));
var memberInitExpression = Expression.MemberInit(newExpression, memberBindings);
var projection = Expression.Lambda<Func<TSource, TDest>>(memberInitExpression, itemParam);
return sourceModel.Select(projection);
}
然后我在下面使用上面的方法
private static MechanicalData TransformMechanicalData(MechanicalData sourceMechanicalData, Dictionary<string, MasterSection> masterSectionMappedLibrary)
{
return new MechanicalData()
{
Acoustic = sourceMechanicalData.Acoustic
.Where(a => a != null)
.Select(ProjectionMap<LibraryAcoustic, LibraryAcoustic>(sourceMechanicalData.Acoustic.AsQueryable())).ToList() ?? new(),
}
}
谁能告诉我哪里做错了,非常感谢。
更新:
Acoustic = sourceMechanicalData.Acoustic
.Where(a => a != null)
.Select(acoustic => new LibraryAcoustic
{
Id = acoustic.Id,
IsApproved = true,
NoiseCriteria = acoustic.NoiseCriteria,
SourceOfData = acoustic.SourceOfData,
SourceOfDataId = acoustic.SourceOfData.Id,
MasterSection = masterSectionMappedLibrary["Library Acoustic"]
}).ToList() ?? new(),
调用下面的 transformMechanicalData 方法
if (spaceTypeReader.HasRows)
{
while (spaceTypeReader.Read())
{
var id = spaceTypeReader.IsDBNull(0) ? default : Guid.Parse(spaceTypeReader.GetString(0));
var mechanicalDataJson = spaceTypeReader.IsDBNull(1) ? "null" : spaceTypeReader.GetString(1);
var srcMechanicalDataJson = JsonConvert.DeserializeObject<MechanicalData>(mechanicalDataJson);
fixedSpaceTypesMechanicalData[id] = TransformMechanicalData(srcMechanicalDataJson, masterSectionMappedLibrary);
}
}
与机械数据class如
public class MechanicalData
{
public List<LibraryAcoustic> Acoustic { get; set; }
.........
}
更新 2:
图书馆声学模型
public class LibraryAcoustic
{
public double? NoiseCriteria { get; set; }
[ForeignKey("SourceOfData")]
public Guid? SourceOfDataId { get; set; }
public virtual CodeStandardGuideline SourceOfData { get; set; }
public Guid Id { get; set; }
public MasterSection MasterSection { get; set; }
public bool? IsApproved { get; set; }
}
来自模型
"Acoustic": [
{
"Id": "d9254132-d11d-48dd-9b74-c0b60d1e4b8a",
"IsApproved": null,
"SourceOfData": {
"Id": "c5bf3585-50b1-4894-8fad-0ac884343935",
"CodeStandardGuidelineType": "GUIDELINE_OR_STANDARD"
},
"MasterSection": null,
"SourceOfDataId": null,
"NoiseCriteria": 1,
}
],
至型号:
"Acoustic": [
{
"Id": "d9254132-d11d-48dd-9b74-c0b60d1e4b8a",
"IsApproved": true,
"SourceOfData": {
"Id": "c5bf3585-50b1-4894-8fad-0ac88434393",
"CodeStandardGuidelineType": "GUIDELINE_OR_STANDARD"
},
"MasterSection": {Name:"test"},
"SourceOfDataId": "c5bf3585-50b1-4894-8fad-0ac884343935",
"NoiseCriteria": 1,
}
],
测试Class更新:
SourceOfData sourceOfData = new SourceOfData()
{
Id = new Guid("c5bf3585-50b1-4894-8fad-0ac884343935"),
Name = "test"
};
TestClassA170 testClassA170 = new TestClassA170()
{
Category = "test",
SourceOfData = sourceOfData,
SourceOfDataId = null,
IsApproved = true,
MinOutdoorAirACH = 1,
MinTotalAirACH = 2,
DirectExhaust = DirectExhaust.NO,
PressureRelationship = PressureRelationship.NEGATIVE,
RecirculatedAir = RecirculatedAir.NO,
SpaceFunction = "10"
};
List<TestClassA170> list = new List<TestClassA170>();
list.Add(testClassA170);
您必须创建映射助手 class,它另外接受字典作为参数:
public static class PropertyMapper<TSource, TDest>
{
private static Expression<Func<TSource Dictionary<string, MasterSection>, TDest>> _mappingExpression;
private static Func<TSource, Dictionary<string, MasterSection>, TDest> _mapper;
static PropertyMapper()
{
_mappingExpression = ProjectionMap();
_mapper = _mappingExpression.Compile();
}
public static Func<TSource, Dictionary<string, MasterSection>, TDest> Mapper => _mapper;
public static string MasterKeyFromClassName(string className)
{
// you have to do that yourself
throw new NotImplementedException();
}
public static Expression<Func<TSource, Dictionary<string, MasterSection>, TDest>> ProjectionMap()
{
var sourceProperties = typeof(TSource).GetProperties().Where(p => p.CanRead);
var destProperties = typeof(TDest).GetProperties().Where(p => p.CanWrite);
var propertyMap =
from d in destProperties
join s in sourceProperties on new { d.Name, d.PropertyType } equals new { s.Name, s.PropertyType }
where d.Name != "MasterSection"
select new { Source = s, Dest = d };
var itemParam = Expression.Parameter(typeof(TSource), "item");
var dictParam = Expression.Parameter(typeof(Dictionary<string, MasterSection>), "dict");
var memberBindings = propertyMap.Select(p => (MemberBinding)Expression.Bind(p.Dest, Expression.Property(itemParam, p.Source))).ToList();
var masterSectionProp = destProperties.FirstOrDefault(s => s.Name == "MasterSection");
if (masterSectionProp != null)
{
Expression<Func<Dictionary<string, MasterSection>, string, MasterSection>> dictRetrievalTemplate = (dict, value) => dict[value];
var masterPropertyBind = Expression.Bind(masterSectionProp, ExpressionReplacer.GetBody(dictRetrievalTemplate, dictParam, Expression.Constant(MasterKeyFromClassName(typeof(TSource).Name)));
memberBindings.Add(masterPropertyBind);
}
var sourceOfDataProp = destProperties.FirstOrDefault(s => s.Name == "SourceOfDataId");
if (sourceOfDataProp != null)
{
memberBindings.Add(Expression.Bind(sourceOfDataProp, Expression.Property(Expression.Property(itemParam, "SourceOfData"), "Id")));
}
var isApprovedProp = destProperties.FirstOrDefault(s => s.Name == "IsApproved");
if (isApprovedProp != null)
{
memberBindings.Add(Expression.Bind(isApprovedProp, Expression.Constant(true)));
}
var newExpression = Expression.New(typeof(TDest));
var memberInitExpression = Expression.MemberInit(newExpression, memberBindings);
var projection = Expression.Lambda<Func<TSource, Dictionary<string, MasterSection>, TDest>>(memberInitExpression, itemParam, dictParam);
return projection;
}
class ExpressionReplacer : ExpressionVisitor
{
readonly IDictionary<Expression, Expression> _replaceMap;
public ExpressionReplacer(IDictionary<Expression, Expression> replaceMap)
{
_replaceMap = replaceMap ?? throw new ArgumentNullException(nameof(replaceMap));
}
public override Expression Visit(Expression exp)
{
if (exp != null && _replaceMap.TryGetValue(exp, out var replacement))
return replacement;
return base.Visit(exp);
}
public static Expression Replace(Expression expr, Expression toReplace, Expression toExpr)
{
return new ExpressionReplacer(new Dictionary<Expression, Expression> { { toReplace, toExpr } }).Visit(expr);
}
public static Expression Replace(Expression expr, IDictionary<Expression, Expression> replaceMap)
{
return new ExpressionReplacer(replaceMap).Visit(expr);
}
public static Expression GetBody(LambdaExpression lambda, params Expression[] toReplace)
{
if (lambda.Parameters.Count != toReplace.Length)
throw new InvalidOperationException();
return new ExpressionReplacer(Enumerable.Range(0, lambda.Parameters.Count)
.ToDictionary(i => (Expression) lambda.Parameters[i], i => toReplace[i])).Visit(lambda.Body);
}
}
}
然后重写你的函数:
private static Expression<MechanicalData TransformMechanicalData(MechanicalData sourceMechanicalData, Dictionary<string, MasterSection> masterSectionMappedLibrary)
{
return new MechanicalData()
{
Acoustic = sourceMechanicalData.Acoustic
.Where(a => a != null)
.Select(a => PropertyMapper<LibraryAcoustic, LibraryAcoustic>.Mapper(a, masterSectionMappedLibrary)).ToList(),
}
}
我正在尝试使用投影图将 属性 值从源映射到目标,如本问题中所述 Projection mapping 如下所示,但在 select 语句附近出现错误
Error is : The type arguments for the method 'Enumerable.Select<TSource, Tresult>(IEnumerable, Func<Tsource, int, Tresult>)' cannot be inferred from usage.Try specifying type arguments explicitly
下面是代码示例
public static IQueryable<TDest> ProjectionMap<TSource, TDest>(IQueryable<TSource> sourceModel)
where TDest : new()
{
var sourceProperties = typeof(TSource).GetProperties().Where(p => p.CanRead);
var destProperties = typeof(TDest).GetProperties().Where(p => p.CanWrite);
var propertyMap = from d in destProperties
join s in sourceProperties on new { d.Name, d.PropertyType } equals new { s.Name, s.PropertyType }
select new { Source = s, Dest = d };
var itemParam = Expression.Parameter(typeof(TSource), "item");
var memberBindings = propertyMap.Select(p => (MemberBinding)Expression.Bind(p.Dest, Expression.Property(itemParam, p.Source)));
var newExpression = Expression.New(typeof(TDest));
var memberInitExpression = Expression.MemberInit(newExpression, memberBindings);
var projection = Expression.Lambda<Func<TSource, TDest>>(memberInitExpression, itemParam);
return sourceModel.Select(projection);
}
然后我在下面使用上面的方法
private static MechanicalData TransformMechanicalData(MechanicalData sourceMechanicalData, Dictionary<string, MasterSection> masterSectionMappedLibrary)
{
return new MechanicalData()
{
Acoustic = sourceMechanicalData.Acoustic
.Where(a => a != null)
.Select(ProjectionMap<LibraryAcoustic, LibraryAcoustic>(sourceMechanicalData.Acoustic.AsQueryable())).ToList() ?? new(),
}
}
谁能告诉我哪里做错了,非常感谢。
更新:
Acoustic = sourceMechanicalData.Acoustic
.Where(a => a != null)
.Select(acoustic => new LibraryAcoustic
{
Id = acoustic.Id,
IsApproved = true,
NoiseCriteria = acoustic.NoiseCriteria,
SourceOfData = acoustic.SourceOfData,
SourceOfDataId = acoustic.SourceOfData.Id,
MasterSection = masterSectionMappedLibrary["Library Acoustic"]
}).ToList() ?? new(),
调用下面的 transformMechanicalData 方法
if (spaceTypeReader.HasRows)
{
while (spaceTypeReader.Read())
{
var id = spaceTypeReader.IsDBNull(0) ? default : Guid.Parse(spaceTypeReader.GetString(0));
var mechanicalDataJson = spaceTypeReader.IsDBNull(1) ? "null" : spaceTypeReader.GetString(1);
var srcMechanicalDataJson = JsonConvert.DeserializeObject<MechanicalData>(mechanicalDataJson);
fixedSpaceTypesMechanicalData[id] = TransformMechanicalData(srcMechanicalDataJson, masterSectionMappedLibrary);
}
}
与机械数据class如
public class MechanicalData
{
public List<LibraryAcoustic> Acoustic { get; set; }
.........
}
更新 2:
图书馆声学模型
public class LibraryAcoustic
{
public double? NoiseCriteria { get; set; }
[ForeignKey("SourceOfData")]
public Guid? SourceOfDataId { get; set; }
public virtual CodeStandardGuideline SourceOfData { get; set; }
public Guid Id { get; set; }
public MasterSection MasterSection { get; set; }
public bool? IsApproved { get; set; }
}
来自模型
"Acoustic": [
{
"Id": "d9254132-d11d-48dd-9b74-c0b60d1e4b8a",
"IsApproved": null,
"SourceOfData": {
"Id": "c5bf3585-50b1-4894-8fad-0ac884343935",
"CodeStandardGuidelineType": "GUIDELINE_OR_STANDARD"
},
"MasterSection": null,
"SourceOfDataId": null,
"NoiseCriteria": 1,
}
],
至型号:
"Acoustic": [
{
"Id": "d9254132-d11d-48dd-9b74-c0b60d1e4b8a",
"IsApproved": true,
"SourceOfData": {
"Id": "c5bf3585-50b1-4894-8fad-0ac88434393",
"CodeStandardGuidelineType": "GUIDELINE_OR_STANDARD"
},
"MasterSection": {Name:"test"},
"SourceOfDataId": "c5bf3585-50b1-4894-8fad-0ac884343935",
"NoiseCriteria": 1,
}
],
测试Class更新:
SourceOfData sourceOfData = new SourceOfData()
{
Id = new Guid("c5bf3585-50b1-4894-8fad-0ac884343935"),
Name = "test"
};
TestClassA170 testClassA170 = new TestClassA170()
{
Category = "test",
SourceOfData = sourceOfData,
SourceOfDataId = null,
IsApproved = true,
MinOutdoorAirACH = 1,
MinTotalAirACH = 2,
DirectExhaust = DirectExhaust.NO,
PressureRelationship = PressureRelationship.NEGATIVE,
RecirculatedAir = RecirculatedAir.NO,
SpaceFunction = "10"
};
List<TestClassA170> list = new List<TestClassA170>();
list.Add(testClassA170);
您必须创建映射助手 class,它另外接受字典作为参数:
public static class PropertyMapper<TSource, TDest>
{
private static Expression<Func<TSource Dictionary<string, MasterSection>, TDest>> _mappingExpression;
private static Func<TSource, Dictionary<string, MasterSection>, TDest> _mapper;
static PropertyMapper()
{
_mappingExpression = ProjectionMap();
_mapper = _mappingExpression.Compile();
}
public static Func<TSource, Dictionary<string, MasterSection>, TDest> Mapper => _mapper;
public static string MasterKeyFromClassName(string className)
{
// you have to do that yourself
throw new NotImplementedException();
}
public static Expression<Func<TSource, Dictionary<string, MasterSection>, TDest>> ProjectionMap()
{
var sourceProperties = typeof(TSource).GetProperties().Where(p => p.CanRead);
var destProperties = typeof(TDest).GetProperties().Where(p => p.CanWrite);
var propertyMap =
from d in destProperties
join s in sourceProperties on new { d.Name, d.PropertyType } equals new { s.Name, s.PropertyType }
where d.Name != "MasterSection"
select new { Source = s, Dest = d };
var itemParam = Expression.Parameter(typeof(TSource), "item");
var dictParam = Expression.Parameter(typeof(Dictionary<string, MasterSection>), "dict");
var memberBindings = propertyMap.Select(p => (MemberBinding)Expression.Bind(p.Dest, Expression.Property(itemParam, p.Source))).ToList();
var masterSectionProp = destProperties.FirstOrDefault(s => s.Name == "MasterSection");
if (masterSectionProp != null)
{
Expression<Func<Dictionary<string, MasterSection>, string, MasterSection>> dictRetrievalTemplate = (dict, value) => dict[value];
var masterPropertyBind = Expression.Bind(masterSectionProp, ExpressionReplacer.GetBody(dictRetrievalTemplate, dictParam, Expression.Constant(MasterKeyFromClassName(typeof(TSource).Name)));
memberBindings.Add(masterPropertyBind);
}
var sourceOfDataProp = destProperties.FirstOrDefault(s => s.Name == "SourceOfDataId");
if (sourceOfDataProp != null)
{
memberBindings.Add(Expression.Bind(sourceOfDataProp, Expression.Property(Expression.Property(itemParam, "SourceOfData"), "Id")));
}
var isApprovedProp = destProperties.FirstOrDefault(s => s.Name == "IsApproved");
if (isApprovedProp != null)
{
memberBindings.Add(Expression.Bind(isApprovedProp, Expression.Constant(true)));
}
var newExpression = Expression.New(typeof(TDest));
var memberInitExpression = Expression.MemberInit(newExpression, memberBindings);
var projection = Expression.Lambda<Func<TSource, Dictionary<string, MasterSection>, TDest>>(memberInitExpression, itemParam, dictParam);
return projection;
}
class ExpressionReplacer : ExpressionVisitor
{
readonly IDictionary<Expression, Expression> _replaceMap;
public ExpressionReplacer(IDictionary<Expression, Expression> replaceMap)
{
_replaceMap = replaceMap ?? throw new ArgumentNullException(nameof(replaceMap));
}
public override Expression Visit(Expression exp)
{
if (exp != null && _replaceMap.TryGetValue(exp, out var replacement))
return replacement;
return base.Visit(exp);
}
public static Expression Replace(Expression expr, Expression toReplace, Expression toExpr)
{
return new ExpressionReplacer(new Dictionary<Expression, Expression> { { toReplace, toExpr } }).Visit(expr);
}
public static Expression Replace(Expression expr, IDictionary<Expression, Expression> replaceMap)
{
return new ExpressionReplacer(replaceMap).Visit(expr);
}
public static Expression GetBody(LambdaExpression lambda, params Expression[] toReplace)
{
if (lambda.Parameters.Count != toReplace.Length)
throw new InvalidOperationException();
return new ExpressionReplacer(Enumerable.Range(0, lambda.Parameters.Count)
.ToDictionary(i => (Expression) lambda.Parameters[i], i => toReplace[i])).Visit(lambda.Body);
}
}
}
然后重写你的函数:
private static Expression<MechanicalData TransformMechanicalData(MechanicalData sourceMechanicalData, Dictionary<string, MasterSection> masterSectionMappedLibrary)
{
return new MechanicalData()
{
Acoustic = sourceMechanicalData.Acoustic
.Where(a => a != null)
.Select(a => PropertyMapper<LibraryAcoustic, LibraryAcoustic>.Mapper(a, masterSectionMappedLibrary)).ToList(),
}
}