LINQ查询返回DataTable类型[轉]與将DataTable序列化为Json格式【轉】
(原文地址:http://xuzhihong1987.blog.163.com/blog/static/26731587201101853740294/)
LINQ查询返回DataTable类型
在使用LINQ查询的时候,一般我们会返回List<T>或IList<T>类型,如下所示:
例1:
public List<TSample> GetList()
{
using (BPDataContext db = newBPDataContext(TCTC_ConnectionStrings.connStr))
{
var q = from p in db.TSample
select p;
return q.ToList();
}
}
例1实现的是一个最简单的列表查询,返回的是List<TSample>类型,本身没有任何问题!但是如果现在希望查询TSample表中的指定几列,代码应该是:
var q = from p in db.TSample
select new
{
p.FID,
p.FName
};
return q.ToList();
现在问题是返回类型该写什么呢?new{p.FID,p.FName}已经不是TSample类型了,又不支持返回值为List<T>的!
可能的解决方案是:
方法一:
先扩展一个类SampleEx
public class SampleEx
{
public Guid FID
{
get;
set;
}
public string FName
{
get;
set;
}
}
然后返回List<SampleEx>类型
public List<SampleEx> GetList()
{
using (BPDataContext db = newBPDataContext(TCTC_ConnectionStrings.connStr))
{
var q = from p in db.TSample
select new SampleEx()
{
FID = p.FID,
FName = p.FName
};
return q.ToList();
}
}
这样就达到了我们想要的目标。
问题是解决了,但是再仔细想想这样的解决方案似乎可行性不强。因为在实际开发中我们经常查询两个表join查询,那么重新组合的字段就比较多了,要每个都去扩展单独的类,工作量太大!有些人可能会想到用试图,然后dbml会自动帮我们生成类,但是这个工作量也应该不小,天天建试图,要频繁跟新dbml文件的方式不怎么合理!最期望的方式就是不用构造自定义类型,经过转换返回我们需要的类型!
下面通过一个方法来实现返回DataTable类型:
/// <summary>
/// LINQ返回DataTable类型
/// </summary>
/// <typeparam name="T"> </typeparam>
/// <param name="varlist"> </param>
/// <returns> </returns>
public static DataTable ToDataTable<T>(IEnumerable<T> varlist)
{
DataTable dtReturn = new DataTable();
// column names
PropertyInfo[] oProps = null;
if (varlist == null)
return dtReturn;
foreach (T rec in varlist)
{
if (oProps == null)
{
oProps = ((Type)rec.GetType()).GetProperties();
foreach (PropertyInfo pi in oProps)
{
Type colType = pi.PropertyType;
if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition()
== typeof(Nullable<>)))
{
colType = colType.GetGenericArguments()[0];
}
dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
}
}
DataRow dr = dtReturn.NewRow();
foreach (PropertyInfo pi in oProps)
{
dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value :pi.GetValue
(rec, null);
}
dtReturn.Rows.Add(dr);
}
return dtReturn;
}
如何使用?如下示例:
/// <summary>
/// 根据获取多个器具信息
/// </summary>
/// <param name="IDs"></param>
/// <returns></returns>
public DataTable GetByIDs(List<string> IDs)
{
using (BPDataContext db = newBPDataContext(TCTC_ConnectionStrings.connStr))
{
var p = (from c in db.TSample
where IDs.Contains(c.FID.ToString())
select new
{
c.FID,
c.FName,
c.FCode,
c.FType,
c.FProductUnit,
c.FDeviceNo
}).ToList();
return LinqToDataTable.ToDataTable(p);
}
}
到这里就达到了我们预期的方式!返回DataTable,那么对后面数据源直接绑定,或序列化为Json都非常方便了!
序列化DataTable为Json格式的方法直接用微软的JavaScriptSerializer.Serialize()方法是会有问题的,我们需要自己写方法序列化,
序列化代码详见:http://xuzhihong1987.blog.163.com/blog/static/26731587201101913722238/
将DataTable序列化为Json格式
很多时候我们希望将查询出的数据源格式(如:List<T>、DataTable等)转换为Json格式,便于前台的JS的处理,尤其是在使用Extjs框架的时候,JsonStore异步(Ajax)请求的数据格式就是Json,那么后台序列化的就显得非常重要!
当然序列化很简单,因为微软已经提供了序列化的方法,在引用命名空间(using System.Web.Script.Serialization;)后,即可使用内置的JavaScriptSerializer. Serialize()方法,使用方式如下:
JavaScriptSerializer jss = new JavaScriptSerializer();
string strJson = jss.Serialize(t); //T t为泛型
一般类型都能顺利序列化,但是如果此时传入的类型T为DataTable,那么就会发生异常了,出现”序列化类型为“System.Reflection.Module”的对象时检测到循环引用。”的错误提示.

