tutorial query español ejemplos c# linq

c# - query - LINQ: selección dinámica



linq c# tutorial español (6)

Considera que tenemos esta clase:

public class Data { public string Field1 { get; set; } public string Field2 { get; set; } public string Field3 { get; set; } public string Field4 { get; set; } public string Field5 { get; set; } }

¿Cómo selecciono dinámicamente para especificar columnas? algo como esto :

var list = new List<Data>(); var result= list.Select("Field1,Field2"); // How ?

¿Es esta la única solución => Dynamic LINQ ?
Los campos seleccionados no son conocidos en tiempo de compilación. Serían especificados en tiempo de ejecución


Además de Nicholas Butler y la sugerencia en el comentario de Matt (que usan T para el tipo de clase de entrada), puse una mejora a la respuesta de Nicholas que genera la propiedad de entidad dinámicamente y los dúos de función no necesitan enviar el field como parámetro.

Para el uso agrega la clase como golpe:

public static class Helpers { public static Func<T, T> DynamicSelectGenerator<T>(string Fields = "") { string[] EntityFields; if (Fields == "") // get Properties of the T EntityFields = typeof(T).GetProperties().Select(propertyInfo => propertyInfo.Name).ToArray(); else EntityFields = Fields.Split('',''); // input parameter "o" var xParameter = Expression.Parameter(typeof(T), "o"); // new statement "new Data()" var xNew = Expression.New(typeof(T)); // create initializers var bindings = EntityFields.Select(o => o.Trim()) .Select(o => { // property "Field1" var mi = typeof(T).GetProperty(o); // original value "o.Field1" var xOriginal = Expression.Property(xParameter, mi); // set value "Field1 = o.Field1" return Expression.Bind(mi, xOriginal); } ); // initialization "new Data { Field1 = o.Field1, Field2 = o.Field2 }" var xInit = Expression.MemberInit(xNew, bindings); // expression "o => new Data { Field1 = o.Field1, Field2 = o.Field2 }" var lambda = Expression.Lambda<Func<T, T>>(xInit, xParameter); // compile to Func<Data, Data> return lambda.Compile(); } }

El método DynamicSelectGenerator obtiene entidad con tipo T , este método tiene parámetros de entrada opcionales Fields que si desea seleccionar campo especial de la entidad send como una cadena como "Field1, Field2" y si no envía nada a methid, devuelve todos los campos de entidad, puede usar este método de la siguiente manera:

using (AppDbContext db = new AppDbContext()) { //select "Field1, Field2" from entity var result = db.SampleEntity.Select(Helpers.DynamicSelectGenerator<SampleEntity>("Field1, Field2")).ToList(); //select all field from entity var result1 = db.SampleEntity.Select(Helpers.DynamicSelectGenerator<SampleEntity>()).ToList(); }

(Suponga que tiene un DbContext con el nombre AppDbContext y el contexto tiene una entidad con el nombre SampleEntity )


Debe usar el reflejo para obtener y establecer el valor de la propiedad con su nombre.

var result = new List<Data>(); var data = new Data(); var type = data.GetType(); var fieldName = "Something"; for (var i = 0; i < list.Count; i++) { foreach (var property in data.GetType().GetProperties()) { if (property.Name == fieldName) { type.GetProperties().FirstOrDefault(n => n.Name == property.Name).SetValue(data, GetPropValue(list[i], property.Name), null); result.Add(data); } } }

Y aquí está el método GetPropValue ()

public static object GetPropValue(object src, string propName) { return src.GetType().GetProperty(propName).GetValue(src, null); }


Otro enfoque que he usado es un operador ternario anidado:

string col = "Column3"; var query = table.Select(i => col == "Column1" ? i.Column1 : col == "Column2" ? i.Column2 : col == "Column3" ? i.Column3 : col == "Column4" ? i.Column4 : null);

El operador ternario requiere que cada campo sea del mismo tipo, por lo que deberá llamar a .ToString () en cualquier columna que no sea de cadena.


Puedes hacer esto creando dinámicamente el lambda al que pasas a Select:

Func<Data,Data> CreateNewStatement( string fields ) { // input parameter "o" var xParameter = Expression.Parameter( typeof( Data ), "o" ); // new statement "new Data()" var xNew = Expression.New( typeof( Data ) ); // create initializers var bindings = fields.Split( '','' ).Select( o => o.Trim() ) .Select( o => { // property "Field1" var mi = typeof( Data ).GetProperty( o ); // original value "o.Field1" var xOriginal = Expression.Property( xParameter, mi ); // set value "Field1 = o.Field1" return Expression.Bind( mi, xOriginal ); } ); // initialization "new Data { Field1 = o.Field1, Field2 = o.Field2 }" var xInit = Expression.MemberInit( xNew, bindings ); // expression "o => new Data { Field1 = o.Field1, Field2 = o.Field2 }" var lambda = Expression.Lambda<Func<Data,Data>>( xInit, xParameter ); // compile to Func<Data, Data> return lambda.Compile(); }

Entonces puedes usarlo así:

var result = list.Select( CreateNewStatement( "Field1, Field2" ) );


Usando Reflection and Expression bulid puede hacer lo que usted dice. Ejemplo:

var list = new List<Data>(); //bulid a expression tree to create a paramter ParameterExpression param = Expression.Parameter(typeof(Data), "d"); //bulid expression tree:data.Field1 Expression selector = Expression.Property(param,typeof(Data).GetProperty("Field1")); Expression pred = Expression.Lambda(selector, param); //bulid expression tree:Select(d=>d.Field1) Expression expr = Expression.Call(typeof(Queryable), "Select", new Type[] { typeof(Data), typeof(string) }, Expression.Constant(list.AsQueryable()), pred); //create dynamic query IQueryable<string> query = list.AsQueryable().Provider.CreateQuery<string>(expr); var result=query.ToList();


var result = from g in list.AsEnumerable() select new {F1 = g.Field1,F2 = g.Field2};