![](/img/trans.png)
[英]How to insert a record into a table with a foreign key using Entity Framework in ASP.NET MVC
[英]Insert distinct record into table with foreign key using Entity Framework
這些是我的模型,並且我在以代碼優先方式使用Entity Framework。
public class Respondent
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int RespondentId { get; set; }
public User Requester { get; set; }
public User Provider { get; set; }
public string Role { get; set; }
}
public class User: IUser
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public int UPI { get; set; }
public string Name { get; set; }
}
這是兩個生成的表的關系。
我想要的是如果用戶存在於用戶表中,則不要創建用戶的另一個條目。
問題是我每次添加新的提供程序(用戶類型)時,都會在用戶中創建新條目,即使該用戶存在也是如此。 我想要的是在受訪者表中添加該用戶的引用。
private Context db = new Context();
public async Task<IHttpActionResult> PostRespondent(Respondent respondent)
{
var TempProvidersList = respondent.Providers.ToList();
try
{
var requester = db.Users.Single(s => s.UserId == respondent.Requester.UserId);
requester.IsPublic = false;
var providerIds = respondent.Providers.Select(x => x.UPI).ToList();
foreach (var providerId in providerIds)
{
if (!db.Respondents.Any(x => x.Requester.UserId == requester.UserId && x.Provider.UPI == providerId))
{
var provider = respondent.Providers.Single(x => x.UPI == providerId);
provider.IsPublic = true;
db.Respondents.Add(new Respondent() { Requester = requester, Provider = provider, Role = provider.Role });
}
}
db.SaveChanges();
}
catch (Exception ex)
{
}
return CreatedAtRoute("DefaultApi", new { id = respondent.RespondentId }, respondent);
}
我相信問題是由於傳遞了由其他DbContext加載的實體,然后在新的DbContext中添加了對這些實體的引用。
這里的代碼沒有多大意義:
var res = db.Respondents
.Include(user => user.Requester)
.Include(user => user.Provider)
.Where(o => o.Requester.UserId == requester.UserId ).ToList();
在代碼中任何地方都不使用“ res”的地方。 您是否確實使用了“ a”這個詞? 首先,如果您只想檢查行的存在,請使用Any()
if (!db.Respondents.Any(x => x.Requester.UserId == requester.UserId))
而不是加載所有可用的實體只是為了檢查是否存在某些實體。
我看到的問題區域是這樣的:
tempProvider = TempProvidersList[i];
db.Respondents.Add(new Respondent() { Requester = requester, Provider = tempProvider, Role = TempProvidersList[i].Role });
這是在新的響應者中將您的提供者引用設置為可能是從其他DbContext實例加載的用戶(提供者)。
為了解決這個問題,您設置的所有引用都應從當前的DbContext中加載:
var providerIds = respondent.Providers.Select(x => x.UPI).ToList();
var providers = db.Users.Where(x => providerIds.Contains(x.UPI)).ToList();
var requester = db.Users.Single(s => s.UserId == respondent.Requester.UserId);
requester.IsPublic = false;
foreach(var providerId in providerIds)
{
if (!db.Respondents.Any(x => x.Requester.UserId == requester.UserId))
{
var provider = providers.Single(x => x.UPI == providerId);
provider.IsPublic = true;
db.Respondents.Add(new Respondent() { Requester = requester, Provider = provider, Role = provider.Role });
}
}
db.SaveChanges();
我選擇根據ID在一次點擊中加載所有適用的提供程序,而不是在循環內一次加載一次。 在循環中,我只是嘗試從加載的集中檢索與ID匹配的那個。
我會用try / catch塊包裝它並處理異常。 可能想到的例外是找不到ProviderId的用戶時。 (可以刪除用戶嗎?)我對ID而不是已加載的引用進行了foreach操作,因為基於上述條件,該集合可能沒有每個ID的實體。 (如果6個ID中只有5個加載了提供者用戶,則ID集合將有6個元素,而實體集合將只有5個元素)
這里的另一點是使用Single
而不是FirstOrDefault
記錄一條記錄。 這將強制執行該規則,並且如果存在多個或不匹配的記錄,則將引發異常。 僅當找不到行是預期結果時才應使用“ OrDefault”變體。 如果一個或多個匹配項進入數據庫,則FirstOrDefault
將隱藏問題,並且如果沒有“ OrderBy”子句,則您不能依賴於將返回哪個引用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.