我正在寻找一个简单的Xml存储库(GetAll,Add,Update,Delete)示例.
每个人都说“使用存储库模式是个好主意,因为你可以交换你的数据存储位置……”现在我需要将我的数据存储在xml文件中,并且不知道如何实现XML存储库.我搜索了整个谷歌,无法找到它.
如果可能,请发送包含关系数据句柄的示例.就像在EF上保存产品实体一样,所有依赖于产品的实体也都是持久的.
那么,Petter解决方案很好.
原文链接:https://www.f2er.com/xml/292645.html只是为了分享我的实现,我将再次回答我的问题,我希望这对某人有用.请评价和评论.
public interface IRepository<T> { IEnumerable<T> GetAll(); IEnumerable<T> GetAll(object parentId); T GetByKey(object keyValue); void Insert(T entidade,bool autoPersist = true); void Update(T entidade,bool autoPersist = true); void Delete(T entidade,bool autoPersist = true); void Save(); }
和XML存储库的基类
public abstract class XmlRepositoryBase<T> : IRepository<T> { public virtual XElement ParentElement { get; protected set; } protected XName ElementName { get; private set; } protected abstract Func<XElement,T> Selector { get; } #endregion protected XmlRepositoryBase(XName elementName) { ElementName = elementName; // clears the "cached" ParentElement to allow hot file changes XDocumentProvider.Default.CurrentDocumentChanged += (sender,eventArgs) => ParentElement = null; } #region protected abstract void SetXElementValue(T model,XElement element); protected abstract XElement CreateXElement(T model); protected abstract object GetEntityId(T entidade); #region IRepository<T> public T GetByKey(object keyValue) { // I intend to remove this magic string "Id" return XDocumentProvider.Default.GetDocument().Descendants(ElementName) .Where(e => e.Attribute("Id").Value == keyValue.ToString()) .Select(Selector) .FirstOrDefault(); } public IEnumerable<T> GetAll() { return ParentElement.Elements(ElementName).Select(Selector); } public virtual IEnumerable<T> GetAll(object parentId) { throw new InvalidOperationException("This entity doesn't contains a parent."); } public virtual void Insert(T entity,bool autoPersist = true) { ParentElement.Add(CreateXElement(entity)); if (autoPersist) Save(); } public virtual void Update(T entity,bool autoPersist= true) { // I intend to remove this magic string "Id" SetXElementValue( entity,ParentElement.Elements().FirstOrDefault(a => a.Attribute("Id").Value == GetEntityId(entity).ToString() )); if (persistir) Save(); } public virtual void Delete(T entity,bool autoPersist = true) { ParentElement.Elements().FirstOrDefault(a => a.Attribute("Id").Value == GetEntityId(entity).ToString()).Remove(); if (autoPersist) Save(); } public virtual void Save() { XDocumentProvider.Default.Save(); } #endregion #endregion }
还有2个抽象类,一个是独立实体,另一个是子实体.为了避免每次都读取Xml文件,我做了一种缓存控制
public abstract class EntityXmlRepository<T> : XmlRepositoryBase<T> { #region cache control private XElement _parentElement; private XName xName; protected EntityXmlRepository(XName entityName) : base(entityName) { } public override XElement ParentElement { get { // returns in memory element or get it from file return _parentElement ?? ( _parentElement = GetParentElement() ); } protected set { _parentElement = value; } } /// <summary> /// Gets the parent element for this node type /// </summary> protected abstract XElement GetParentElement(); #endregion }
现在实现子类型
public abstract class ChildEntityXmlRepository<T> : XmlRepositoryBase<T> { private object _currentParentId; private object _lastParentId; private XElement _parentElement; public override XElement ParentElement { get { if (_parentElement == null) { _parentElement = GetParentElement(_currentParentId); _lastParentId = _currentParentId; } return _parentElement; } protected set { _parentElement = value; } } /// <summary> /// Defines wich parent entity is active /// when this property changes,the parent element field is nuled,forcing the parent element to be updated /// </summary> protected object CurrentParentId { get { return _currentParentId; } set { _currentParentId = value; if (value != _lastParentId) { _parentElement = null; } } } protected ChildEntityXmlRepository(XName entityName) : base(entityName){} protected abstract XElement GetParentElement(object parentId); protected abstract object GetParentId(T entity); public override IEnumerable<T> GetAll(object parentId) { CurrentParentId = parentId; return ParentElement.Elements(ElementName).Select(Selector); } public override void Insert(T entity,bool persistir = true) { CurrentParentId = GetParentId(entity); base.Insert(entity,persistir); } public override void Update(T entity,bool persistir = true) { CurrentParentId = GetParentId(entity); base.Update(entity,persistir); } public override void Delete(T entity,bool persistir = true) { CurrentParentId = GetParentId(entity); base.Delete(entity,persistir); } }
现在,一个真实世界的实施
public class RepositorioAgendamento : EntityXmlRepository<Agendamento>,IRepositorioAgendamento { protected override Func<XElement,Agendamento> Selector { get { return x => new Agendamento() { Id = x.Attribute("Id").GetGuid(),Descricao = x.Attribute("Descricao").Value,TipoAgendamento = x.Attribute("TipoAgendamento").GetByte(),Dias = x.Attribute("Dias").GetByte(),Data = x.Attribute("Data").GetDateTime(),Ativo = x.Attribute("Ativo").GetBoolean(),}; } } protected override XElement CreateXElement(Agendamento agendamento) { agendamento.Id = Guid.NewGuid(); return new XElement(ElementName,new XAttribute("Id",agendamento.Id),new XAttribute("Descricao",agendamento.Descricao),new XAttribute("TipoAgendamento",agendamento.TipoAgendamento),new XAttribute("Dias",agendamento.Dias),new XAttribute("Data",agendamento.Data),new XAttribute("Ativo",agendamento.Ativo),new XElement(XmlNames.GruposBackup),new XElement(XmlNames.Credenciais) ); } protected override void SetXElementValue(Agendamento modelo,XElement elemento) { elemento.Attribute("Descricao").SetValue(modelo.Descricao); elemento.Attribute("TipoAgendamento").SetValue(modelo.TipoAgendamento); elemento.Attribute("Dias").SetValue(modelo.Dias); elemento.Attribute("Data").SetValue(modelo.Data); elemento.Attribute("Ativo").SetValue(modelo.Ativo); } public RepositorioAgendamento() : base(XmlNames.Agendamento) { } protected override XElement GetParentElement() { return XDocumentProvider.Default.GetDocument().Elements(XmlNames.Agendamentos).First(); } protected override object GetEntityId(Agendamento entidade) { return entidade.Id; } public IEnumerable<Agendamento> ObterAtivos() { return ParentElement.Elements() .Where(e => e.Attribute("Ativo").GetBoolean()) .Select(Selector); } }
现在,XDocumentProvider.它的功能是抽象对xml文件的访问,并统一到所有存储库,XDocument是数据上下文.这可以命名为UnitOfWork吗?
public abstract class XDocumentProvider { // not thread safe yet private static bool pendingChanges; private bool _documentLoadedFromFile; FileSystemWatcher fileWatcher; public static XDocumentProvider Default; public event EventHandler CurrentDocumentChanged; private XDocument _loadedDocument; public string FileName { get; set; } protected XDocumentProvider() { fileWatcher = new FileSystemWatcher(); fileWatcher.NotifyFilter = NotifyFilters.LastWrite; fileWatcher.Changed += fileWatcher_Changed; } void fileWatcher_Changed(object sender,FileSystemEventArgs e) { if (_documentLoadedFromFile && !pendingChanges) { GetDocument(true); } } /// <summary> /// Returns an open XDocument or create a new document /// </summary> /// <returns></returns> public XDocument GetDocument(bool refresh = false) { if (refresh || _loadedDocument == null) { // we need to refactor it,but just to demonstrate how should work I will send this way ;P if (File.Exists(FileName)) { _loadedDocument = XDocument.Load(FileName); _documentLoadedFromFile = true; if (fileWatcher.Path != Environment.CurrentDirectory) { fileWatcher.Path = Environment.CurrentDirectory; fileWatcher.Filter = FileName; fileWatcher.EnableRaisingEvents = true; } } else { _loadedDocument = CreateNewDocument(); fileWatcher.EnableRaisingEvents = false; _documentLoadedFromFile = false; } if(CurrentDocumentChanged != null) CurrentDocumentChanged(this,EventArgs.Empty); } return _loadedDocument; } /// <summary> /// Creates a new XDocument with a determined schemma. /// </summary> public abstract XDocument CreateNewDocument(); public void Save() { if (_loadedDocument == null) throw new InvalidOperationException(); try { // tells the file watcher that he cannot raise the changed event,because his function is to capture external changes. pendingChanges = true; _loadedDocument.Save(FileName); } finally { pendingChanges = false; } } }
然后,我可以为不同的实体提供许多存储库,在单个数据上下文中添加挂起持久性操作.
我已经为我的应用程序进行了测试,该应用程序使用这个存储库使用模拟并运行良
在我的IoC配置中,我必须为XDocumentProvider设置Default.如有必要,我们可以通过构造函数而不是静态“Default”属性传递XDocumentProvider
您如何看待我的实施?
谢谢