C# 实体框架代码首先从父项中删除一到零/一个子项

C# 实体框架代码首先从父项中删除一到零/一个子项,c#,entity-framework,ef-code-first,code-first,C#,Entity Framework,Ef Code First,Code First,我首先在代码内部创建了一个简单的一对零/一关系。下面的代码的工作原理是,我可以拥有一个Person实例,并且可以选择在数据库中拥有一个帐户及其模型 public class Person { public int Id { get; set; } public string Name { get; set; } public virtual Account Account { get; set; } } public class Account { public

我首先在代码内部创建了一个简单的一对零/一关系。下面的代码的工作原理是,我可以拥有一个Person实例,并且可以选择在数据库中拥有一个帐户及其模型

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);
公共类人物
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟帐户{get;set;}
}
公共类帐户
{
公共int Id{get;set;}
公共字符串位置{get;set;}
公共虚拟人所有者{get;set;}
}
//映射
modelBuilder.Entity().has可选(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();
}
使用(Context ctx=new Context())
{
var personToDeleteFrom=ctx.Persons.Single(x=>x.Id==);
personToDeleteFrom.Account=null;
ctx.SaveChanges();
}

但是,关系的子对象只是留在数据库中。有没有办法让这一切顺利进行?如果没有,处理这种关系的最佳实践是什么?

仅通过将导航属性设置为null,实际上并不是删除子数据。您需要实际删除数据以使其消失

只需将
账户
集合上的null设置改为
删除

using (Context ctx = new Context())
{
    var personToDeleteFrom = ctx.Persons.Single(x => x.Id == <personid>);
    ctx.Accounts.Remove(personToDeleteFrom.Account);
    ctx.SaveChanges();
}
这将抛出一个
System.Date.Core.Entity.UpdateException
,因为它试图向Accounts表添加一个主键设置为的条目,而该条目已经存在


因此,清空导航属性实际上没有任何作用。通过保持每个实体的主键同步来维护关系。要实际删除该帐户,需要将其从表中删除

不,这不会引发引用完整性冲突。它将抛出一个重复的主键异常,因为您现在有多个记录具有相同的主键。EF不做任何事情来保持这些同步,而是依靠数据库通过主键约束来实现。@ErikFunkenbusch正确,EF不是维护Account表中外键需要存在于数据库Persons表中这一事实的人。EF实际上所做的是确保个人身份证和账户身份证相等。您可以轻松地分析EF生成的SQL,以查看在将新帐户分配给persons Account属性时插入的Id与Person具有相同的Id。这就是EF保持1:1关系的方式。如果Id必须相等,则它们只有1:1的关系。如果您查看由上述实体创建的表的表定义,则人员上的Id列(因为EF足够聪明,可以将其称为人员而不是人员,见图)被定义为标识(1,1)NOT NULL,其中帐户的Id列不为NULL。我假设这是为了让EF可以管理Account的Id值来维护这种关系。是的,但如果您尝试添加第二个帐户,这并不是违反引用完整性。这是一个重复的主键约束冲突。在插入过程中,EF确实会将生成的ID从所需端分配给可选端,但在数据库处理事情时,它不会进行任何引用完整性跟踪。@ErikFunkenbusch如果你看,我编辑了答案以反映在初始注释后引发的确切异常。我对你的评论最关心的是你说EF没有做任何事情来保持这些同步,这是不正确的。数据库确保帐户上的Id存在,但该Id由EF而不是数据库分配。
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();
}