Как объявить результат запроса в LINQ для сущностей

#linq #entity-framework-4

#linq #entity-framework-4

Вопрос:

Я только начал использовать MS entity framework и столкнулся со следующей проблемой с LINQ. Я упростю свою проблему, чтобы сделать ее более понятной; допустим, у меня есть три таблицы в базе данных SQL Server:

  • customerData (PK — это CustomerID, в таблице также около двадцати столбцов для хранения данных клиента).
  • CustomerData1 (содержит некоторые данные для клиента в соотношении один к одному).
  • CustomerData2 (также содержит некоторые данные для клиента в соотношении один к одному).

Я знаю, что данные с отношением один к одному лучше должны находиться в одной таблице, но это какая-то корпоративная база данных, и изменить исходную таблицу невозможно (поэтому все наши данные должны быть в отдельных таблицах).

Теперь я хочу отобразить список клиентов с их данными из таблицы customerData и добавить несколько столбцов данных из CustomerData1 через join. С другой стороны, я хочу отобразить список клиентов и добавить некоторые данные из другой таблицы CustomerData2 через join.

Таким образом, данные в основном одинаковы оба раза, за исключением того, что в первом случае результат включает некоторые столбцы из CustomerData1, а во втором случае некоторые данные из таблицы CustomerData2.

Итак, я создал класс Customer со свойствами для всех соответствующих столбцов в таблице customerData и добавил свойства для столбцов, которые должны быть включены из CustomerData1, и свойства, которые должны быть включены из CustomerData2. Все столбцы должны включаться каждый раз, за исключением того, что при первом вызове свойства, которые сопоставляются с таблицей CustomerData2, будут пустыми, а во время второго вызова свойства, которые сопоставляются с таблицей CustomerData1, будут пустыми.

Для этого я хотел создать одну функцию, поэтому я попытался создать ее следующим образом: входной параметр в функции определяет, включены ли данные из CustomerData1 или CustomerData2.

 if (firstList)
{
  var query1 = from obj in CustomerData
               join rel in CustomerData1
               on obj.CustomerId equals rel.CustomerId 
               select new { obj, rel };
}

if (secondList)
{
   var query2 = from obj in CustomerData
               join rel in CustomerData2
               on obj.CustomerId equals rel.CustomerId 
               select new { obj, rel };
}
  

Итак, этот код дает мне анонимный тип на основе входного параметра. Теперь я хочу создать объекты Customer и упорядочить их (порядок всегда один и тот же, он не зависит от входного параметра). Итак, я хочу создать список заказанных клиентов и включить дополнительные данные на основе входного параметра.

 var query3 = <previous_query_variable>.Select(f => new Customer {
Id = f.obj.CustomerId,
Name = f.obj.CustomerName,
... other columns from Customer table (a lot of them)
//and then add some additional columns based on the input parameter
Data1 = f.rel.someDataFromCustomer1, //only when firstList == true, otherwise empty
Data2 = f.rel.someDataFromCustomer2  //only when secondList == true, otherwise empty
}).OrderBy(f => f.Name); //order by customer name
  

Конечно, это не компилируется, поскольку оба параметра находятся внутри операторов if. Я знаю, что мог бы скопировать этот последний оператор (var query3 = …) внутри обоих операторов if и включить только соответствующие назначения (Data1 или Data2), но я не хочу назначать свойства, которые сопоставляются с таблицей customerData дважды (один раз в обоих операторах if), и я не хочу заказывать дважды.

Как я могу решить эту проблему? Я использую .NET 4.

Ответ №1:

Вы не можете заранее объявить переменную для анонимного типа, то есть перед вашими двумя операторами if. (Что-то вроде var query = null не поддерживается.) Вам нужно будет создать вспомогательный тип и спроецировать в него, например:

 public class ProjectedCustomerData
{
    public CustomerData CustomerData { get; set; }
    public CustomerData1 CustomerData1 { get; set; }
    public CustomerData2 CustomerData2 { get; set; }
}
  

И затем проекция:

 IQueryable<ProjectedCustomerData> resultQuery = null;
if (firstList)
{
    resultQuery = from obj in CustomerData
                  join rel in CustomerData1
                  on obj.CustomerId equals rel.CustomerId 
                  select new ProjectedCustomerData
                  {
                      CustomerData = obj,
                      CustomerData1 = rel
                  };
}
if (secondList)
{
    resultQuery = from obj in CustomerData
                  join rel in CustomerData2
                  on obj.CustomerId equals rel.CustomerId 
                  select new ProjectedCustomerData
                  {
                      CustomerData = obj,
                      CustomerData2 = rel
                  };
}

var query3 = resultQuery.Select(f => new Customer {
    Id = f.CustomerData.CustomerId,
    Name = f.CustomerData.CustomerName,
    // ...
    Data1 = f.CustomerData1.someDataFromCustomer1,
    Data2 = f.CustomerData2.someDataFromCustomer2
}).OrderBy(f => f.Name);
  

Я не уверен, является ли Customer это сущностью в вашей модели или только классом, который вы используете для своей проекции. Если это сущность, вам нужно изменить последний код, потому что вы не можете проецировать в сущность (в основном вам понадобится другой вспомогательный тип для вашей проекции).