[英]Partially Modifying an XML serialized document
我有一個XML文檔,實際上有幾個,可以通過前端UI進行編輯。 我發現了這種方法的問題(除了它使用xml文件而不是數據庫的事實以外,但是我現在無法更改它)。
如果一個用戶進行更改而另一用戶正在進行更改,則第二個用戶的更改將覆蓋第一個用戶的更改。
我需要能夠從xml文件中請求對象,進行更改,然后將更改提交回xml文件,而無需重寫整個文件。 我已經在這里發布了整個xml訪問類(它是在stackoverflow的大力幫助下形成的!)
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
namespace Repositories
{
/// <summary>
/// A file base repository represents a data backing that is stored in an .xml file.
/// </summary>
public partial class Repository<T> : IRepository
{
/// <summary>
/// Default constructor for a file repository
/// </summary>
public Repository() { }
/// <summary>
/// Initialize a basic repository with a filename. This will have to be passed from a context to be mapped.
/// </summary>
/// <param name="filename"></param>
public Repository(string filename)
{
FileName = filename;
}
/// <summary>
/// Discovers a single item from this repository.
/// </summary>
/// <typeparam name="TItem">The type of item to recover.</typeparam>
/// <typeparam name="TCollection">The collection the item belongs to.</typeparam>
/// <param name="expression"></param>
/// <returns></returns>
public TItem Single<TItem, TCollection>(Predicate<TItem> expression)
where TCollection : IDisposable, IEnumerable<TItem>
{
using (var list = List<TCollection>())
{
return list.Single(i => expression(i));
}
}
/// <summary>
/// Discovers a collection from the repository,
/// </summary>
/// <typeparam name="TCollection"></typeparam>
/// <returns></returns>
public TCollection List<TCollection>()
where TCollection : IDisposable
{
using (var list = System.Xml.Serializer.Deserialize<TCollection>(FileName))
{
return (TCollection)list;
}
}
/// <summary>
/// Discovers a single item from this repository.
/// </summary>
/// <typeparam name="TItem">The type of item to recover.</typeparam>
/// <typeparam name="TCollection">The collection the item belongs to.</typeparam>
/// <param name="expression"></param>
/// <returns></returns>
public List<TItem> Select<TItem, TCollection>(Predicate<TItem> expression)
where TCollection : IDisposable, IEnumerable<TItem>
{
using (var list = List<TCollection>())
{
return list.Where( i => expression(i) ).ToList<TItem>();
}
}
/// <summary>
/// Attempts to save an entire collection.
/// </summary>
/// <typeparam name="TCollection"></typeparam>
/// <param name="collection"></param>
/// <returns></returns>
public Boolean Save<TCollection>(TCollection collection)
{
try
{
// load the collection into an xml reader and try to serialize it.
System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();
xDoc.LoadXml(System.Xml.Serializer.Serialize<TCollection>(collection));
// attempt to flush the file
xDoc.Save(FileName);
// assume success
return true;
}
catch
{
return false;
}
}
internal string FileName { get; private set; }
}
public interface IRepository
{
TItem Single<TItem, TCollection>(Predicate<TItem> expression) where TCollection : IDisposable, IEnumerable<TItem>;
TCollection List<TCollection>() where TCollection : IDisposable;
List<TItem> Select<TItem, TCollection>(Predicate<TItem> expression) where TCollection : IDisposable, IEnumerable<TItem>;
Boolean Save<TCollection>(TCollection collection);
}
}
Xml不是固定寬度的記錄格式。 在不重寫內部文件的情況下很難(請閱讀:不要打擾)。 在xml的大多數合理用例中,這都是可以預期的。 如果這是一個問題,請考慮使用另一種存儲機制(很快就會想到數據庫),並在需要時簡單地導入/導出xml。
我認為您正在學習為什么要使用數據庫。
您不能同時有多個線程在磁盤上寫入相同的XML文檔。 最好的辦法是進行一些設置,在其中將更改提交到某些中央服務,該服務將維護磁盤文檔的內存中副本。 它將每個更改更新到內存中,然后將其刷新到磁盤。 由於這將是此服務的中心服務,因此它可以序列化更新請求,從而確保文檔一致。
我想它也應該將生成的文檔提供給客戶。
我不認為有一個簡單的解決方案,因為有很多問題:您不能在不重寫整個文件的情況下更新XML文件,但與此無關,如果有多個用戶訪問您的數據,則您必須關心資源鎖定與此同時。 這個問題沒有簡單的解決方案!
您發布的類對我來說也很奇怪:為什么要序列化為XmlDocument之后再將其寫入光盤? 為什么不立即序列化到光盤? 捕獲異常而忽略它們是非常糟糕的風格!
據我所知,您有2種方法。 一種是實施一種鎖定機制,以防止一個以上的人一次修改任何給定的文件。 由於您正在詢問如何允許他們同時進行更改,因此我假設您無法執行此操作。
另一種方式是丑陋的,真正丑陋的。 但它應該起作用。 基本上,將您的存儲庫變成單例(所有用戶請求中只有一個靜態引用),然后“編輯”內存中的文件。 設置每個更改后,將更改保存到磁盤。 由於您正在處理內存中信息的一個副本,因此一個用戶不會覆蓋另一個用戶。 (除非它們都更改了組件)
您必須實現鎖定才能起作用。 (您基本上會將每個請求視為一個線程,並在多線程環境中進行編程。
祝好運...
如果您對XML文檔格式有一定的靈活性,那么可以做一些事情。
一種可能性:
如果您的應用適合該應用,則可以通過自動保存並經常刷新本地副本來減少沖突。 如果要自動保存而無需用戶干預,只需確保您具有出色的撤消功能即可。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.