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; }
}
这些是我的实体模型。我在CentralPoint
和BIDatabase
个实体之间建立了一对一的关系,也是BIDatabase
和Connection
个实体之间的一对一关系。显然,每个实体都有一个单独的表。
在控制器内部,我使用新实例更新BIDatabase
的{{1}}属性
CentralPoint
这是控制器部分:
centralPoint.BIDatabase = biDatabase;
之后:
CentralPoint表 - >保持不变:正常
BIDatabase表 - >更新了新ID:正常
连接表 - > //添加新行而不是更新旧行
我想要的是连接实体要更新,而不是每次都为同一个数据库添加。
答案 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表。