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