2015-01-09 2 views
1

Сначала я создал простую связь с нулем/одним внутри кода. В приведенном ниже коде показано, что я могу иметь экземпляр Person и, возможно, иметь учетную запись и ее смоделированный штраф в базе данных.Код элемента Entity Framework Сначала удаляем один из ноль/одного дочернего элемента из родителя

public class Person 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual Account Account { get; set; } 
} 

public class Account 
{ 
    public int Id { get; set; } 
    public string Location { get; set; } 
    public virtual Person Owner { get; set; } 
} 
//Mapping 
modelBuilder.Entity<Person>().HasOptional(x => x.Account).WithRequired(x => x.Owner); 

Что бы я хотел сделать, так это удалить необязательный дочерний элемент из родителя. Я бы ожидал, что это сработает.

using (Context ctx = new Context()) 
{ 
    var personToDeleteFrom = ctx.Persons.Single(x => x.Id == <personid>); 
    personToDeleteFrom.Account = null; 
    ctx.SaveChanges(); 
} 

Однако дочерний объект отношений просто оставлен в базе данных. Есть ли способ сделать эту работу? Если нет, то какова наилучшая практика для взаимодействия с этим типом отношений?

ответ

1

Фактически вы не удаляете дочерние данные, просто устанавливая свойство навигации равным нулю. Вам нужно фактически удалить данные, чтобы заставить их уйти.

Просто измените настройку нулевого значения на Remove на коллекцию Accounts.

using (Context ctx = new Context()) 
{ 
    var personToDeleteFrom = ctx.Persons.Single(x => x.Id == <personid>); 
    ctx.Accounts.Remove(personToDeleteFrom.Account); 
    ctx.SaveChanges(); 
} 

Это удалит Account.

Это связано с тем, как Entity Framework обрабатывает отношения 1: 1. EF фактически не добавляет в базу данных поля внешнего ключа, поскольку они не нужны. Вместо этого он просто поддерживает связь, что первичный ключ для Account всегда равен первичному ключу для связанного Person.

Это поведение возникает, если вы попытаетесь сделать следующее.

using (Context ctx = new Context()) 
{ 
    var person = ctx.Persons.Single(x => x.Id == <personid>); 
    person.Account = null; 
    ctx.SaveChanges(); 

    person.Account = new Account(); 
    ctx.SaveChanges(); 
} 

Это будет бросать System.Date.Core.Entity.UpdateException, как он пытается добавить запись в таблицу счетов с первичным ключом, установленным в <PersonId>, когда один уже существует.

Как таковое, исключение свойства навигации фактически не делает ничего. Связь поддерживается путем сохранения первичных ключей каждого объекта в синхронизации. Чтобы действительно удалить учетную запись, вам необходимо удалить ее из таблицы.

+0

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

+0

@ErikFunkenbusch Правильно, EF не поддерживает тот факт, что внешний ключ в таблице Account должен существовать в таблице Person, которая является базой данных. Фактически, EF делает, чтобы удостоверение личности на лице и идентификатор на счете были равны. Вы можете легко профилировать SQL, сгенерированный EF, чтобы увидеть, что идентификатор, вставленный при назначении новой учетной записи владельцу аккаунта, имеет тот же идентификатор, что и Person. Именно так EF поддерживает идею отношения 1: 1. Если идентификаторы должны быть равны, тогда нет никаких шансов на то, что они будут чем-то вроде отношения 1: 1. –

+0

Если вы посмотрите на определения таблиц, созданных указанными выше объектами, столбец «Идентификатор» для людей (поскольку EF достаточно умен, чтобы называть его людьми, а не людьми, идите на рисунок) определяется как IDENTITY (1, 1) NOT NULL где, поскольку столбец Идентификатора счета просто НЕ НУЛЛ. Я предполагаю, что EF может управлять значениями Id для учетной записи для поддержания этих отношений. –

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