Reputation: 6742
I want to create a data access layer, supporting CRUD methods, with an underlying storage of XML files.
I'm new to XML, and I'm not quite sure how to work with XmlDocument
, XDocument
, XmlSerializer
etc..
Here's my basic idea for a data access class:
public class EmployeesDao
{
private const string FILE_NAME = "file.xml";
//an XDocument which contains all the employees records
private XDocument m_XDocument;
private XmlSerializer m_XmlSerializer;
public TestCasesDao()
{
//is this correct?
m_XDocument = XDocument.Load(@"c:\" + FILE_NAME);
m_XmlSerializer = new XmlSerializer(typeof(EmployeeDTO));
}
public void Save(IEmployee employee)
{
var dto = new EmployeeDTO(employee);
//TODO: serialize the DTO, add it to the XDocument, and save to file
}
public IEmployee GetEmployee(string name)
{
//TODO: retrieve an EmployeeDTO from my XDocument
return employeeDto.Convert(); //return an IEmployee
}
//TODO: update and delete methods...
}
Any ideas as to how to fill in the missing gaps?
Upvotes: 3
Views: 3370
Reputation: 757
For Serialization you can use Generic methods
public static class GenericSerializer
{
public static string Serialize<T>(ICollection<T> listToSerialize)
{
MemoryStream stream = new MemoryStream();
XmlSerializer xmlSerializer;
try
{
xmlSerializer = new XmlSerializer(typeof(List<T>));
xmlSerializer.Serialize(stream, listToSerialize);
return Encoding.UTF8.GetString(stream.ToArray());
}
finally
{
stream.Close();
}
}
public static string Serialize<T>(T objectToSerialize)
{
MemoryStream stream = new MemoryStream();
XmlSerializer xmlSerializer;
try
{
xmlSerializer = new XmlSerializer(typeof(T));
xmlSerializer.Serialize(stream, objectToSerialize);
return Encoding.UTF8.GetString(stream.ToArray());
}
finally
{
stream.Close();
}
}
public static T Deserialize<T>(string xmlDataToeSerialize)
{
XmlSerializer xmlDeSerializer = new XmlSerializer(typeof(T));
StringReader stringReader = new StringReader(xmlDataToeSerialize);
return (T)xmlDeSerializer.Deserialize(stringReader);
}
}
For Update and Delete You can Retrieve the collection or object from file and edit and overwrite the existing one or you can use XPath expression for directly edit the XML
XML/0340_XPath.htm">http://www.java2s.com/Tutorial/CSharp/0540_XML/0340_XPath.htm
Upvotes: 0
Reputation: 51224
It really depends what your needs are. Using XML for a DAL only makes sense for a small project, and even in this case SQLite might be a better solution. The only "benefit" in XML is that it is a textual, human readable format, but in that sense it serves better as an export file, than an actual DAL technology. The problem with any "hand made" single file DB system is that you need to save the entire file each time you make a change (if you don't opt for memory mapped files, which could be an overkill depending on your needs).
For every insert or update operation, you will need a reader and a writer, in order to copy all records to a new file. Depending on your file size, an option might be to keep the records in memory during your app lifetime, and flush them to disk every once in a while. It would be a statically available list (with concurrency in mind), but it only makes sense if the database is relatively small.
Your biggest concern might be consistency and transactional integrity. If you have two processes using the same XML file simultaneously, it will be hard to synchronize access. Additionally, app crash or a power failure could leave your data corrupted, which means you should also think about some kind of a journaling system. SQLite, for example, as simple as it may seem on first glance, is ACID, and dedicates a great deal of effort to achive this (if you have time, check this lengthy article to get an idea). Implementing this from scratch is a real overkill.
So, to summarize, your options are:
You only have a single process using a single file.
a. Database is small: keep it in memory, lock all operations, and flush it regularly. Relatively simple.
b. Database is large:
use a reader/writer combination to copy the entire file on each operation. Very simple, but slower.
keep a queue of commands and flush them in batches. Faster, adds some transactional support, but complicated.
Another process can access the file.
a. implement a journaling mechanism to prevent simultaneous access.
b. create a separate service which will handle all transactions by itself.
In any case, you might need to keep a transactional log file and use it to make sure data is consistent between accesses. Your app should be able to recover from failures by itself. My opinion is that SQLite is probably the way to go: combined with an ORM solution like NHibernate, it's really simple and safe to use.
Upvotes: 4