2016-05-10 3 views
0

Я пытаюсь выяснить для IQueryable, как я могу построить файл csv путем динамического выбора объектов в виде строк.Построение динамического linq Func для возврата строки

, например:

Я прочитал это о динамически подбирая свойства Т ...

LINQ : Dynamic select

Это позволит мне сделать что-то вроде этого ...

var data = new List<T> { items }; 
      var fields = new string[] { "Field1", "Field2", "Field3" }; 
      // build row strings 
      var rows = set.Select(BuildRowObjectExpression<T, ProjectionOfT>(fields)) 
       .Select(i => Serialise<ProjectionOfT>(i)); 


     string Serialise<T>(T i, string separator) 
     { 
      var properties = typeof(T).GetProperties(); 
      var values = new List<string>(); 
      foreach (var p in properties) 
       values.Add(p.GetValue(i).ToString()); 

      return string.Join(separator, values); 
     } 

     Func<T, Tout> BuildRowObjectExpression<T, Tout>(string[] fields) 
     { 
      // input parameter "o" 
      var xParameter = Expression.Parameter(typeof(T), "o"); 

      // new statement "new Data()" 
      var xNew = Expression.New(typeof(T)); 

      // create initializers 
      var bindings = fields.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 T { Field1 = o.Field1, Field2 = o.Field2 }" 
      var xInit = Expression.MemberInit(xNew, bindings); 

      // expression "o => new T { Field1 = o.Field1, Field2 = o.Field2 }" 
      var lambda = Expression.Lambda<Func<T, string>>(xInit, xParameter); 

      // compile to Func<T, string> 
      return lambda.Compile(); 
     } 

Что мне было интересно:

Как построить это как выражение/FUNC, что я могу использовать с IQueryable, чтобы сделать что-то вроде этого

// this would build me a string array from the specified properties 
// in a collection of T joining the values using the given separator 
var results = data.Select(i => BuildString(fields, "|")).ToArray(); 

Я бы в идеале хотел бы использовать это с набором сущностей.

ответ

0

Преобразование строк/конкатенация не задание базы данных. Вам лучше сохранить две части отдельно - поиск данных в запросе базы данных и преобразовании данных в запросе памяти.

Например, вы можете использовать следующие пользовательские расширения методов:

public static class Extensions 
{ 
    public static IQueryable<T> Select<T>(this IQueryable source, string[] fields) 
    { 
     var parameter = Expression.Parameter(source.ElementType, "o"); 
     var body = Expression.MemberInit(
      Expression.New(typeof(T)), 
      fields.Select(field => Expression.Bind(
       typeof(T).GetProperty(field), 
       Expression.PropertyOrField(parameter, field)) 
      ) 
     ); 
     var selector = Expression.Lambda(body, parameter); 
     var expression = Expression.Call(
      typeof(Queryable), "Select", new[] { parameter.Type, body.Type }, 
      source.Expression, Expression.Quote(selector) 
     ); 
     return source.Provider.CreateQuery<T>(expression); 
    } 

    public static IEnumerable<string> Serialize<T>(this IEnumerable<T> source, string separator) 
    { 
     var properties = typeof(T).GetProperties(); 
     return source.Select(item => string.Join(separator, properties.Select(property => property.GetValue(item)))); 
    } 
} 

как этот

var results = db.Data.Select<ProjectionOfT>(fields).Serialize("|"); 

Если вы хотите, чтобы избежать ProjectionOfT класс, не существует простой способ сделать это, так как для этого требуется динамическое создание класса времени выполнения, поэтому вам лучше прибегнуть к пакету System.Linq.Dynamic.

+0

Gah, это не решает мою актуальную проблему, но я не думаю, что это был хорошо сформулированный вопрос, который сказал, что он решает проблему, представленную в вопросе. Спасибо :) – War

Смежные вопросы