Получение всей записи с помощью ссылочного номера в LINQ

#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