jeudi 16 juin 2016

Converting DbNull to null in Linq-Expression

I'm replacing Reflection for setting property-values with LINQ using the SetProperty method below.
It works fine. However, when newValue comes from a SQL-query, it unfortunately can be System.DbNull.Value...

Is there any way to Check for DbNull in the LINQ-expression and set the value to NULL (type = object) if the value is DbNull, so I don't have to check for DbNull when calling the compiled expression ?

Note: I'm trying to replace reflection, so please don't advise me to use Reflection's SetValue instead.

Also, perhaps supplemential, is there any way to call a custom conversion function within the LINQ-expression ?

e.g. when newValue is of type string, but the target field is of type Guid or vice-versa? So I call MyChangeType instead of Expression.Convert ?

public static object MyChangeType(object objVal, System.Type t)
{
    if (objVal == null || object.ReferenceEquals(objVal, System.DBNull.Value))
    {
        return null;
    }

    //getbasetype
    System.Type tThisType = objVal.GetType();

    bool bNullable = IsNullable(t);
    if (bNullable)
    {
        t = System.Nullable.GetUnderlyingType(t);
    }

    if (object.ReferenceEquals(t, typeof(string)) && object.ReferenceEquals(tThisType, typeof(System.Guid)))
    {
        return objVal.ToString();
    }

    return System.Convert.ChangeType(objVal, t);
} // End Function MyChangeType

This is the code I have

// http://ift.tt/23dct2I
public static void SetProperty<T>(T target, string fieldName, object newValue)
{
    // Class in which to set value
    System.Linq.Expressions.ParameterExpression targetExp = System.Linq.Expressions.Expression.Parameter(typeof(T), "target");

    // Object's type:
    System.Linq.Expressions.ParameterExpression valueExp = System.Linq.Expressions.Expression.Parameter(typeof(object), "value");


    // Expression.Property can be used here as well
    System.Linq.Expressions.MemberExpression memberExp =
        // System.Linq.Expressions.Expression.Field(targetExp, fieldName);
        // System.Linq.Expressions.Expression.Property(targetExp, fieldName);
        System.Linq.Expressions.Expression.PropertyOrField(targetExp, fieldName);


    // BreakPoint: This is the Problem 
    { 
        System.Type type = memberExp.Type;
        if (type.IsGenericType && object.ReferenceEquals(type.GetGenericTypeDefinition(), typeof(System.Nullable<>)))
        {
            System.Type undType = System.Nullable.GetUnderlyingType(type);
            System.Console.WriteLine(undType);
        }

    } 
    System.Linq.Expressions.UnaryExpression conversionExp = System.Linq.Expressions.Expression.Convert(valueExp, memberExp.Type);
    // End Of problem This is the Problem 

    System.Linq.Expressions.BinaryExpression assignExp =
        //System.Linq.Expressions.Expression.Assign(memberExp, valueExp); // Without conversion 
        System.Linq.Expressions.Expression.Assign(memberExp, conversionExp);

    //System.Action<TTarget, TValue> setter = System.Linq.Expressions.Expression
    System.Action<T, object> setter = System.Linq.Expressions.Expression
        .Lambda<System.Action<T, object>>(assignExp, targetExp, valueExp).Compile();


    setter(target, newValue);
}

public class Person
{
    public string Name { get; set; }
    public Person Brother { get; set; }
    public string Email { get; set; }

    public string SnailMail;
    public int Anumber;

    public int? NullableNumber;
}

The problem illustrated

public static void LinqTest()
{
     Person someOne = new Person() { Name = "foo", Email = "foo@bar.com", SnailMail="Snail" };

    object obj = System.DBNull.Value;
    SetProperty(someOne, "NullableNumber", obj);
}





Aucun commentaire:

Enregistrer un commentaire