问题
I have the following object received from Angular client application in ASP.NET Core:
public class ModelFromClient
{
public string name {get;set;} //Database field is Name
public int qunatity {get;set;} //Database field is Quantity
}
And I have a EF Table class:
[Table("MyTable")]
public class MyRow
{
public int Id {get;set;}
public string Name {get;set;}
public int Qunatity {get;set;}
}
Now I need to create expression from ModelFromClient
to Expression<Func<MyRow, MyRow>>
and I need it with generic.
Without generics solution would be:
public Expression<Func<MyRow, MyRow>> ToExpression(ModelFromClient Model)
{
Expression<Func<MyRow, MyRow>> result = (t) => new MyRow()
{
Name = Model.name,
Quantity = Model.qunatity
};
return result;
}
But I would like something like that:
public Expression<Func<T, T>> ToExpression<T>(object Model) where T: new()
{
Expression<Func<T, T>> result = (t) => new T();
foreach(var prop in Model.GetType().GetProperties())
{
//compile error Fields does not exists.
result.Body.Fields.Add(prop.Name.Capitalize(), prop.GetValue(Model, null)); //capitalize returns Name from input name
}
return result;
}
I need expression to pass it to Update extension method of EntityFramework-Plus.
回答1:
Disclaimer: I'm the owner of the project Entity Framework Plus
Here is a fiddle to get you started: https://dotnetfiddle.net/JY0wzw
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
public class Program
{
public class MyRow
{
public int Id { get; set; }
public string Name { get; set; }
public int Qunatity { get; set; }
}
public static void Main()
{
var type = typeof(MyRow);
var constructorInfo = type.GetConstructor(new Type[0]);
var newExpression = Expression.New(constructorInfo);
var memberInits = new List<MemberAssignment>();
foreach (var prop in type.GetProperties())
{
if (prop.Name == "Id")
{
memberInits.Add(Expression.Bind(prop, Expression.Constant(1)));
}
else if (prop.Name == "Name")
{
memberInits.Add(Expression.Bind(prop, Expression.Constant("Z_Name")));
}
else if (prop.Name == "Qunatity")
{
memberInits.Add(Expression.Bind(prop, Expression.Constant(2)));
}
}
var expression = Expression.MemberInit(newExpression, memberInits);
// FOR testing purpose
var compiledExpression = Expression.Lambda<Func<MyRow>>(expression).Compile();
var myRow = compiledExpression();
Console.WriteLine(myRow.Id);
Console.WriteLine(myRow.Name);
Console.WriteLine(myRow.Qunatity);
}
}
Disclaimer: I'm the owner of the project Eval-Expression.NET
This library is not free but allows you to create code dynamically at runtime. Once you get familiar, you can do pretty much anything you want way more easily than with the previous solution.
// Register your type
EvalManager.DefaultContext.RegisterType(typeof(MyRow));
// Register extension methods once from Z.EntityFramework.Plus
EvalManager.DefaultContext.RegisterExtensionMethod(typeof(BatchUpdate));
Eval.Execute("query.Update(x => new MyRow() { Id = 1, Name = 'Z_Name', Qunatity = 2});", new {query});
回答2:
As @Jonathan Magnan said (thank you Jonathan), his answer point me to right direction:
public static Expression<Func<T, T>> ToExpressionGeneric<T>(this object Model) where T : new()
{
var type = typeof(T);
var constructorinfo = type.GetConstructor(new Type[0]);
var newExpression = Expression.New(constructorinfo);
var memberInits = new List<MemberAssignment>();
var modelProperties = Model.GetType().GetProperties();
foreach (var prop in type.GetProperties())
{
var modelProperty = modelProperties.Where(t => t.Name == prop.Name.FirstLetterToLowerCase()).SingleOrDefault();
if (modelProperty != null)
memberInits.Add(Expression.Bind(prop, Expression.Constant(modelProperty.GetValue(Model, null))));
}
var expression = Expression.MemberInit(newExpression, memberInits);
var p = Expression.Parameter(typeof(T), "p");
return Expression.Lambda<Func<T, T>>(expression, p);
}
public static string FirstLetterToLowerCase(this string s)
{
if (string.IsNullOrEmpty(s))
throw new ArgumentException("There is no first letter");
char[] a = s.ToCharArray();
a[0] = char.ToLower(a[0]);
return new string(a);
}
Just in case if someone will search for same solution.
来源:https://stackoverflow.com/questions/47468652/build-expression-from-object