Ho il seguente oggetto ricevuto dall'applicazione client angolare 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
}
E ho una classe EF Table:
[Table("MyTable")]
public class MyRow
{
public int Id {get;set;}
public string Name {get;set;}
public int Qunatity {get;set;}
}
Ora ho bisogno di creare espressioni da ModelFromClient
a Expression<Func<MyRow, MyRow>>
e ne ho bisogno con generico. Senza la soluzione generica sarebbe:
public Expression<Func<MyRow, MyRow>> ToExpression(ModelFromClient Model)
{
Expression<Func<MyRow, MyRow>> result = (t) => new MyRow()
{
Name = Model.name,
Quantity = Model.qunatity
};
return result;
}
Ma vorrei qualcosa del genere:
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;
}
Ho bisogno di espressioni per passarlo al metodo di estensione di aggiornamento di EntityFramework-Plus.
Disclaimer : sono il proprietario del progetto Entity Framework Plus
Ecco un violino per iniziare: 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 : sono il proprietario del progetto Eval-Expression.NET
Questa libreria non è gratuita ma consente di creare codice in modo dinamico in fase di runtime. Una volta acquisito familiarità, puoi fare praticamente tutto quello che vuoi in modo più semplice rispetto alla soluzione precedente.
// 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});
Come @Jonathan Magnan ha detto (grazie Jonathan), la sua risposta mi indica la giusta direzione:
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);
}
Nel caso in cui qualcuno cercherà la stessa soluzione.