[英]EF update the child relation of a relation
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
一對一關系,在BIDatabase
和Connection
實體之間也存在一對一關系。 顯然,每個實體都有一個單獨的表。
在控制器內部,我正在使用新實例更新CentralPoint
的BIDatabase
屬性。
centralPoint.BIDatabase = biDatabase;
這是控制器部分:
public async Task<IActionResult> AddBIDatabaseAsync(Guid cpId, BIDatabase biDatabase)
{
// context is available through Dependency Injection (.net core)
var centralPoint = _context.CentralPoint.Where(cp => cp.ID == cpId)
.Include(cp => cp.BIDatabase)
.ThenInclude(biDb => biDb.Connection)
.FirstOrDefault();
centralPoint.BIDatabase = biDatabase;
await _context.SaveChangesAsync();
// more code ...
}
在這之后:
CentralPoint表->保持不變:正常
BIDatabase表->更新為新ID:正常
連接表-> //添加新行,而不是更新舊行
我想要的是對同一數據庫每次都更新而不是每次添加的連接實體。
我想我看到了問題。
當您替換centralPoint.BIDatabase = biDatabase;
您的新BIDatabase
對象可能沒有將其鏈接到Connection
的ID
嘗試將所需的字段映射到現有對象上,而不是替換它(或替換它,但首先將要持久化的所有Id和現有字段映射到新對象上)。
什么代碼創建了這個新的biDatabase? 在此方法之前,它是否一直保留到dbContext?
您對BIDatabase和連接表的期望有點可疑。 給定現有的CentralPoint / w BIDatabase / w連接,如果將CentralPoint的BIDatabase“更改”為新的,則現有記錄不會更新,它將被替換。 這意味着將刪除舊記錄及其關聯的連接,並插入新的BIDatabase / wa new Connection。 假設使用數據庫生成的密鑰配置了這些實體:
示例:CentralPoint(id:1)-> BIDatabase(id:1)-> Connection(id:1)
使用新的連接(id:x)創建新的BIDatabase(id:x),然后:
CentralPoint.BIDatabase = newBIDatabase
BIDatabase(id:1)和Connection(id:1)被標記為刪除。 保存時,新的BIDatabase&Connection將保留新的ID。
CentralPoint(id:1)-> BIDatabase(id:2)-> Connection(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)將永遠不會插入到替換現有BIDatabase的位置。
我在犯一些錯誤。 我正在詳細說明它們,因此可能會對其他人有所幫助。
第一個錯誤 (由@ Steveland83指出)
centralPoint.BIDatabase = biDatabase;
由於上下文(DbContext)跟蹤了CentralPoint實體,因此我們不能簡單地用另一個屬性來替換。 我們需要通過復制值來修改屬性。 因此,應改為執行以下操作
_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表。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.