LINQ非常牛逼,操作数据库和集合对象非常方便,已经得到了非常广泛的应用。好处我不多说了。今天来给大家看看LINQ对XML的增删改查操作,并且封装为DAL类,方便在多层结构的应用程序中使用。以我网站的友情链接模块为例:

XML文件的结构如下:



  
    1
    XNA Develop
    http://www.xnadevelop.com/
    1
  
  
    2
    BlogNT 开源.NET博客
    http://www.blognt.com/
    2
  

 和以往写ORM一样,我们首先要把对数据的描述抽象为model:

public sealed class FriendLink
{
    private int _id;
    private string _title;
    private string _url;
    private int _orderId;

    public int Id
    {
        get { return _id; }
        set { _id = value; }
    }

    public string Title
    {
        get { return _title; }
        set { _title = value; }
    }

    public string Url
    {
        get { return _url; }
        set { _url = value; }
    }

    public int OrderId
    {
        get { return _orderId; }
        set { _orderId = value; }
    }
}

接下来我们就可以用LINQ 写DAL了。

注意先要using这些命名空间:

using System.Linq;
using System.Xml;
using System.Xml.Linq;

下面代码中的_xmlPath局部变量是你XML文件的虚拟路径。

Add(新增一条记录):

public bool Add(GeekStudio.ORM.Model.FriendLink model)
{
    try
    {
        int id = GetNextId();
        string path = HttpContext.Current.Server.MapPath(_xmlPath);

        XDocument xDoc = XDocument.Load(path);
        xDoc.Element(rootName).Add(
            new XElement("FriendLink", new XElement("Id", id),
                                       new XElement("Title", model.Title),
                                       new XElement("Url", model.Url),
                                       new XElement("OrderId", model.OrderId)
                        ));
        xDoc.Save(path);
        return true;
    }
    catch
    {
        return false;
    }
}

GetModel(查询:根据Id获取一条记录(一个Model))

public GeekStudio.ORM.Model.FriendLink GetModel(int Id)
{
    string path = HttpContext.Current.Server.MapPath(_xmlPath);
    XDocument xDoc = XDocument.Load(path);
    var q = from fdlink in xDoc.Descendants("FriendLink")
            where fdlink.Element("Id").Value == Id.ToString()
            select new ORM.Model.FriendLink()
            {
                Id = Convert.ToInt32(fdlink.Element("Id").Value),
                Title = fdlink.Element("Title").Value,
                Url = fdlink.Element("Url").Value,
                OrderId = Convert.ToInt32(fdlink.Element("OrderId").Value)
            };
    return q.ToList()[0];
}

如果要返回一个Model List集合,只要把写成return q.ToList()就可以了。

Delete(删除一条记录)

public bool Delete(int Id)
{
    try
    {
        string path = HttpContext.Current.Server.MapPath(_xmlPath);
        XDocument xDoc = XDocument.Load(path);
        (from fdlink in xDoc.Descendants("FriendLink")
         where fdlink.Element("Id").Value == Id.ToString()
         select fdlink).Remove();
        xDoc.Save(path);
        return true;
    }
    catch
    {
        return false;
    }
}

Update(更新一条记录)

public bool Update(GeekStudio.ORM.Model.FriendLink model)
{
    try
    {
        string path = HttpContext.Current.Server.MapPath(_xmlPath);

        XDocument xDoc = XDocument.Load(path);
        var q = from fdlink in xDoc.Descendants("FriendLink")
                where fdlink.Element("Id").Value == model.Id.ToString()
                select fdlink;
        foreach (XElement xe in q)
        {
            xe.SetElementValue("Title", model.Title);
            xe.SetElementValue("Url", model.Url);
            xe.SetElementValue("OrderId", model.OrderId);
        }
        xDoc.Save(path);
        return true;
    }
    catch
    {
        return false;
    }
}

至此,我们已经写好了CRUD的4个方法。大家可以根据自己需要做调整。

附:生成下一个Id的方法(寻找最大的Id然后+1)

private static int GetNextId()
{
    string path = HttpContext.Current.Server.MapPath(_xmlPath);
    try
    {
        XDocument xDoc = XDocument.Load(path);
        var q = (from fdlink in xDoc.Descendants("FriendLink")
                 select fdlink.Element("Id").Value).Max();
        int i = int.Parse(q);
        return i + 1;
    }
    catch
    {
        return 0;
    }
}

提示:这个方法是有bug的。文末公布bug。

不过XML做数据库还是无法和传统的关系型数据库做比较,毕竟思想不一样。比如这个方法。我们知道,通过最大ID+1生成的新Id是可笑的。我们的本意是Id为IDENTITY列。但如果让数据库做,这个Id就不会是最大Id+1了。比如你有一坨记录,Id为1,2,3,4。你把4删了,再增加一条记录,数据库绝对不会把新记录的Id写成4。而是从5开始的。

另外,XML也有很多硬伤,无法和数据库相比。本文只是演示如何用LINQ对XML进行增删改查操作,并不是建议大家用XML做数据库。至于用什么来存数据,这是一个“适合和不适合”的命题,而不是一个“对与错”的命题~。

刚才提到的bug其实是这样的:

select Convert.ToInt32(fdlink.Element("Id").Value)).Max();

恍然大悟吧?:D