2015-09-11 3 views
0

Это немного многогранный вопрос, поэтому позвольте мне просто погрузиться в код с некоторым объяснением внизу.Как преобразовать анонимный тип в Dynamic LINQ в сильный тип

Пример Пример данных:

List<Encounter> input 
Id, Facility, HospitalService, Field3, Field4, Field5, ... 
1, 1,  A,    ..., ..., ... 
2, 2,  A,    ..., ..., ... 
3, 1,  B,    ..., ..., ... 
4, 2,  B,    ..., ..., ... 
5, 1,  A,    ..., ..., ... 
5, 2,  A,    ..., ..., ... 

То, что я хочу сделать, это запрос мой объект данных и, например, возвращать отдельные поля, например.

distinct Facility is 1, 2 
distinct HospitalService is A, B 
distinct pair is 1A, 2A, 1B, 2B 

Однако один глюк, я хочу вернуться сильно типизированных объект, и в этом случае тот же объект в качестве входных данных, в этом случае объект Encounter, со всеми другими полями с пустыми или значения по умолчанию, например

List<Encounter> output, with only fields of interest populated 
Id, Facility, HospitalService, Field3, Field4, Field5, ... 
0, 1,  A,    "",  "",  "" 
0, 2,  A,    "",  "",  "" 
0, 1,  B,    "",  "",  "" 
0, 2,  B,    "",  "",  "" 

Со стандартным LINQ я могу это сделать, и он работает.

List<Encounter> sampleData = CreateSampleData(); 
    List<Encounter> rawResultFromStandardLinq = 
     sampleData 
      .GroupBy(e => new {e.Facility, e.HospitalService}) 
      .Select(e => new Encounter() { Facility = e.Key.Facility, HospitalService = e.Key.HospitalService}) 
      .ToList(); 

Вопрос № 1: В приведенном выше примере, это не является динамическим. Я должен был знать, какой объект создать с новым ключевым словом. Кроме того, я должен был знать, какие поля выбрать/проектировать. Как я могу сделать это динамически? Как я могу проецировать анонимный тип на сильный тип?

например. Я думал, что смогу сделать что-то подобное, чтобы использовать сериализацию json. Это работает, но я предполагаю, что это будет очень медленно.

var rawResultAsAnonymousType = 
     sampleData 
      .GroupBy(e => new { e.Facility, e.HospitalService }) 
      .Select(e => new { e.Key.Facility, e.Key.HospitalService }) 
      .ToList(); 

    string json = JsonConvert.SerializeObject(rawResultAsAnonymousType); 
    var encountersFromJson = JsonConvert.DeserializeObject<List<Encounter>>(json); 

Вопрос № 2: Следующая проблема у нас в том, что мы хотим, чтобы запрос быть динамичным. т. Е. Мы хотим открыть интерфейс, который позволит клиенту запрашивать данные, чтобы получить то, что они хотят. Для этой цели мы обратились к Dynamic LINQ.

Может кто-нибудь помочь мне заставить это работать?

[Update: I can now do this for multiple columns] 
      var rawResultFromDynamicLinq4 = 
       DynamicQueryable 
        .GroupBy(_sampleData.AsQueryable(), @"new (Facility, HospitalService)", "it") 
        .Select("new (it.Key.Facility, it.Key.HospitalService)") 
        ; 

[Before, I was trying to do this] 
     var rawResultFromDynamicLinq = 
      sampleData 
       .GroupByMany("Facility", "HospitalService") 
       //.Select(.... how do I get my object back?) 
      ; 

Некоторые пояснения:

Почему мы делаем это как это? Это в значительной степени не имеет отношения к техническому вопросу, но если вы знаете, я работаю в сфере здравоохранения, и мы используем стандарты FHIR для запроса данных, поэтому мы должны использовать определенные модели FHIR. Это означает, что мы не можем просто вернуть список, содержащий различные значения определенного поля (например, для того, чтобы клиент мог создавать значения выпадающего списка для фильтрации данных).

ответ

3

Как я могу проецировать анонимный тип на сильный тип?

