我習慣性使用OData,它的$expand與層級查詢非常好用,這個功能非常依賴于資料庫的導航屬性,也就是外鍵結構,最近想著把一個單體的系統拆分為多個小系統,首先需要處理外鍵依賴的問題,
多個服務各自有各自的資料庫,資料庫層面并不互通,也就無法使用外鍵約束,
我使用EF Core來描述資料庫的結構,有兩個物體類如下:
public class AD_Insect_Info
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id {get;set;}
public string Name { get; set; }
public virtual List<AD_Insect_Datum> Results { get; set; }
}
public class AD_Insect_Datum
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public virtual AD_Insect_Info AttachDevice { get; set; }
[NotMapped]
public override string AttachId => AttachDevice.AttachDeviceId;
}
可以看到他們之間有一個導航屬性,實作一個一對多的關系,如果系統是新系統,大可直接進行拆解,想怎么弄就怎么弄,但是對于已經有較多資料的現有系統,最好使用漸進拆分的方式,
思路:通過多次,每次只修改一點,維持對舊有系統的兼容性,并在完全拆分前保持系統高度可用,破壞性最小,
指定外鍵
跨資料庫的訪問,資料完整性不能由資料庫通過外鍵實作,我們需要在應用層實作自己的邏輯,由于外鍵不存在,我們需要在資料表中有表示對外參考的欄位,而對于導航屬性而言,外鍵已經由EF Core自動建立,為了防止資料結構變化導致的問題,我們可以明確指定外鍵,
查詢資料表結構
EF Core有默認的外鍵命名規則,通常是欄位名+外鍵的欄位名,對于本例,則是AttachDeviceId,保險起見,我們可以查詢資料庫獲得外鍵列名稱,
顯式指定外鍵名稱
導航屬性的外鍵名字不是那么直觀,我們可以使用EF Core的ForeignKey特性,
public class AD_Insect_Datum : AttachDataBase
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[ForeignKey("AttachDeviceId")]
public virtual AD_Insect_Info AttachDevice { get; set; }
public int AttachDeviceId { get; set; }
}
這樣,這個物件Id就被顯式指定了,
查詢替代
前一步指定了外鍵,但是實際上并沒有對EF Core表做任何更改,原來的程式可以正常運行,我們需要在這個基礎上繼續改造,將使用導航屬性的地方修改一下,
public virtual async Task<IActionResult> Data(string key)
{
return Ok(_context.AD_Insect_Data.Where(w => w.AttachDevice.Name == key));
}
修改為:
public virtual async Task<IActionResult> Data(string key)
{
var instances = _context.AD_Insect_Infos.Where(w=>w.Name == key).Select(w=> w.Id).ToList();
return Ok(_context.AD_Insect_Data.Where(w => instances.Contains(w.AttachDeviceId)));
}
這樣就避免使用導航屬性依賴,
我這里也沒有使用連表查詢方法,因為將來需要拆分,
洗掉外鍵
由于不再使用導航屬性,可以安全地洗掉外鍵,注意,可能需要補充一些業務邏輯以確保資料庫中的資料完整性,
拆分DbContext
將來DbContext將不再擁有AD_Insect_Infos,因此我們需要進一步拆分,
public virtual async Task<IActionResult> Data(string key)
{
IEnumerable<int> instances = Foreign.GetList(key);
return Ok(_context.AD_Insect_Data.Where(w => instances.Contains(w.AttachDeviceId)));
}
public class Foreign
{
public IEnumerable<int> GetList(string key)
{
return _context.AD_Insect_Infos.Where(w=>w.Name == key).Select(w=> w.Id).ToList();
}
}
上面代碼表示大致的思路,請自行處理注入依賴等問題,
然后就是熟悉的動作了,將Foreign類作為一個資料服務,只要回傳的型別是IEnumerable<int>
就可以了,資料的來源可以是本身,也可以是外部的服務,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/551359.html
標籤:.NET技术
上一篇:外鍵拆分手記
下一篇:返回列表