2011-01-27 4 views
8

मैं एक साधारण एक्सएमएल रिपोजिटरी (GetAll, जोड़ें, अपडेट, हटाएं) उदाहरण की तलाश में हूं।एक्सएमएल रिपोजिटरी कार्यान्वयन

हर कोई कहता है "रिपोजिटरी पैटर्न का उपयोग करना एक अच्छा विचार है क्योंकि आप अपने डेटा स्टोर स्थान को स्वैप कर सकते हैं ..." अब मुझे अपने डेटा को एक्सएमएल फाइल पर स्टोर करने की आवश्यकता है और यह नहीं पता कि एक्सएमएल रिपोजिटरी को कैसे कार्यान्वित किया जाए। मैंने पूरे Google पर खोज की है और इसे नहीं मिला।

यदि संभव हो, तो संबंधपरक डेटा हैंडल युक्त एक उदाहरण भेजें। जैसे कि जब आप ईएफ पर उत्पाद इकाई को सहेजते हैं और सभी उत्पाद निर्भर संस्थाएं भी जारी रहती हैं।

उत्तर

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(); 
} 

और एक्सएमएल डेटा संग्रह स्थान

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 डेटा संदर्भ है। इसे यूनिटऑफवर्क नाम दिया जा सकता है?

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; 
     } 
    } 
} 

}

तब मैं लटकता हुआ एक भी डेटा संदर्भ में कार्रवाई की हठ जोड़ने विभिन्न संस्थाओं के लिए कई खजाने हो सकता है।

मैंने अपने आवेदन के लिए परीक्षण किए हैं जो इस भंडार का उपयोग मैक्स का उपयोग करके करते हैं और अच्छी तरह से काम करते हैं।

मेरे आईओसी कॉन्फ़िगरेशन पर मुझे XDocumentProvider के लिए डिफ़ॉल्ट सेट करना होगा। यदि आवश्यक हो, तो हम इस स्थिर "डिफ़ॉल्ट" संपत्ति के बजाय XDocumentProvider को कन्स्ट्रक्टर के माध्यम से पास कर सकते हैं

मेरे कार्यान्वयन के बारे में आप क्या सोचते हैं?

धन्यवाद

+2

मैं सिर्फ यह बताने के लिए यह स्पष्ट है कि इस कार्यान्वयन एक समय पहले बनाया गया था और आजकल वहाँ बेहतर तरीके यह करने के लिए, एक्सएमएल के लिए LINQ का उपयोग कर की तरह हैं चाहता हूँ। आज इस उत्तर की समीक्षा करते हुए, मुझे पता चला कि मैं इसे बेहतर बना सकता हूं। अगर किसी दिन मुझे इसकी ज़रूरत है, तो मैं यहां लागू और पोस्ट करूंगा। सहायता का शुक्रिया –

2

एक सहयोगी और मैंने बिल्कुल एक एक्सएमएल भंडार लागू किया, और इसे XmlRepository :-) कहा जाता है।

यह आंतरिक रूप से लिनक्स के साथ एक्सएमएल के साथ बनाया गया है और बाहरी पहुंच इस तरह है कि आप निचलेनेट के लिए linq का उपयोग कैसे करते हैं। यह ऑब्जेक्ट्स के लिए linq के साथ किया जाता है, क्लाइंट कोड में उपयोग सरल एक्सएमएल-टिप्पणी इंटरफेस की वजह से बहुत आसान, आसान और जल्दी समझ में आता है।

मौजूदा रिलीज (विधानसभा) कोई समर्थन उपवर्गों या 1 के लिए बनाया गया है:, एन संबंधों, लेकिन मौजूदा विकास स्रोत कोड है, जो आप ऊपर की साइट पर भी पा सकते हैं उन दोनों में बनाया गया है

यह रिलीज करने के लिए पूरी तरह से तैयार नहीं है - इसमें कुछ मामूली बग हो सकती हैं, लेकिन इसे आज़माएं, स्रोत कोड लें और इसे बेहतर बनाएं, अगर आपको पसंद है। यह खुला स्रोत है।

किसी भी टिप्पणी, इच्छाओं, रचनात्मक आलोचना, और खुले स्रोत के लिए पैच (पढ़ें: केवल स्रोत) परियोजना मेरे सहयोगी (गोलो रॉडेन) बनाती है और मैं खुश हूं और परियोजना को बेहतर स्थिति में लाता हूं।

एक उदाहरण एप्लिकेशन उपलब्ध है here (पाठ जर्मन में है)।

संबंधित मुद्दे