利用SQL2005的forxml以及反系列化去替代ORM?
ORM用多了就会发现越来越多的问题。。。。。最后就觉得ORM简直是鸡肋....(呵呵,别拿砖头砸我,个人觉得而已)
最后没办法了,发现SQL2005出来一个for xml 可以直接将查询生成xml返回,如果能把这个返回来的xml直接反系列化成实体,貌似很可爱,在测试了一段时间后决定把它用到项目中去。项目完成用到现在为止还没出现过严重问题,看来这个解决方案是可行的,不敢独享,贴出来大家一起讨论讨论。
一。在使用过程中,遇到过以下几个问题:
1、编写查询的存储过程是比较麻烦的(为此专门写了个windows小工具来辅助生成查询)
2、实体名不能随便改。。。。跟查询的存储过程有联系(这个就没办法了,反正实体名我不改就是了)
3、xml非法字符问题。(替换。。。)
4、xml中带有html字符的时候(cdata,然而怎么在数据库查询的是偶构建cdata字段的问题)
5、好像没再遇到什么问题了,至于有人说大量查询的时候会出现xml断层的问题也是比较容易解决的
二。至于效率问题的话,现在这个项目网站运行差不多一个月来有12000用户注册,不见有任何服务器CPU过高或者死机的情况(当然这跟数据库存储过程优化以及数据库索引有很大关系),算是比较满意。
三。详细解决方案
1、数据库方面
当然不能再用SELECT * FROM 什么的方法了。下面是一个简单的查询
a、返回数据集
SELECT
1 as Tag,
0 as Parent,
UserId as [Users!1!UserId!ELEMENT],--用户ID
UserEmail as [Users!1!UserEmail!cdata] --用户Email
FROM
[User]
FOR XML EXPLICIT,ROOT('ArrayOfUser')
b、返回单条数据
SELECT
1 as Tag,
0 as Parent,
UserId as [Users!1!UserId!ELEMENT],--用户ID
UserEmail as [Users!1!UserEmail!cdata] --用户Email (注意,这里使用cdata就可以把生成的xml文件UserEmail包含在cdata中)
FROM
[User] WHERE UserId = 1
FOR XML EXPLICIT
2、程序方面
呵,不像一些ORM框架一样要引入项目,生成配置文件这么痛苦~~换来的是要自己写sqlcommand,open sqlconnection等等,但是我个人认为这些东西自己写的话也有很多方法可以偷懒,呵呵在这里就不介绍这些东西了,反正创建一个SQLCOMMAND,给SQLCOMMAND提供相应的参数,然后SQLCOMMAND.ExecuteDataReader就好了。。。
a、当然你的有个User的实体,大概如下:
public class User
{
int userId = 0;
public int UserId
{
get{}
set{}
}
//略
}
b、然后你必须将上面的存储过程执行,并返回datareader
c、反序列化
d、将你执行后的datareader直接调用上面的方法
User user = Deserialize(reader,typeof(User));
或者
User[] user = Deserialize(reader,typeof(User[]));
======================================end===========================================
就是这么简单。。。。至于说那些什么反射啊之类的影响性能啊(个人觉得在.NET里面的性能就算再优化,还不如花多点时间去优化SQL查询语句以及SQL数据库索引)。。还是看具体的结果去检验吧
其它就待补~~~没时间再写了。。呵呵
最后没办法了,发现SQL2005出来一个for xml 可以直接将查询生成xml返回,如果能把这个返回来的xml直接反系列化成实体,貌似很可爱,在测试了一段时间后决定把它用到项目中去。项目完成用到现在为止还没出现过严重问题,看来这个解决方案是可行的,不敢独享,贴出来大家一起讨论讨论。
一。在使用过程中,遇到过以下几个问题:
1、编写查询的存储过程是比较麻烦的(为此专门写了个windows小工具来辅助生成查询)
2、实体名不能随便改。。。。跟查询的存储过程有联系(这个就没办法了,反正实体名我不改就是了)
3、xml非法字符问题。(替换。。。)
4、xml中带有html字符的时候(cdata,然而怎么在数据库查询的是偶构建cdata字段的问题)
5、好像没再遇到什么问题了,至于有人说大量查询的时候会出现xml断层的问题也是比较容易解决的
二。至于效率问题的话,现在这个项目网站运行差不多一个月来有12000用户注册,不见有任何服务器CPU过高或者死机的情况(当然这跟数据库存储过程优化以及数据库索引有很大关系),算是比较满意。
三。详细解决方案
1、数据库方面
当然不能再用SELECT * FROM 什么的方法了。下面是一个简单的查询
a、返回数据集
SELECT
1 as Tag,
0 as Parent,
UserId as [Users!1!UserId!ELEMENT],--用户ID
UserEmail as [Users!1!UserEmail!cdata] --用户Email
FROM
[User]
FOR XML EXPLICIT,ROOT('ArrayOfUser')
b、返回单条数据
SELECT
1 as Tag,
0 as Parent,
UserId as [Users!1!UserId!ELEMENT],--用户ID
UserEmail as [Users!1!UserEmail!cdata] --用户Email (注意,这里使用cdata就可以把生成的xml文件UserEmail包含在cdata中)
FROM
[User] WHERE UserId = 1
FOR XML EXPLICIT
2、程序方面
呵,不像一些ORM框架一样要引入项目,生成配置文件这么痛苦~~换来的是要自己写sqlcommand,open sqlconnection等等,但是我个人认为这些东西自己写的话也有很多方法可以偷懒,呵呵在这里就不介绍这些东西了,反正创建一个SQLCOMMAND,给SQLCOMMAND提供相应的参数,然后SQLCOMMAND.ExecuteDataReader就好了。。。
a、当然你的有个User的实体,大概如下:
public class User
{
int userId = 0;
public int UserId
{
get{}
set{}
}
//略
}
b、然后你必须将上面的存储过程执行,并返回datareader
c、反序列化
private static Regex reg = new Regex("[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]", RegexOptions.Compiled| RegexOptions .IgnoreCase | RegexOptions.Multiline);
/// <summary>
/// 反序列化对象
/// </summary>
/// <param name="xmlstr">源xml字符串</param>
/// <param name="objtype">要序列化后的类型</param>
/// <returns>结果</returns>
static public object Deserialize(string xmlstr, Type objtype)
{
if (string.IsNullOrEmpty(xmlstr))
return null;
object obj = null;
xmlstr = reg.Replace(xmlstr, "");
XmlSerializer serializer = new XmlSerializer(objtype);
try
{
obj = serializer.Deserialize(new StringReader(xmlstr));
}
catch {
xmlstr = xmlstr.Replace("&", "&");
obj = serializer.Deserialize(new StringReader(xmlstr));
}
return obj;
}
/// <summary>
/// 反序列化对象
/// </summary>
/// <param name="reader">从reader进行反序列化,序列化完毕后将在这里关闭</param>
/// <param name="objtype">要序列化后的类型</param>
/// <returns>结果</returns>
static public object Deserialize(System.Data.IDataReader reader, Type objtype)
{
return Deserialize(reader, objtype, true);
}
/// <summary>
/// 反序列化对象
/// </summary>
/// <param name="reader">从reader进行反序列化,序列化完毕后将在这里关闭</param>
/// <param name="objtype">要序列化后的类型</param>
/// <param name="isCloseReader">是否关闭IDataReader</param>
/// <returns>结果</returns>
static public object Deserialize(System.Data.IDataReader reader, Type objtype,bool isCloseReader)
{
StringBuilder sb = new StringBuilder();
while (reader.Read())
sb.Append(reader[0].ToString());
if(isCloseReader)
reader.Close();
try
{
return Deserialize(sb.ToString(), objtype);
}
catch (Exception ex)
{
throw;
}
}
/// <summary>
/// 反序列化对象
/// </summary>
/// <param name="xmlstr">源xml字符串</param>
/// <param name="objtype">要序列化后的类型</param>
/// <returns>结果</returns>
static public object Deserialize(string xmlstr, Type objtype)
{
if (string.IsNullOrEmpty(xmlstr))
return null;
object obj = null;
xmlstr = reg.Replace(xmlstr, "");
XmlSerializer serializer = new XmlSerializer(objtype);
try
{
obj = serializer.Deserialize(new StringReader(xmlstr));
}
catch {
xmlstr = xmlstr.Replace("&", "&");
obj = serializer.Deserialize(new StringReader(xmlstr));
}
return obj;
}
/// <summary>
/// 反序列化对象
/// </summary>
/// <param name="reader">从reader进行反序列化,序列化完毕后将在这里关闭</param>
/// <param name="objtype">要序列化后的类型</param>
/// <returns>结果</returns>
static public object Deserialize(System.Data.IDataReader reader, Type objtype)
{
return Deserialize(reader, objtype, true);
}
/// <summary>
/// 反序列化对象
/// </summary>
/// <param name="reader">从reader进行反序列化,序列化完毕后将在这里关闭</param>
/// <param name="objtype">要序列化后的类型</param>
/// <param name="isCloseReader">是否关闭IDataReader</param>
/// <returns>结果</returns>
static public object Deserialize(System.Data.IDataReader reader, Type objtype,bool isCloseReader)
{
StringBuilder sb = new StringBuilder();
while (reader.Read())
sb.Append(reader[0].ToString());
if(isCloseReader)
reader.Close();
try
{
return Deserialize(sb.ToString(), objtype);
}
catch (Exception ex)
{
throw;
}
}
d、将你执行后的datareader直接调用上面的方法
User user = Deserialize(reader,typeof(User));
或者
User[] user = Deserialize(reader,typeof(User[]));
======================================end===========================================
就是这么简单。。。。至于说那些什么反射啊之类的影响性能啊(个人觉得在.NET里面的性能就算再优化,还不如花多点时间去优化SQL查询语句以及SQL数据库索引)。。还是看具体的结果去检验吧
其它就待补~~~没时间再写了。。呵呵