尝试使用表达式为可为 null 的 Guid 属性 赋值

Trying to assign value to nullable Guid property using an expression

大家好我正在使用表达式树通过使用以下代码创建表达式来将值从源映射到目标

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 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 != "SourceOfDataId"
            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 sourceOfDataProp = destProperties.FirstOrDefault(s => s.Name == "SourceOfDataId");
        if (sourceOfDataProp != null)
        {
            // here i am setting one of the inner object(SourceOfData) ID to outer object nullable guid property (SourceOfDataId)
            memberBindings.Add(Expression.Bind(sourceOfDataProp, Expression.Property(Expression.Property(itemParam, "SourceOfData"), "Id")));
        }
       
        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;
    }
} 

然后像下面这样调用上面的方法

 AirflowsLab = sourceMechanicalData
                          .AirflowsLab
                          .Select(a => PropertyMapper<LibraryLabAirflow, LibraryLabAirflow>
                                  .Mapper(a, masterSectionMappedLibrary)).ToList()

我在源实体和目标实体上有这些属性 SourceOfDataId、IsApproved,我试图将 IsApproved 设置为 true 并将 sourceOfDataId 设置为相应的值。

此项目映射错误值设置为 SourceOfDataId 而不是内部对象后 属性 Id

实体 LibraryLabAirflow 看起来像这样

public class LibraryLabAirflow
{
    [ForeignKey("SourceOfData")]
    public Guid? SourceOfDataId { get; set; }
    public virtual CodeStandardGuideline SourceOfData { get; set; }
    public bool? IsApproved { get; set; }
}

我也试过下面的表达式绑定,但都没有用

尝试 1:

 var sourceOfDataPropertyBind = Expression.Bind(sourceOfDataProp, Expression.Property(Expression.Property(itemParam, "SourceOfData"),typeof(Guid?), "Id"));

尝试 2:

var sourceOfDataPropertyBind = Expression.Bind(sourceOfDataProp, Expression.Property(Expression.Property(itemParam, typeof(Guid?), "SourceOfData"), "Id"));

并试图从上面得到这些表达式

  airflowLab => new LibraryLabAirflow
  {              
        IsApproved = true,                 
        SourceOfData = airflowLab.SourceOfData,
        SourceOfDataId = airflowLab.SourceOfData.Id,
   }

任何人都可以让我知道我在上面的代码中做错了什么,在此先感谢。

不太确定为什么需要将 airflowLab.SourceOfData.Id 分配给显式 FK 属性 SourceOfDataId,因为在服务器端 LINQ to Entities 的上下文中,它应该与分配相同直接airflowLab.SourceOfDataId.

但是假设出于某种原因您需要它。由于 airflowLab.SourceOfData.Id 表达式的静态类型是 non nullable Guid (C# 没有隐式 null 传播的概念),C# 编译器为

SourceOfDataId = airflowLab.SourceOfData.Id

会是

SourceOfDataId = (Guid?)airflowLab.SourceOfData.Id

注意强制转换为可为空 Guid。在 Expression 术语中映射到 Expression.Convert,所以你需要的是

Expression.Convert(
    Expression.Property(Expression.Property(itemParam, "SourceOfData"), "Id"),
    typeof(Guid?))