簡體   English   中英

如何使用導航屬性將更改正確保存到實體

[英]How to correctly save the changes to Entity with Navigation Properties

我正在嘗試編寫PUT-action的正確實現。 我有一個基本的Model類(我們稱它為Model)。

public class Model
{
    [Key]
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
    [Required]
    public User Creator { get; set; }
}

創建者是必需的導航屬性,該屬性通過外鍵引用User實體。 另外,我有一個用於我的模型的簡單DTO類,該類正在從客戶端發布。

public class ModelDTO
{
    public int Id { get; set; }
    public string Name { get; set; }
}

如您所見,DTO類不包含Creator引用,因為我們不需要從客戶端進行更新。

這是PUT動作。 它基於Visual Studio為我提供的模板。 我剛剛添加了Automapper調用以將DTO映射到Model。

    // PUT: api/Models/5
    [ResponseType(typeof(void))]
    public async Task<IHttpActionResult> PutModel(int id, ModelDTO modelDTO)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (id != Model.Id)
        {
            return BadRequest();
        }

        var model = Mapper.Map<Model>(modelDTO); // i've just added this
        db.Entry(model).State = EntityState.Modified;

        try
        {
            await db.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!ModelExists(id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return StatusCode(HttpStatusCode.NoContent);
    }

問題是SaveChangesAsync方法因Db驗證錯誤“需要創建者字段”而崩潰。 從技術上講,我了解Creator是空的,因為我已經創建了新的Model實例,並且EF不知道我是要將Creator設置為null還是忽略它。 我需要以某種方式聲明我不想設置創建者。 我只想更新Name(或其他將來的標量屬性)。 那么,如何在不加載(包括)導航屬性數據的情況下正確地進行操作呢? 是否有一些常見的最佳實踐方法?

謝謝。

好的,一旦您扔掉了腳手架為您生成的廢話,也許您可​​以嘗試編寫一些有用的代碼並增加獲得可行解決方案的機會。

您可以從DTO / viewmodel =>擺脫Id屬性開始,該屬性來自其他地方(路徑段),因此它不應該成為更新視圖模型的一部分:

public class ModelDTO
{
    // The name is required => make sure that your DTO
    // respects this requirement as well before even
    // reaching your backend
    [Required]
    public string Name { get; set; }
}

太好了,現在您可以繼續為PUT控制器操作編寫代碼:

[HttpPut]
public async Task<IHttpActionResult> Put(int id, ModelDTO modelDTO)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    // Get the model that you are trying to update from the DB
    // using the id:
    var model = db.Models.Find(id);

    if (model == null)
    {
        // the id that was provided as parameter doesn't exist in the DB =>
        // we don't need to go any further, just let the client know
        // by returning 404
        return NotFound();
    }

    // set the properties that you want to update (only Name in your case)
    // of course when you have more complex models you might consider using
    // AutoMapper to take care of this part, but for the purposes of this
    // demonstration you don't need it:
    model.Name = modelDTO.Name; 

    // Now save the changes back to your database
    await db.SaveChangesAsync();

    return StatusCode(HttpStatusCode.NoContent);
}

好,所以這里要記住的是以下幾點:

當某個工具試圖在自己的位置編寫代碼時,開發人員應該做的第一件事就是簡單地丟棄該工具/代碼,然后開始工作(在開發人員的情況下,就是編寫代碼)。

我只想更新Name(或其他將來的標量屬性)。 那么,如何在不加載(包括)導航屬性數據的情況下正確地進行操作呢? 是否有一些常見的最佳實踐方法?

因此,您想更新一些特定字段,並在情況下更新Name字段

 //// find your model 
 var entity = db.Models.Find(id);
 entity.Name=modelDTO.Name; 
 /// set modified property
 db.Entry(entity).Property(c => c.Name).IsModified = true     
 await db.SaveChangesAsync();

暫無
暫無

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

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