EF更新关系的子关系

时间:2017-07-11 21:03:24

标签: c# entity-framework

EF跟踪让我困惑。这是我想要实现的方案:

public class CentralPoint
{
   public Guid ID { get; set; }
   public virtual BIDatabase BIDatabase { get; set; }
}

public class BIDatabase
{
    public Guid ID { get; set; }
    public Guid CentralPointID { get; set; }
    public virtual CentralPoint CentralPoint { get; set; }
    public Guid ConnectionID { get; set; }
    public virtual Connection Connection { get; set; }
}

public class Connection
{
    public Guid ID { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
}

这些是我的实体模型。我在CentralPointBIDatabase个实体之间建立了一对一的关系,也是BIDatabaseConnection个实体之间的一对一关系。显然,每个实体都有一个单独的表。

在控制器内部,我使用新实例更新BIDatabase的{​​{1}}属性

CentralPoint

这是控制器部分:

centralPoint.BIDatabase = biDatabase;

之后:

  

CentralPoint表 - >保持不变:正常

     

BIDatabase表 - >更新了新ID:正常

     

连接表 - > //添加新行而不是更新旧行

我想要的是连接实体要更新,而不是每次都为同一个数据库添加。

3 个答案:

答案 0 :(得分:0)

认为我看到了这个问题。

当您替换centralPoint.BIDatabase = biDatabase;时,您的新BIDatabase对象可能没有ID将其链接到Connection

尝试将您需要的字段映射到现有对象上,而不是将其替换(或替换它,但首先将要保留的任何ID和现有字段映射到新对象上)。

答案 1 :(得分:0)

什么代码创建了这个新的biDatabase?它是否在此方法之前持久保存到dbContext?

您对BIDatabase和连接表的期望有点可疑。给定现有的CentralPoint / w BIDatabase / w Connection,如果将CentralPoint的BIDatabase“更改”为新的BIDatabase,则不会更新现有记录,而是替换它。这意味着将删除旧记录及其关联的连接,并插入新的BIDatabase / w新连接。假设这些实体配置了DB生成的密钥:

实施例: CentralPoint(id:1) - > BIDatabase(id:1) - >连接(ID:1)

使用新的Connection(id:x)创建新的BIDatabase(id:x),然后:

CentralPoint.BIDatabase = newBIDatabase

BIDatabase(id:1)&连接(标识:1)标记为删除。 新的BIDatabase&保存时,连接将与新ID保持一致。

CentralPoint(id:1) - > BIDatabase(id:2) - >连接(ID:2)

如果要替换BIDatabase但保留相同的连接ID /引用:

创建新的BIDatabase(id:x)/ w Connection(id:x)

但在将其保存到上下文之前:

   var centralPoint = _context.CentralPoint.Where(cp => cp.ID == cpId)
        .Include(cp => cp.BIDatabase)
        .ThenInclude(biDb => biDb.Connection)
        .FirstOrDefault();

   biDatabase.Connection = (centralPoint?.BIDatabase?.Connection) ?? biDatabase.Connection;

    centralPoint.BIDatabase = biDatabase;
    await _context.SaveChangesAsync();

该额外语句的作用是通过将引用复制到新的BIDatabase来保留现有CentralPoint.BIDatabase上已有的连接。如果现有BIDatabase没有连接(或现有CP没有BIDatabase),则将使用创建的新连接。如果您在此代码之前未将新BIDatabase保存到dbContext,则“新”连接(id:x)将永远不会插入现有替换的位置。

答案 2 :(得分:0)

我正在做一些错误。我正在详细说明它们,这可能对其他人有帮助。

第一个错误(@ Steveland83指出)

  

centralPoint.BIDatabase = biDatabase;

由于CentralPoint实体正被上下文(DbContext)跟踪,我们不能简单地用另一个属性替换属性。我们需要通过复制值来修改属性。 所以应该做以下事情

  

_context.Entry(centralPoint.BIDatabase).CurrentValues.SetVal的UE(biDatabase);

第二个错误 通过上面的修复,我期望上下文跟踪centralPoint.BIDatabase中的所有属性更改并自行更新(在我的情况下是Connection属性,例如centralPoint.BIDatabase.Connection)

然而不幸的是,非原始类型不会发生这种情况。您必须明确告诉上下文哪些非原始属性已更改。 这是第二个修复

  

_context.Entry(centralPoint.BIDatabase).CurrentValues.SetVal的UE(biDatabase);

     

_context.Entry(centralPoint.BIDatabase.Connection).CurrentValues.SetVal的UE(biDatabase.Connection);

这将更新BIDatabase和Connection表。