簡體   English   中英

使用實體框架使用外鍵將不同的記錄插入表中

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM