簡體   English   中英

如何在以后保存對 EF Core 跟蹤實體的更改?

[英]How to save changes to EF Core tracked entity at a later date?

下午,

我正在嘗試使用 EF Core 來修改實體以及相關子項。 扭曲是我試圖通過中間的“批准”步驟來做到這一點。

目前,我正在從數據庫中加載實體,讓用戶對其屬性和關系進行更改,但通常在表單提交時使用Context.SaveChanges() ,我將實體序列化為 JSON。 它當前存儲在文件中,但稍后將存儲在 db 列中。

稍后,實體將在 EF 上下文中再次從數據庫加載並進行跟蹤,並從文件中反序列化更新的版本。 我希望能夠簡單地將更新的實體 map 到從上下文加載的實體上( Entity = UpdatedEntity ),並向批准更新的人提供更改內容的列表,但這當然不起作用:EF 沒有因為整個 object 已經改變,所以不考慮有任何改變。

它可以更改Entity的屬性: Entity.PropA = "test"但不會將整個 object 映射到具有匹配主鍵的另一個。 通過相關實體的大型網絡遞歸地從上下文將所有屬性從UpdatedEntity映射到Entity會很麻煩,而且我認為容易出錯。

有沒有辦法將 map 一個完整的實體轉換為一個被跟蹤的實體,以及 EF Core 中的所有相關子項?

我的其他想法包括序列化上下文的 ChangeTracker 並重新應用它,但我認為不太可能起作用,並且會將更新的值與表單提交時存在的值進行比較,而不是在批准時的值。

總是這樣……撓頭幾個小時,但在發布問題后幾分鍾就解決了:

將更新的 object 重新分配給從上下文加載的 object 不起作用,但在基礎EntityEntry上設置值可以。 下面使用“聯系人”作為我的實體類型的完整示例。

// Value loaded from JSON file elsewhere.
Contact UpdatedEntity;

// Example from Blazor component, hence the factory
DbContext Context = DbFactory.CreateDbContext(); 

// Load the entity from db to context
Contact CurrentEntity = Context.Contacts.Where(c => c.ID == UpdatedEntity.ID);

// Create underlying EntityEntry for the loaded entity
EntityEntry<Contact> ee = Context.Entry(CurrentEntity);

// Update the values
ee.CurrentValues.SetValues(UpdatedEntity);

EF Core 現在可以正確跟蹤當前實體(在 DB 中)與從 JSON 文件加載的更新值之間的變化。


編輯:

這並不像我想象的那么好,因為沒有跟蹤任何子實體。

使用這個...

        Context.ChangeTracker.TrackGraph(ContactChanges.UpdatedContact, e =>
        {
            if (e.Entry.IsKeySet)
            {
                e.Entry.State = EntityState.Unchanged;
            }
            else
            {
                e.Entry.State = EntityState.Added;
            }
        });

...確實讓我跟蹤孩子,但當然所有數據看起來都已更新。

仍然沒有找到好的解決方案。

編輯@freeAll

聯系人是從數據庫中加載的

Contact = Context.Contacts
  .Where(c => c.Code == ContactCode)
  .Include(contact => contact.FormerNames
    .OrderBy(formerName => formerName.Sequence)
  )
  .Include(contact => contact.TitleNavigation)
  .Include(contact => contact.MaritalStatusNavigation)
  .First();

然后以 Blazor 形式編輯聯系人。 這包括聯系人上的任何字段,還包括相關實體,例如前姓名,包括這些相關實體的添加和刪除。

然后將這些更改序列化為 JSON 文件,如下所示:

ContactChanges changes = new ContactChanges() {
  UpdatedContact = Contact,
  ChangeRequestedAt = DateTime.UtcNow
};

string jsonString = JsonConvert.SerializeObject(
  changes,
  new JsonSerializerSettings() {
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
  });

string filePath = Path.Combine(
  Environment.ContentRootPath,
  "wwwroot",
  "contact_changes",
  $"{DateTime.UtcNow.ToString("yyyy-MM-dd--HH-mm-ss")}.json"
);

File.WriteAllText(filePath, jsonString);

稍后,該文件被另一個用戶加載和反序列化:

string jsonString = System.IO.File.ReadAllText(filePath);
ContactChanges change = JsonConvert.DeserializeObject<ContactChanges>(jsonString);

此時,我希望再次從數據庫中加載聯系人(與上面的查詢相同),然后只需 map 將更新的聯系人數據反序列化到新加載/跟蹤的聯系人上:

Contact = ContactChanges.UpdatedContact;

但是,它只跟蹤對根聯系人所做的更改,而不是所有相關實體(如FormerName)。

只需將反序列化的數據加載到“ChangeTracker.TrackGraph”中,而無需先加載當前存在於數據庫中的聯系人,就可以將所有正確的更改加載到 EF 中,但它們都顯示為已修改,因為 EF 沒有可比較的內容。 理想情況下,我想向批准此數據更改的用戶展示他們將進行哪些具體更改,而不僅僅是“這是將替換舊數據的新數據,我不知道有什么不同”。

在過去一周考慮了這一點之后,我可能會嘗試序列化對 JSON 文件所做的初始更改,而不是更新后的 state(有點像ChangeTracker.DebugView ),然后在需要批准時將應用於最近加載的聯系人數據。 我可能會被相關實體(特別是刪除)所吸引,但目前,這似乎是唯一可行的選擇。

如果您有任何意見或替代想法,我將不勝感激!

謝謝,傑米。

暫無
暫無

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

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