#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
это сущностью в вашей модели или только классом, который вы используете для своей проекции. Если это сущность, вам нужно изменить последний код, потому что вы не можете проецировать в сущность (в основном вам понадобится другой вспомогательный тип для вашей проекции).