我正在尋找一個簡單的Xml存儲庫(GetAll,Add,Update,Delete)示例。Xml存儲庫實現
大家都說「使用存儲庫模式是個好主意,因爲您可以交換數據存儲位置......」現在我需要將我的數據存儲在xml文件中,而不知道如何實現XML存儲庫。我搜遍了谷歌,找不到它。
如果可能,發送包含關係數據句柄的示例。就像在EF上保存產品實體一樣,並且所有產品相關實體也都保留下來。
我正在尋找一個簡單的Xml存儲庫(GetAll,Add,Update,Delete)示例。Xml存儲庫實現
大家都說「使用存儲庫模式是個好主意,因爲您可以交換數據存儲位置......」現在我需要將我的數據存儲在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;
}
}
}
}
然後我可以有diferent實體將懸掛持久單個數據方面行動過很多版本庫。
我已經爲我的應用程序做了測試,使用這個庫使用mocks並運行良好。
在我的IoC配置上,我必須設置XDocumentProvider的默認值。如果有必要,我們可以通過XDocumentProvider通過構造函數而不是這個靜態的「默認」屬性
你對我的實現有什麼看法?
感謝
一位同事和我實現了這樣一個XML存儲庫,它被稱爲XmlRepository :-)。
它內部使用linq創建XML,外部訪問類似於您如何使用linq for nhibernate。它使用linq完成對象,由於簡單的XML註釋接口,客戶端代碼中的用法非常簡單,易於理解。
當前版本(組裝)已經不支持內置的子類或1:n的關係,但目前的開發源代碼,您還可以找到上面的網站上,有他們兩個內置
。它還沒有完全準備好發佈 - 它可能有一些小錯誤,但是如果你喜歡,可以嘗試一下,獲取源代碼並改進它。它是開源的。
任何對開源項目(只讀源代碼)的評論,願望,建設性批評和補丁都會使我的同事(Golo Roden)和我感到高興,並使項目進入更好的狀態。
示例應用程序可用here(文本是德語)。
我只想讓它清楚,這是實現了一個很久以前和現在有更好的方法來做到這一點,就像使用LINQ to XML。 今天回顧這個答案,我發現我現在可以做得更好。如果有一天我需要它,我會執行並在這裏發佈。感謝您的支持 – 2013-01-28 22:33:56