投影图给出类型参数错误

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(),
    }
}