嗨,我正在嘗試使用我的 Asp.Net MVC 專案在我的物體企業中添加一個 ApplicationUser(IdentityUser 的派生類)。它們之間存在多對多的關系,并且自從我的資料庫中的 ApplicationUserEntreprise 表更新以來,它似乎有效。但是當我嘗試做類似 user.Entreprisew 或 entreprise.Users 的事情時,它總是回傳 null
這是我的 EntrepriseRepo 的 addUser 方法,我嘗試在我的物體之間建立鏈接
public void AddUser(ApplicationUser user , Entreprise entreprise) {
Entreprise entrepriseFromDb = base.FirstOrDefaultAsync(u => u.Id == entreprise.Id).Result;
if (entrepriseFromDb.ApplicationUsers == null)
{
entrepriseFromDb.ApplicationUsers = new List<ApplicationUser>();
entrepriseFromDb.ApplicationUsers.Add(user);
}
else {
entrepriseFromDb.ApplicationUsers.Add(user);
}
if (user.Entreprises == null) {
user.Entreprises = new List<Entreprise>();
user.Entreprises.Add(entrepriseFromDb);
}
else
{
user.Entreprises.Add(entrepriseFromDb);
}
}
我的控制器
public async Task AddUser(int id, string UserId)
{
Entreprise entreprise = await _services.Configuration.GetEntreprise(id);
ApplicationUser user = await _userManager.FindByIdAsync(UserId);
_services.Configuration.AddUserToEntrepriseAsync(user, entreprise);
await Details(id);
}
我的服務
public void AddUserToEntrepriseAsync(ApplicationUser user, Entreprise entreprise) {
_uow.Entreprises.AddUser(user, entreprise);
_uow.Save();
}
這是我的 SQL 資料庫

這是我的課程
應用用戶
public class ApplicationUser : IdentityUser
{
public ICollection<Entreprise> Entreprises { get; set; }
}
企業
public class Entreprise
{
public int Id { get; set; }
public string Nom { get; set; }
public string LogoURL { get; set; }
public List<Groupe> Groupes { get; set; }
public List<Periode> Periodes { get; set; }
[NotMapped]
public int GroupesCount { get; set; }
[NotMapped]
public int EquipementsCount { get; set; }
[NotMapped]
public int PeriodesCount { get; set; }
public ICollection<ApplicationUser> ApplicationUsers{ get; set; }
}
有什么辦法可以通過執行 entreprise.User 和我的 entreprise 通過執行 user.Entreprises 來獲取我的用戶串列嗎?
uj5u.com熱心網友回復:
您的代碼有幾個問題。
首先,不要FirstOrDefault()用作檢索物體的拐杖方法。如果您希望應該有一個物體,請使用Single(). 如果您希望有一個物體或可能沒有物體,請使用SingleOrDefault(). 如果您期望多個物體或可能什么都沒有,并且只關心第一個物體,請使用FirstOrDefault(),但也只能與OrderBy*()方法結合使用。
接下來,不要.Result在異步呼叫上使用。要么一直使用等待的異步方法,要么使用同步方法。
傳遞潛在的分離物體可能會導致應用程式中的很多混亂,因為您可能會得到一個分離的物體、一個由當前 DbContext 跟蹤的物體,或者一個由另一個 DbContext 跟蹤的物體。所有 3 種情況都可能導致不同的例外。無論如何,當您從 DbContext 獲取物體時,傳遞物體也是不需要的開銷。我建議對 ApplicationUser 資訊使用 ViewModel/DTO,如有必要,您可能會使用它來創建新用戶,并且只傳遞企業 ID。我們還將對與該企業相關聯的任何用戶感興趣,因此我們應該立即加載這些用戶.Include():
public void AddUser(ApplicationUserViewModel userVm , int entrepriseId)
{
Entreprise entreprise = base
.Include(e => e.ApplicationUsers)
.Single(e => e.Id == entrepriseId);
// ...
接下來,避免在代碼中初始化集合參考,而是初始化物體中的屬性。代碼“沒問題”,但在被跟蹤物體中重新初始化集合可能會導致問題,這僅需要分散的額外條件邏輯在添加之前檢查空集。
public class Enterprise
{
// ...
public virtual ICollection<ApplicationUser> ApplicationUsers { get; internal set; } = new List<ApplicationUser>();
}
這同樣適用于 ApplicationUser 初始化它的企業集合。
在添加用戶之前,我們的代碼應該斷言該用戶尚未關聯,因為這也可能導致例外。您還應該考慮在此程序中是關聯現有用戶記錄還是創建新用戶。理想情況下,這些操作應該是原子的,因此創建全新用戶是將用戶關聯到企業的單獨操作。您的代碼的危險在于 DbContext 可能正在跟蹤
所以而不是:
if (entrepriseFromDb.ApplicationUsers == null)
{
entrepriseFromDb.ApplicationUsers = new List<ApplicationUser>();
entrepriseFromDb.ApplicationUsers.Add(user);
}
else
{
entrepriseFromDb.ApplicationUsers.Add(user);
}
if (user.Entreprises == null) {
user.Entreprises = new List<Entreprise>();
user.Entreprises.Add(entrepriseFromDb);
}
else
{
user.Entreprises.Add(entrepriseFromDb);
}
...我們做的更像是:
if (userVm.Id != 0 && enterprise.ApplicationUsers.Any(u => u.Id == userVm.Id))
return; // user is already associated.
ApplicationUser user = userVm.Id == 0
? createUser(userVm)
: base.ApplicationUsers.Single(u => u.Id == userVm.Id);
enterprise.ApplicationUsers.Add(user);
base.SaveChanges(); // Or saved further up the call stack/unit of work...
當我們通過導航屬性關聯配置有關系的物體時,EF 將自動管理雙向關系。我們希望避免做任何事情,比如檢查和假設我們需要初始化集合,因為如果我們在錯誤的假設上搞砸了,這很容易導致錯誤。上面的代碼假設我們可能會獲得一個新用戶或應該是現有用戶。如果我們得到一個現有用戶,我們檢查企業是否已經擁有它,如果有則退出。否則我們準備添加它。如果 Id 不存在,我們使用視圖模型中的詳細資訊創建一個新的 ApplicationUser。這可以使用 Automapper 和.Map<ApplicationUser>(). 否則,我們從 DbContext 中獲取 User 參考。我們用Single()再次作為完整性檢查以確保提供的用戶詳細資訊有效。如果呼叫方傳遞的 UserId 為“101”,并且沒有該 ID 的記錄,則應用程式應將此視為例外,因為資料狀態確實有問題或被篡改。
這將通過更多原子方法進一步簡化,其中 CreateUser 操作與 AddUserToEnterprise 操作分開,后者可以期望始終獲得現有的 User 參考。這樣 AddUserToEnterprise 只需要傳遞一個 EnterpriseId 和一個 UserId 而不是有條件邏輯來處理新用戶和現有用戶。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/388558.html
