Xml存储库实现

我正在寻找一个简单的Xml存储库(GetAll,Add,Update,Delete)示例.

每个人都说“使用存储库模式是个好主意,因为你可以交换你的数据存储位置……”现在我需要将我的数据存储在xml文件中,并且不知道如何实现XML存储库.我搜索了整个谷歌,无法找到它.

如果可能,请发送包含关系数据句柄的示例.就像在EF上保存产品实体一样,所有依赖于产品的实体也都是持久的.

那么,Petter解决方案很好.

只是为了分享我的实现,我将再次回答我的问题,我希望这对某人有用.请评价和评论.

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

您如何看待我的实施?

谢谢

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


php输出xml格式字符串
J2ME Mobile 3D入门教程系列文章之一
XML轻松学习手册
XML入门的常见问题(一)
XML入门的常见问题(三)
XML轻松学习手册(2)XML概念
xml文件介绍及使用
xml编程(一)-xml语法
XML文件结构和基本语法
第2章 包装类
XML入门的常见问题(二)
Java对象的强、软、弱和虚引用
JS解析XML文件和XML字符串详解
java中枚举的详细使用介绍
了解Xml格式
XML入门的常见问题(四)
深入SQLite多线程的使用总结详解
PlayFramework完整实现一个APP(一)
XML和YAML的使用方法
XML轻松学习总节篇