2011-01-27 2 views
8

저는 간단한 Xml 저장소 (GetAll, Add, Update, Delete) 예제를 찾고 있습니다.Xml 저장소 구현

누구나 "데이터 저장소 위치를 바꿀 수 있기 때문에 저장소 패턴을 사용하는 것이 좋습니다."이제 XML 데이터에 데이터를 저장하고 XML 저장소를 구현하는 방법을 알아야합니다. 나는 모든 곳에서 구글을 수색했고 그것을 찾을 수 없다.

가능한 경우 관계형 데이터 핸들이 포함 된 예제를 보냅니다. EF에 제품 엔티티를 저장하고 모든 제품 종속 엔티티도 유지되는 경우와 같습니다.

답변

8

글쎄, 페터 솔루션이 좋습니다.

내 구현을 공유하기 만하면 다시 질문에 답할 것이고, 누군가에게 유용 할 수 있기를 바랍니다. 제발, 평가 및 코멘트.

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 
} 

} 자식 엔티티

그리고이 개 더 추상 클래스, 하나의 독립 기관 및 기타의 기본 클래스입니다. 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"속성 대신 XDocumentProvider throught 생성자를 전달할 수 있습니다.

구현 방법에 대해 어떻게 생각합니까?

감사

난 그냥 분명이 구현은 시간 제출되었다 요즘 XML에 LINQ를 사용하는 것과 같이, 그것을 할 수있는 더 나은 방법이 있다는 것을 있도록 할
+2

. 오늘이 답변을 검토 한 결과 지금은 더 나아질 수 있다는 것을 알았습니다. 언젠가 필요하다면, 여기에서 구현하고 게시 할 것입니다. 도와 주셔서 감사합니다 –

2

동료와 정확히 같은 XML 저장소를 구현했으며 XmlRepository :-)이라고합니다.

내부적으로 XML에 linq이 내장되어 있으며 외부 액세스는 linq를 nhibernate에 사용하는 것과 비슷합니다. 객체에 대한 linq로 처리되었으므로 클라이언트 코드의 사용법은 간단한 XML 주석 인터페이스로 인해 매우 간단하고 쉽고 빠르게 이해할 수 있습니다.

현재 릴리스 (어셈블리) 서브 클래스 또는 1 내장은 지원이 없습니다 : N 관계,하지만 당신은 위의 사이트에서도 찾을 수있는 현재의 개발 소스 코드를, 둘 다 내장되어

.

완전히 공개 준비가되지 않았습니다. 약간의 사소한 버그가있을 수 있지만, 시도해보십시오. 원한다면 소스 코드를 개선하고 개선하십시오. 그것은 오픈 소스입니다.

공개 소스 (읽기 전용 소스) 프로젝트에 대한 모든 의견, 희망 사항, 건설적인 비판 및 패치로 인해 동료 (Golo Roden)와 나는 행복하게되고 더 나은 상태로 프로젝트를 가져올 수 있습니다.

예제 응용 프로그램은 here (텍스트는 독일어)입니다.

관련 문제