EF 6 Code-First отношение «многие ко многим» с одним и тем же объектом на неосновном ключе - PullRequest
0 голосов
/ 13 февраля 2019

У меня есть объект EF 6 Task, который выглядит следующим образом:

public class Task
{
    public Guid TaskId {get; set;}
    public TaskTypeEnum TaskType {get; set;}
    public TaskStatusEnum TaskStatus {get; set;}

    public virtual ICollection<Task> Dependencies {get; set;}
}

Задачи определенного типа могут зависеть от всех других задач определенного типа, которые должны завершиться до их запуска, и те,зависимости должны быть определены в таблице следующим образом:

public class TaskTypeDependency
{
    public TaskTypeEnum TaskType {get; set;}
    public TaskTypeEnum DependsOnTaskType {get; set;}
}

Пример того, что я хочу - Задача A имеет Тип 1, Задача B и C имеют Тип 2. У меня TaskTypeDependency

TaskType | DependsOnTaskType
----------------------------
1        |  2              

Во время выполнения я хочу получить все задачи, от которых зависит эта задача, а для задачи A - это задача B и задача C, чтобы проверить, завершены ли зависимые задачи.Есть ли способ установить эти отношения в Code-First, может быть, с помощью Fluent API?Или я застрял с помощью LINQ, чтобы разобраться во всем без виртуального свойства?

1 Ответ

0 голосов
/ 13 февраля 2019

Добро пожаловать в StackOverflow!

Насколько я знаю, EF не может обрабатывать отношения такого рода.

Ваша проблема не в том, что основной ключ не является первичным ключом.Ваша основная проблема заключается в том, что эти ключи (TaskType s) не являются уникальными .

Предложение решения

Вы можете обойти это ограничение, инкапсулировав логику загрузкизависимые задачи в хранилище.Хотя многие люди советуют против построения шаблона хранилища поверх EF, и в большинстве случаев я тоже на этой стороне, это отличный пример того, почему он может быть полезен.

Я бы создал метод, который заполняет зависимости, используя LINQ, может быть, метод расширения, что-то вроде:

private static void LoadDependentTasks(this Task task, IEnumerable<Task> allTasks){
    task.Dependencies = allTasks.Where(yourCustomSelector).ToList();
}

Затем в вашем хранилище вы можете использовать этот метод в задачах, которые вы загрузили, прежде чем вернуть их,Например:

public Task GetById(Guid taskId){
    Task t = _context.Tasks.Find(taskId);
    t.LoadDependentTasks(_context.Tasks);
}

Затем, когда ваша бизнес-логика вызывает ваш репозиторий, он получит объекты, у которых уже заполнено свойство Dependencies.

Есть одна оптимизация это стоит упомянуть здесь, хотя.Это не так важно для получения одной задачи, но имеет большое значение при загрузке их всех.Если вы наивно реализуете метод GetAll, как показано ниже, будет извлекать список задач с сервера n х , что не очень хорошо.

public Task GetAll(){
    List<Task> allTasks = _context.Tasks.ToList();
    foreach(var task in allTasks)
        task.LoadDependentTasks(_context.Tasks);
    return allTasks;
}

Вместо этого вы должны передать уже существующую переменную allTasks в метод.Если - в другом сценарии - у вас нет списка задач, другое решение - вызвать _context.Tasks.Load() и затем использовать _context.Tasks.Load.

...