1

В моем приложении, Agency имеет много Employees, один из которых делегированы владелец указанного агентства:Как решить эту циклическую зависимость в EF

public class Employee 
{ 
    public int EmployeeId { get; set; } 
    public string EmployeeName { get; set; } 
    public int EmployerId { get; set; } 

    [ForeignKey("EmployerId")] 
    public virtual Agency Employer { get; set; } 
} 

public class Agency 
{ 
    public int AgencyId { get; set; } 
    public string AgencyName { get; set; } 
    public int OwnerId { get; set; } 

    [ForeignKey("OwnerId")] 
    public virtual Employee Owner { get; set; } 

    [InverseProperty("Employer")] 
    public virtual ICollection<Employee> Employees { get; set; } 
} 

Я пытаюсь ввести новый Agency в datebase с использованием этот код:

var agency = new Agency(); 
// ... 

context.Agencies.Add(agency); 

var owner = new Employee(); 
// ... 

context.Employees.Add(owner); 

owner.Employer = agency; 
agency.Owner = owner; 

context.SaveChanges(); 

Когда слово SaveChanges, я получаю следующее сообщение об ошибке, которое я полагаю, связано с круговой зависимостью я описал выше:

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

Есть ли способ в EF указать порядок для «зависимой операции»? В качестве альтернативы, есть ли лучший способ написать мою базу данных таким образом, чтобы она обошла эту проблему, но все же моделирует структуру данных, которую я хочу?

+0

делает ваш фактический DB Schema выглядеть так, как вы ожидали? –

+0

Да, точно, как я ожидал. – ajbeaven

ответ

3

Я не уверен, что было бы возможно создать агентство и владельца в SQL, потому что для хранения агентства вам нужен действительный FK владельцу и для хранения владельца вам нужен действительный FK агентству. Из-за ограничений FK (если они не будут применены), вы не сможете сохранить их, не нарушая ограничений.

раствор (и я не знаю другой) делает одно из отношений факультативных, например Owner путем определения OwnerId в обнуляемым:

public int? OwnerId { get; set; } 

Это не будет решать «действительный заказывая "исключение, но теперь вы можете хранить агентство без владельца, а затем хранить владельца с отношением к уже имеющемуся агентству. Для того, чтобы сделать всю работу «атомным» вы можете обернуть два необходимых вызовы на SaveChanges во внешние сделки:

using (var tx = new TransactionScope()) 
{ 
    var agency = new Agency(); 

    context.Agencies.Add(agency); 

    context.SaveChanges(); // inner transaction 1 
    // saves agency with OwnerId = NULL, it wouldn't work with a required owner 
    // agency has a primary key from the database now 

    var owner = new Employee(); 

    context.Employees.Add(owner); 

    owner.Employer = agency; // sets FK EmployerId to the now known PK of agency 
    agency.Owner = owner; 

    context.SaveChanges(); // inner transaction 2 

    tx.Complete(); // commits the outer transaction 
} 
+0

Хм, грустно. Я пытался избежать транзакции, поскольку я читал, что они могут вызывать взаимоблокировки с сущностью. Является ли приведенный выше код вероятным причиной таких проблем? – ajbeaven

+1

@ajbeaven: Да, уровень изоляции * по умолчанию 'TransactionScope' является довольно ограничительным (' Serializable'). Но вы можете легко изменить его, например, на «Снимок», что делает тупики гораздо менее вероятными: http://blogs.msdn.com/b/diego/archive/2012/04/01/tips-to-avoid-deadlocks- в-сущности-каркасного applications.aspx – Slauma

Смежные вопросы