#entity-framework #linq #asp.net-core #linq-to-sql #linq-to-entities
#entity-framework #linq #asp.net-core #linq-to-sql #linq-to-entities
Вопрос:
У меня мало сложностей с заполнением логики для чтения нескольких записей из моей таблицы с помощью linq. Может кто-нибудь предложить хороший вариант для решения моей проблемы. У меня есть такая таблица
ContractID, ContractDate, PreviousReference
1 1/1/2012
2 1/2/2012 1
3 1/8/2015
4 1/3/2015 2
В моей таблице есть некоторая информация о контракте. иногда у какого-то контакта есть предыдущая ссылка на контракт. В случае предыдущей ссылки мне нужно прочитать все предыдущие ссылки на последний контракт. допустим, идентификатор контракта 4, у него есть 2 ссылки, поэтому мне также нужно получить предыдущие 2 записи.
Есть ли в LINQ какая-либо опция для обработки такого цикла
Комментарии:
1. В настоящее время нет решения с чистым EF LINQ. Это называется рекурсивным CTE, поэтому попробуйте написать SQL вручную.
2. SQL будет хорошим вариантом. Спасибо
Ответ №1:
Вы хотите получить ваши предыдущие ссылки рекурсивно? Итак, если Contract[4] имеет предыдущую ссылку 2, а contract [2] имеет предыдущую ссылку 1, то, если вы запрашиваете предыдущие ссылки contract [4], вам нужен только номер 2 или также номер 1 и все предыдущие ссылки на номер 1? (в вашем примере номер 1 не имеет предыдущих ссылок, но если бы они у него были, захотели бы вы их также получить, если бы запросили предыдущие ссылки на контракт 4?
Сможете ли вы справиться с этим рекурсивно , зависит от того , являются ли ваши данные IEnumerable<...>
or IQueryable<...>
. Другими словами: являются ли данные локальными в вашем процессе или вам нужно извлекать их из другого процесса, например, из системы управления базами данных?
Я не уверен, что это может быть сделано СУБД, это зависит от того, знает ли SQL рекурсивность.
В локальном процессе решение не является сложным.
Итак, у вас есть контракт класса, аналогичный следующему:
class Contract
{
public int Id {get; set;}
public Datetime Date {get; set;}
public int PreviousReference {get; set;}
}
Здесь предыдущие ссылки похожи на внешний ключ к другому контракту, который может иметь внешний ключ к еще одному контракту, который может иметь внешний ключ к … и т.д.
Вы хотите иметь все эти контракты в виде одной последовательности контрактов
Для этого мы создаем метод расширения для Contract. Если вы не знакомы с методами расширения, см. раздел [Методы расширения демистифицированы][1]
public static IEnumerable<Contract> GetPreviousReferences(this Contract contract,
IList<Contract> contracts)
{
// TODO: implement
}
Использование будет следующим:
List<Contract> myContracts = ...
Contract contract = myContracts[4];
List<Contract> previousReferences = contract.GetPreviousReferences(myContracts)
.ToList();
Реализация проста, если определение PreviousReferences
понятно:
коллекция предыдущих ссылок контракта представляет собой нулевую или одну предыдущую ссылку контракта все предыдущие ссылки предыдущей ссылки контракта
public static IEnumerable<Contract> GetPreviousReferences(this Contract contract,
IList<Contract> contracts)
{
if (contract.PreviouseReference != 0)
{
// this contract has previous references:
Contract previousContract = contracts[contract.PreviousReference];
yield return previousContract;
foreach (Contract previousReference in previousContract.GetPreviousReferences(contracts))
yield return previousReferences;
}
}
вместо yield return
и foreach(...)
вы можете использовать LINQ Concat:
if (contract.PreviouseReference != 0)
{
Contract previousContract = contracts[contract.PreviousReference];
return new Contract[] {previousContract}
.Contcat(previousContract.GetPreviousContracts(contracts);
}
Это сделает внутренний foreach для вас. Я не уверен, что это решение лучше читается.
[1]: http://geekswithblogs.net/BlackRabbitCoder/archive/2013/03/08/c.net-little-wonders-extension-methods-demystified.aspx