Ну, анонимный тип является сильным типа - вы просто не знаете имени типа во время компиляции (отсюда «анонимного»). Так что, вы можете проецировать на разные типы и использовать такие инструменты, как AutoMapper, для сопоставления анонимного типа с другим типом, но вы еще должны знать поля во время компиляции.

Вы могли быть в состоянии сделать что-то вроде:

sampleData 
     .GroupBy(e => new {e.Facility, e.HospitalService}) 
     .Select(g => g.First()) 
     .ToList(); 

, но это не ясно, если это именно то, что вы ищете (и вы все еще должны знать «группировка» поля на compile- время).

Как это сделать динамически?

Что вы подразумеваете под "динамическим"? Вы имеете в виду что-то, что автоматически устанавливает свойства на основе типа назначения?

Может кто-нибудь помочь мне заставить это работать?

Опять же, если вы просто хотите, первый элемент, который соответствует каждой группе условие, которое вы можете сделать

var rawResultFromDynamicLinq = 
    sampleData 
     .GroupByMany("Facility", "HospitalService") 
     .Select(g -> g.First()) 
    ; 
0

Ответ на # 2: Там действительно нет такой вещи, как динамический LINQ; однако для этого есть некоторые сторонние библиотеки. Также встроен в .Net есть 2 варианта. В-1 есть возможность выполнять динамический SQL (это плохая идея). Второй вариант - деревья выражений. Это может работать для вопроса 1, но тип не может быть динамическим.

 // Add a using directive for System.Linq.Expressions. 

     string[] companies = { "Consolidated Messenger", "Alpine Ski House", "Southridge Video", "City Power & Light", 
          "Coho Winery", "Wide World Importers", "Graphic Design Institute", "Adventure Works", 
          "Humongous Insurance", "Woodgrove Bank", "Margie's Travel", "Northwind Traders", 
          "Blue Yonder Airlines", "Trey Research", "The Phone Company", 
          "Wingtip Toys", "Lucerne Publishing", "Fourth Coffee" }; 

     // The IQueryable data to query. 
     IQueryable<String> queryableData = companies.AsQueryable<string>(); 

     // Compose the expression tree that represents the parameter to the predicate. 
     ParameterExpression pe = Expression.Parameter(typeof(string), "company"); 

     // ***** Where(company => (company.ToLower() == "coho winery" || company.Length > 16)) ***** 
     // Create an expression tree that represents the expression 'company.ToLower() == "coho winery"'. 
     Expression left = Expression.Call(pe, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes)); 
     Expression right = Expression.Constant("coho winery"); 
     Expression e1 = Expression.Equal(left, right); 

     // Create an expression tree that represents the expression 'company.Length > 16'. 
     left = Expression.Property(pe, typeof(string).GetProperty("Length")); 
     right = Expression.Constant(16, typeof(int)); 
     Expression e2 = Expression.GreaterThan(left, right); 

     // Combine the expression trees to create an expression tree that represents the 
     // expression '(company.ToLower() == "coho winery" || company.Length > 16)'. 
     Expression predicateBody = Expression.OrElse(e1, e2); 

     // Create an expression tree that represents the expression 
     // 'queryableData.Where(company => (company.ToLower() == "coho winery" || company.Length > 16))' 
     MethodCallExpression whereCallExpression = Expression.Call(
      typeof(Queryable), 
      "Where", 
      new Type[] { queryableData.ElementType }, 
      queryableData.Expression, 
      Expression.Lambda<Func<string, bool>>(predicateBody, new ParameterExpression[] { pe })); 
     // ***** End Where ***** 

     // ***** OrderBy(company => company) ***** 
     // Create an expression tree that represents the expression 
     // 'whereCallExpression.OrderBy(company => company)' 
     MethodCallExpression orderByCallExpression = Expression.Call(
      typeof(Queryable), 
      "OrderBy", 
      new Type[] { queryableData.ElementType, queryableData.ElementType }, 
      whereCallExpression, 
      Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe })); 
     // ***** End OrderBy ***** 

     // Create an executable query from the expression tree. 
     IQueryable<string> results = queryableData.Provider.CreateQuery<string>(orderByCallExpression); 

     // Enumerate the results. 
     foreach (string company in results) 
      Console.WriteLine(company); 

     /* This code produces the following output: 

      Blue Yonder Airlines 
      City Power & Light 
      Coho Winery 
      Consolidated Messenger 
      Graphic Design Institute 
      Humongous Insurance 
      Lucerne Publishing 
      Northwind Traders 
      The Phone Company 
      Wide World Importers 
     */ 

