简体   繁体   中英

Trying to assign value to nullable Guid property using an expression

Hi all i am using an expression tree to map the values from source to destination by creating an expression using below code

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

and then calling above method like as below

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

I have these properties SourceOfDataId, IsApproved on source and destination entity where i am trying to set IsApproved to true and sourceOfDataId to the corresponding values.

After this project map wrong value has been set to SourceOfDataId instead of inner object property Id

the entity LibraryLabAirflow is looks like this

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

and i have tried below expression binding as well but both did not worked

Attempt 1:

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

Attempt 2:

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

and trying to get these expressions out of above

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

Could any one please let me know where i am doing wrong with the above code, Thanks in advance.

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?))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM