首页 > 解决方案 > 尝试使用表达式为可为空的 Guid 属性赋值

问题描述

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

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

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

标签: c#.net-coreentity-framework-corelinq-to-entitiesexpression-trees

解决方案


Not quite sure why you need to assign airflowLab.SourceOfData.Id to the explicit FK property SourceOfDataId, since in the context of server side LINQ to Entities it should be the same as assigning directly airflowLab.SourceOfDataId.

But let say for some reason you need that. Since the static type of the airflowLab.SourceOfData.Id expression is non nullable Guid (C# has no notion of implicit null propagation), the actual expression emitted by the C# compiler for

SourceOfDataId = airflowLab.SourceOfData.Id

would be

SourceOfDataId = (Guid?)airflowLab.SourceOfData.Id

Note the cast to nullable Guid. In Expression terms that maps to Expression.Convert, so what you need is something like

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

推荐阅读