2017-02-15 9 views
1

Я бы хотел использовать Entity Framework для возврата данных из 2 таблиц и выбора столбцов из двух таблиц, сначала мне не повезло с чем-то простым, например возвращая int и строки (то есть select new { id = t1.ID, other = t2.OtherData }, поскольку литье анонимного типа было громоздким в пункте назначения (назначение было моей winform), поэтому я ударил по идее, чтобы просто вернуть обе строки таблицы ...Entity Framework, возвращающий IQueryable для объединения двух таблиц

Так что-то вроде этого:

public static IQueryable<{Table1,Table2}> byRecID(Guid recID, MyContext DBContext) 
    { 
     return (from i1 in DBContext.Table1 
      join j1 in DBContext.Table2 on i1.GroupID equals j1.GroupID 
      where i1.RecID.Equals(RecID) 
      select new { i1, j1 }).SingleOrDefault(); 
    } 

Это все хорошо, за исключением типа возвращаемого значения метода является неправильным. Я попробовал несколько комбинаций. Unfort в то время как я вызываю «byRecID» из winform, «SingleOrDefault» недоступен, но доступен внутри внутри метода byRecID, поэтому я не могу просто вернуть IQueryable, должен быть напечатан IQueryable<SOMETHING IN HERE> (потому что SingleOrDefault не является расширением IQueryable, только IQueryable<T>).

Мой вопрос ... есть ли синтаксис для 'SOMETHING IN HERE', который позволяет мне указать его объединение двух строк таблицы?

и мне интересно ... Почему SingleOrDefault является опцией INSIDE, но не является вариантом результата метода при вызове из моей winform?

В основном я надеялся на то, что позволяет чистые вызовы данных из моих winforms, не отбрасывая отвратительные анонимные типы, а затем используя отражение (например, когда я возвращал анонимный тип примитивов), но также не хочу, чтобы порождать Type just для использования моим методом byRecID.

+1

Вы не можете возвращать анонимные типы из методов. Вам нужен конкретный тип –

+0

, вы можете просто их использовать, что является моей точкой. Я хочу тип, который описывает себя как объединение двух других типов. – Nnoel

+1

Кроме того, вы выполняете запрос, поэтому результат не является IQueryable чего-то, это что-то –

ответ

2

В C# анонимные типы лучше всего использовать в рамках одного и того же метода, где вы их проекту. Как вы видели для себя t hey нельзя использовать вне метода определения. Поэтому вы не можете возвращать анонимные типы из методов (и сохранять их структуру, вы можете вернуть их как объекты, но это не очень хорошая идея), это делает ваш синтаксис недействительным.

Лучшим вариантом является проецирование результата в класс, указанный для ваших нужд.

public class TableJoinResult 
{ 
    public Table1 Table1 { get; set; } 
    public Table2 Table2 { get; set;} 
} 

Ваш запрос:

public static IQueryable<TableJoinResult> byRecID(Guid recID, MyContext DBContext) 
    { 
     return (from i1 in DBContext.Table1 
      join j1 in DBContext.Table2 on i1.GroupID equals j1.GroupID 
      where i1.RecID.Equals(RecID) 
      select new TableJoinResult { Table1= i1, Table2 = j1 }).SingleOrDefault(); 
    } 

Более подробная информация о анонимных типах: https://msdn.microsoft.com/en-us/library/bb397696.aspx

+0

Aaarggg, я перехожу из старого стиля sql, где они пишут sql в коде и могут выбирать любые поля, которые им нравятся. Должен переосмыслить мой подход. Я пытаюсь сохранить производительность, сделав iqueryables, который может быть скомпилирован в sql, но создание сотен этих типов «TableJoinResult» не кажется чистым или забавным, но несколько выражений linq более чисты, но не настолько эффективны (одно выражение linq давайте лучше компиляция бывает) – Nnoel

+0

да, это не забава, к сожалению, лучший вариант, я думаю. С C# 7, который поставляется с визуальной студией 2017 (7 марта), на языке существует новая концепция (лучше поддерживать на самом деле, поскольку кортежи уже существуют на языке, но они не очень полезны) -> кортежи, которые адресуют эти сценарии –

2

1) Создайте определенный класс, который описывает результат.

2) См 1

0

Я хотел, чтобы избежать создания определенного класса или структуры. Ниже приведен длинный путь, который позволяет избежать создания структуры/класса. Так что я сделал это в своем классе услуги: -

List<KeyValuePair<string,int>> IWorkflowService.GetServiceRetention() 
     { 
      var serviceRetention = from y in _context.SERVICES 
        join z in _context.SERVICE_SETTINGS on y.ID equals z.SERVICEID 
        select new { Service= y.SERVICE, Retention=z.RETENTION };//new KeyValuePair<string,int?>(y.SERVICE, z.RETENTION)); 
      var list = new List<KeyValuePair<string, int>>(); 
      foreach (var obj in serviceRetention) 
      { 
       list.Add(new KeyValuePair<string, int>(obj.Service,Convert.ToInt32(obj.Retention))); 
      } 
      return list; 
     } 

Я должен был сделать это в моем классе контроллера:

List<KeyValuePair<string, int>> c = _service.GetServiceRetention(); 

      foreach (var obj in c) 
      { 
       //The key contains service and value contains Rtention. 
        RecurringJob.AddOrUpdate(DELETE_SERVICE + obj.Key,() => 
        Delete(obj.Key), //this is my function that does the actual process 
       Cron.DayInterval(Convert.ToInt32(obj.Value))); 
      } 

Я не уверен, что это лучший способ сделать это, но работает на меня.