究其原因,猜测可能是DataTable的成员DataRow的Table属性又引用了DataTable本身,真正原因我没去分析。下面提供一种解决方式:
/*
* Copyright: Copyright: ?2010 Twilight软件开发工作室
* Author: xuzhihong
* Create date: 2010-3-24
* Description: 将DataTable转换JSON对象
*
*/
public class ConventDataTableToJson
{
/// <summary>
/// 序列化方法(带分页)
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
public static string Serialize(DataTable dt)
{
List<Dictionary<string, object>> list = newList<Dictionary<string, object>>();
foreach (DataRow dr in dt.Rows)
{
Dictionary<string, object> result = new Dictionary<string,object>();
foreach (DataColumn dc in dt.Columns)
{
result.Add(dc.ColumnName, dr[dc].ToString());
}
list.Add(result);
}
int count = 0;
try
{
count = Convert.ToInt32(dt.TableName);
}
catch (System.Exception ex)
{
count = dt.Rows.Count;
}
string strReturn = "";
if (count == 0)
{
strReturn = "{\"totalCount\":0,\"data\":[]}";
}
else
{
strReturn = ConventToJson(list, count);
}
return strReturn;
}
/// <summary>
/// 转换为JSON对象
/// </summary>
/// <returns></returns>
public static string ConventToJson<T>(List<T> list, int count)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
string strJson = serializer.Serialize(list);
strJson = strJson.Substring(1);
strJson = strJson.Insert(0, "{totalCount:" + count + ",data:[");
strJson += "}";
return strJson;
}
/// <summary>
/// 不需要分页
/// </summary>
/// <param name="dt"></param>
/// <param name="flag">false</param>
/// <returns></returns>
public static string Serialize(DataTable dt,bool flag)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
List<Dictionary<string, object>> list = newList<Dictionary<string, object>>();
foreach (DataRow dr in dt.Rows)
{
Dictionary<string, object> result = new Dictionary<string,object>();
foreach (DataColumn dc in dt.Columns)
{
result.Add(dc.ColumnName, dr[dc].ToString());
}
list.Add(result);
}
return serializer.Serialize(list); ;
}
}
原理非常简单,主要思想就是利用Dictionary<string, object>字典,将DataRow属性名/值存储在List<Dictionary<string, object>>中,这样List<T>是能被正常序列化的。
说明:在带分页的序列化方法,我做了一个格式设置,主要是为了序列化为Extjs的JsonStore要求的格式,序列化的Json字符串如下:(下面的字符串只有一条记录)
{totalCount:1,data:[{"FID":"71e78220-8074-4f17-9f7b-c2413bf0ac4e","FTaskID":"b4f42e8e-a457-424c-888c-b874128ffb57","FTaskCode":"20110119-01","FTestItemID":"9a8c3c7a-f8c2-41f0-a279-4d50575f5f89","FTestItemName":"盖总成分离指安装高度及分离指端面跳动量测定","FAssignTag":"0","FTestCompleteTag":"0","FType":"1","FReTestTag":"1","FReTestFromTag":"1","FHasOriginalFile":"0","FInSampleNumber":"","FSerialNumber":"","FTestRemark":"","FReceiver":"","FReceiveTime":"","FEndTag":"1","FSampleModel":"234","FIsUrgent":"0","FSampleName":"","RowNumber":"1"}]}
其中:totalCount和dat对应JS的totalProperty和root配置项。
var store = new Ext.data.JsonStore({
proxy: new Ext.data.HttpProxy({ url: Vars.Url}),
idProperty: 'FID',
root: 'data',
totalProperty: 'totalCount',
fields: ['FID', 'FCode', 'FDuName', 'FSampleName'],
baseParams: { sign: 'GetByCondition', start: 0, limit: Vars.PageSize, condition: Ext.encode(Vars.Condition) }
});
飞天心宏 2011-01-19
LINQ查询返回DataTable类型[轉]與将DataTable序列化为Json格式【轉】的更多相关文章
- LINQ查询返回DataTable类型
个人感觉Linq实用灵活性很大,参考一篇大牛的文章LINQ查询返回DataTable类型 http://xuzhihong1987.blog.163.com/blog/static/267315872 ...
- 转:LINQ查询返回DataTable类型
动态绑定ReportViewer虽然之前实现过,但现在弄起来还是有点晕,主要是过去没有使用Linq,数据的操作经常用到DataTable,可以直接拿来使用,现在用Linq更方便,也懒得再用之前的数据库 ...
- .NET LINQ查询操作中的类型关系
LINQ 查询操作中的类型关系 若要有效编写查询,您应该了解完整的查询操作中的变量类型是如何全部彼此关联的. 如果您了解这些关系,就能够更容易地理解文档中的 LINQ 示例和代码示例. 另外 ...
- Hibernate应用SQL查询返回实体类型
Hibernate应用SQL查询返回实体类型 Hibernate使用SQL查询返回实体类型 以前,使用SQL查询,结果放在 RS 结果集中,还要去转换影射到Java类中.Hibernate中,可以自动 ...
- 使用DataContractJsonSerializer类将类型实例序列化为JSON字符串和反序列化为实例对象 分类: JSON 前端 2014-11-10 10:20 97人阅读 评论(1) 收藏
一.JSON简介 JSON(JavaScript Object Notation,JavaScript对象表示法)是一种轻量级的数据交换格式. JSON是"名值对"的集合.结构由大 ...
- 把Linq查询返回的var类型的数据 转换为DataTable EF连接查询
问题:我要获得一个角色下对应的所有用户,需要两表连接查询,虽然返回的只有用户数据,但是我想到若是返回的不只是用户数据,而还要加上角色信息,那么我返回什么类型呢,返回var吗,这样不行. 于是我网上找找 ...
- C#3.0新增功能09 LINQ 基础06 LINQ 查询操作中的类型关系
连载目录 [已更新最新开发文章,点击查看详细] 若要有效编写查询,应了解完整的查询操作中的变量类型是如何全部彼此关联的. 如果了解这些关系,就能够更容易地理解文档中的 LINQ 示例和代码示例. ...
- HQL查询——查询返回对象类型分析
关于HQL查询,我们可以结合hibernate的API文档,重点围绕org.hibernate.Query接口,分析其方法,此接口的实例对象是通过通过session.对象的creatQuery(Str ...
- mybatis group by查询返回map类型
故事的发生是这样的. . . . . . . 一天 我发现我们的页面显示了这样的汇总统计数据,看起来体验还不错哦-- 然后,我发现代码是这样滴:分开每个状态分别去查询数量. 额e,可是为嘛不使用简单便 ...
随机推荐
- vim 使用、设置笔记
一.设置.vimrc( windows下通常为_vimrc) 1.设置vim中tab的缩进 set ts=4 (注:ts是tabstop的缩写,设TAB宽4个空格) set expandtab (注 ...
- https证书自签
https http over ssl = https 443/tcp ssl: v3 tls: ...
- Mysql数据库的打开和关闭
Mysql数据库的打开和关闭: 选择计算机(win7)-右键管理 在新窗口选择--服务 5 找到mysql,然后右键-启动(停止)
- HDU acm1028 整数划分 递归问题(递推)
我们用递归+记忆化的方法来解决普通整数划分问题:定义 f(n,m)为将整数n划分为一系列整数之和,其中加数 最大不超过m. 得到下面的递推关系式: 当n==1 || m==1 只有一种划分,即 1 或 ...
- HDU 1143 Tri Tiling 递归问题
将一个3*n的矩形用1*2的矩形填充,n为奇数时一定不能被填满,n*3%2==1 接下来处理这个问题我们要从简单的情况开始考虑,所谓递归就是要能将问题的规模不断减小,通过小问题的解决最后将复杂问题解决 ...
- [转]Eclipse创建Maven项目
构建Maven项目的完整过程--普通web项目(Eclipse) 进行以下步骤的前提是你已经安装好本地maven库和eclipse中的maven插件了(有的eclipse中已经集成了maven插件) ...
- ubuntu_ root change to user
(1)从user用户切换到root用户 不管是用图形模式登录Ubuntu,还是命令行模式登录,我们会发现缺省的用户是user 但是当我们需要执行一些具有root权限的操作(如修还系统文件)时,经常需要 ...
- 【Linux学习】Linux文件系统6—文件目录权限设置
Linux文件系统6-文件目录权限设置 1. chmod操作权限设置 chomd是用来改变文件或目录权限的命令,但只有文件的属主和超级权限用户root才有这种权限.通过chmod来改变文件 ...
- TypeScript完全解读(26课时)_3.TypeScript完全解读-Symbol
ts中symbol的支持是按照es6的标准来的,只要我们学会es6中的symbol,就可以直接在ts中使用了 创建symbol 在example文件夹下新建symbol.ts 然后在根目录的index ...
- DOM学习笔记(三)DOM元素的访问、修改与事件
访问 HTML 元素等同于访问节点,使用的是document对象下的数个getElement方法,然后再对返回的元素(或元素列表)进行具体内容的访问和修改,或者响应对应的事件是操作 一些 DOM 对象 ...