簡體   English   中英

實體框架在插入后填充相關記錄

[英]Entity Framework populate related records after insert

我的實體之一如下所示有幾個相關表(大洲、縣、國家/地區),其中將外鍵插入到數據庫表中

public class ContactAddress
{
    [Key]
    public int Id { get; set; } 

    [Required, MaxLength(150)]
    public string AddressLine  { get; set; }
 

    [MaxLength(150)]
    public string Town { get; set; }

    [MaxLength(50)]
    public string PostCode { get; set; }

    [ForeignKey(nameof(Continent))]
    public int? ContinentId { get; set; }

    public Continent Continent { get; set; }

    [ForeignKey(nameof(Country))]
    public int? CountryId { get; set; }

    public Country Country { get; set; }

    [ForeignKey(nameof(County))]
    public int? CountyId { get; set; }

    public County County { get; set; }       
} 

這是向數據庫插入新記錄的代碼

public async Task<ContactAddress> AddNewContactAddress(AddressViewModel viewModel)
{   
    ContactAddress dbModel= new ContactAddress();
    dbModel.AddressLine = viewmodel.AddressLine;
    dbModel.Town=viewmodel.Town;
    dbModel.PostCode=viewmodel.PostCode;
    dbModel.ContinentId=viewmodel.ContinentId;
    dbModel.CountryId=viewmodel.CountryId;
    dbModel.CountyId=viewmodel.CountyId;
    dbContext.ContactAddresses.Add(dbModel);
    await context.SaveChangesAsync().ConfigureAwait(false);
    return dbModel;
}

返回的 dbModel 包含所有這些信息以及 Id / 自動增量為插入的記錄生成的主鍵 但是在重新調整的對象上缺少大陸國家縣的相關信息

我創建了另一種方法

public async Task<ContactAddress> GetContactAddressDetails(int addressId)
{
    return await context.ContactAddresses              
      .Include(c => c.Continent)
      .Include(c => c.Country)
      .Include(c => c.County)
      .FirstOrDefaultAsync(p => p.Id == addressId);
}   


 public async Task<ContactAddress> AddNewContactAddress(AddressViewModel viewModel)
{
    dbModel = convert fromm viewModel to dbModel
    context.ContactAddresses.Add(dbModel);
    await context.SaveChangesAsync().ConfigureAwait(false);
    
    if (dbModel.Id > 0)
    {
        dbModel = await GetContactAddressDetails(dbModel.Id).ConfigureAwait(false);
    }
    return dbModel;

}

這是在實體框架中處理相關記錄的正確方法嗎? 是否可以避免編寫額外的方法來獲取插入后的相關表信息

第一個問題是,當您尚未構建 EF 代理時,您希望有效地依賴延遲加載。

取而代之的是:

ContactAddress dbModel= new ContactAddress();

用:

ContactAddress dbModel = context.ContactAddresses.Create(); 

從那里你可以設置你的 FK 值,EF 應該處理未來的請求以檢索導航屬性,延遲加載數據。

我提倡的插入場景的方法是使用導航屬性而不是 FK 屬性。 在實體中,我通常會聲明其中一個,但不會同時聲明兩者。 對於“盡可能快”的操作,我將只映射 FK,對於更完整的視圖,我將使用導航屬性和 FK 的陰影屬性。 這樣做的主要原因是,如果您有導航屬性和 FK 屬性,那么您現在有兩個關系的真實來源:

contactAddress.CountryId
// and
contactAddress.Country.CountryId

一些接受 ContractAddress 的代碼可能會使用一種或另一種,並且您將獲得不同的行為,具體取決於您是設置 FK 還是導航屬性,以及導航屬性是否已加載。 在您嘗試調用 SaveChanges() 之前,您也不會知道發送的任何提供的值是否有效,讓您嘗試處理如果一個或多個 FK 值無效時該怎么做。

使用導航屬性看起來更像是:

public async Task<ContactAddress> AddNewContactAddress(AddressViewModel viewModel)
{   
    ContactAddress dbModel= new ContactAddress();
    dbModel.AddressLine = viewmodel.AddressLine;
    dbModel.Town=viewmodel.Town;
    dbModel.PostCode=viewmodel.PostCode;

    dbModel.Continent = context.Continents.SingleOrDefault(x => x.ContinentId == viewModel.ContinentId) ?? throw new ArgumentException("The provided continent ID was not valid.");
    dbModel.Country=context.Countries.SingleOrDefault(x => x.CountryId == viewModel.CountryId) ?? throw new ArgumentException("The provided country ID was not valid.");
    dbModel.Country=context.Counties.SingleOrDefault(x => x.CountyId == viewModel.CountyId) ?? throw new ArgumentException("The provided county ID was not valid.");    
    dbContext.ContactAddresses.Add(dbModel);
    await context.SaveChangesAsync().ConfigureAwait(false);
    return dbModel;
}

SingleOrDefault()調用 /w 專用拋出可能就像Single()一樣容易,其中會引發相關實體集的Expected 1, found 0異常。 這僅取決於您是要處理異常以向客戶端提供一些反饋還是僅記錄異常。

這避免了重新加載實體的需要。 它還斷言每個引用的 ID 在創建新行時本身都是有效的。 您會得到一個可以使用的完整模型。 加載實體似乎是不必要的成本,但考慮到您希望在調用后加載數據,這里完成的性能成本與發回時的延遲加載調用沒有什么不同。 您得到的好處是,在SaveChanges調用中,這些值是有效的,每個值都有一個有意義的“拋出”點,而不是一次。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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