Вы писали:
Я хотел собрать 10 последних транзакций и 10 последних клиентов в одном запросе LINQ
Немного неясно, что вы хотите.Я сомневаюсь, что вы хотите одну последовательность с сочетанием клиентов и транзакций.Я полагаю, что вы хотите, чтобы 10 новейших Клиентов, каждый из которых имел свои последние 10 Транзакций?
Интересно, почему бы вы отклонились от соглашения о коде сущности первых соглашений .Если ваш класс Customer представляет строку в вашей базе данных, то, конечно, он не имеет HashSet<Transaction>
?
Один-ко-многим из Customer
с его Transactions
должен быть смоделирован следующим образом:
class Customer
{
public int Id {get; set;}
... // other properties
// every Customer has zero or more Transactions (one-to-many)
public virtual ICollection<Transaction> Transactions {get; set;}
}
class Transaction
{
public int Id {get; set;}
... // other properties
// every Transaction belongs to exactly one Customer, using foreign key
public int CustomerId {get; set;}
public virtual Customer Customer {get; set;}
}
public MyDbContext : DbContext
{
public DbSet<Customer> Customers {get; set;}
public DbSet<Transaction> Transactions {get; set;}
}
Это все, что должна знать инфраструктура сущностей для определения таблиц, которые вы хотите создать, для обнаружения отношений «один ко многим» и для обнаружения первичных ключей и внешних ключей.Только если вам нужны разные имена таблиц или столбцов, вам понадобятся атрибуты и / или свободный API
Основные различия между моими и вашими классами заключаются в том, что отношение один-ко-многим представлено виртуальные свойства.HashSet - это ICollection.В конце концов, ваша таблица Transactions
представляет собой набор строк, а не HashSet
В структуре сущностей столбцы ваших таблиц представлены не виртуальными свойствами;виртуальные свойства представляют отношения между таблицами (один ко многим, многие ко многим, ...)
Довольно много людей склонны (группировать) к объединению таблиц, когдаони используют структуру объекта.Тем не менее, жизнь намного проще, если вы используете виртуальные свойства
Вернуться к вашему вопросу
Я хочу (некоторые свойства) 10 новых клиентов, каждыйс (несколькими свойствами) их 10 последних транзакций
var query = dbContext.Customers // from the collection of Customer
.OrderByDescending(customer => customer.Created) // order this by descending Creation date
.Select(customer => new // from every Customer select the
{ // following properties
// select only the properties you actually plan to use
Id = Customer.Id,
Created = Customer.Created,
Name = Customer.Name,
...
LatestTransactions = customer.Transactions // Order the customer's collection
.OrderBy(transaction => transaction.Created) // of Transactions
.Select(transaction => new // and select the properties
{
// again: select only the properties you plan to use
Id = transaction.Id,
Created = transaction.Created,
...
// not needed you know it equals Customer.Id
// CustomerId = transaction.CustomerId,
})
.Take(10) // take only the first 10 Transactions
.ToList(),
})
.Take(10); // take only the first 10 Customers
Платформа сущностей знает отношение один-ко-многим и признает, что для этого необходимо групповое соединение.
Одна из медленных частей вашего запроса - передача выбранных данных из СУБД в локальный процесс.Следовательно, разумно ограничить выбранные данные теми данными, которые вы фактически планируете использовать.Если у Клиента с Id 4 есть 1000 Транзакций, было бы бесполезно передавать внешний ключ для каждой Транзакции, поскольку вы знаете, что он имеет значение 4.
Если вы действительно хотите выполнить соединение самостоятельно:
var query = dbContext.Customers // GroupJoin customers and Transactions
.GroupJoin(dbContext.Transactions,
customer => customer.Id, // from each Customer take the primary key
transaction => transaction.CustomerId, // from each Transaction take the foreign key
(customer, transactions) => new // take the customer with his matching transactions
{ // to make a new:
Id = customer.Id,
Created = customer.Created,
...
LatestTransactions = transactions
.OrderBy(transaction => transaction.Created)
.Select(transaction => new
{
Id = transaction.Id,
Created = transaction.Created,
...
})
.Take(10)
.ToList(),
})
.Take(10);