https://msdn.microsoft.com/en-us/library/bb882637.aspx

+0

Я использую это: https: // www. nuget.org/packages/System.Linq.Dynamic.Library/ – Raymond

+0

И у Скотта Гу есть блог: http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic- запрос-библиотека – Raymond

0

Это возможно, с некоторыми изменениями в System.Linq.Dynamic.Library

См изменен код здесь: https://gist.github.com/de1e6c5e758e15cc9154.git и здесь https://gist.github.com/d166f17cd672b696b916.git

Теперь вы можете использовать это как:

var sampleData = new List<Encounter> 
{ 
    new Encounter {Id = "1", Language = "1", VersionId = "A"}, 
    new Encounter {Id = "2", Language = "2", VersionId = "A"}, 
    new Encounter {Id = "3", Language = "1", VersionId = "B"}, 
    new Encounter {Id = "4", Language = "2", VersionId = "B"}, 
    new Encounter {Id = "5", Language = "1", VersionId = "A"}, 
    new Encounter {Id = "6", Language = "2", VersionId = "A"} 
}; 

List<Encounter> fromStandardLinq = sampleData 
     .GroupBy(e => new { e.Language, e.VersionId }) 
     .Select(e => new Encounter { Id = "0", Language = e.Key.Language, VersionId = e.Key.VersionId }) 
     .ToList(); 

Console.WriteLine("fromStandardLinq:"); 
foreach (var en in fromStandardLinq) 
{ 
    Console.WriteLine("{0} {1} {2}", en.Id, en.Language, en.VersionId); 
} 

var fromDynamicLinq1a = sampleData.AsQueryable() 
     .GroupBy(@"new (Language, VersionId)", "it") 
     .Select<Encounter>("new (\"0\" as Id, it.Key.Language, it.Key.VersionId)") 
     ; 

Console.WriteLine("fromDynamicLinq1a:"); 
foreach (Encounter en in fromDynamicLinq1a) 
{ 
    Console.WriteLine("{0} {1} {2}", en.Id, en.Language, en.VersionId); 
} 

var fromDynamicLinq1b = sampleData.AsQueryable() 
     .GroupBy(@"new (Language, VersionId)", "it") 
     .Select(new { Id = "9", Language = "9", VersionId = "9" }, "new (\"0\" as Id, it.Key.Language, it.Key.VersionId)") 
     .Select(x => x) 
     ; 

Console.WriteLine("fromDynamicLinq1b:"); 
foreach (dynamic en in fromDynamicLinq1b) 
{ 
    Console.WriteLine("{0} {1} {2}", en.Id, en.Language, en.VersionId); 
} 

Console.WriteLine("fromDynamicLinq2a:"); 
var rawResultFromDynamicLinq2a = sampleData.AsQueryable() 
     .GroupBy(@"new (Language, VersionId)", "it") 
     .Select(typeof(Encounter), "new (\"0\" as Id,it.Key.Language, it.Key.VersionId)") 
     ; 

foreach (Encounter en in rawResultFromDynamicLinq2a) 
{ 
    Console.WriteLine("{0} {1} {2}", en.Id, en.Language, en.VersionId); 
} 

Console.WriteLine("fromDynamicLinq2b:"); 
var rawResultFromDynamicLinq2b = sampleData.AsQueryable() 
     .GroupBy(@"new (Language, VersionId)", "it") 
     .Select(typeof(Encounter), new { Id = "9", Language = "9", VersionId = "9" }, "new (\"0\" as Id,it.Key.Language, it.Key.VersionId)") 
     ; 

foreach (Encounter en in rawResultFromDynamicLinq2b) 
{ 
    Console.WriteLine("{0} {1} {2}", en.Id, en.Language, en.VersionId); 
} 
Смежные вопросы