最近在将一个原来用ASP.NET2.0设计的网站迁移到NET3.5上,主要是要将数据访问从传统的数据库访问方式转换为LINQ技术。其间也遇到一些问题,这里是一些典型的问题。
我原来的项目是在NET2.0下用VS2005开发的,现在使用VS2008了。
1 web.config的问题
由于原来的系统是在NET2.0下用VS2005开发的,在web.config中的有大量对2.0的引用。如果用VS2008直接打开VS2005的网站工程,VS会把这个网站作为aps.net2.0的项目处理。LINQ这些3.5的新功能都不能使用。
解决方法:我用的是笨办法,直接用VS2008新建一个网站,然后把原来网站的web.config中的配置逐行拷贝到新站点的配置文件中。
2 页面上的数据源
这是引入LINQ最好的地方了。原本页面上诸多控件都是绑定到SQLDataSource上的。现在改为绑定到ObjectDataSource数据源上了。这样将页面逻辑和数据访问彻底分离了。我喜欢将ObjectDataSource数据源的返回结果都定义为List<T>类型的。
3 GridView控件的数据过滤
SQLDataSource返回的是DataSet,DataTable类型,这种类型可以支持GridView的过滤。程序中只要通过代码动态设置过滤条件,GridView会自动完成过滤。
原来的过滤代码大体如下
aspx文件:
<tr>
<td align="right">
产品类别:
</td>
<td>
<asp:DropDownList ID="DropDownListProductList" runat="server" DataSourceID="SqlDataSourceTypes"
DataTextField="ProductTypeName" DataValueField="ProductTypeID" Width="130px" AutoPostBack="True" OnSelectedIndexChanged="DropDownListProductList_SelectedIndexChanged">
</asp:DropDownList>
</td>
</tr>
<tr>
<td align="right">
产品代码:</td>
<td >
<asp:TextBox ID="TextBoxProductTypeCode" runat="server" Width="50px" ReadOnly="true"/>-<asp:TextBox ID="TextBoxProductCode" runat="server" Width="50px"/>
</td>
</tr>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:DBConnectionString %>"
SelectCommand="SELECT [ProductTypeName], [ProductTypeCode], [ProductTypeID] FROM [tbl_ProductType] WHERE len([ProductTypeCode])=2 ">
</asp:SqlDataSource>
<asp:SqlDataSource ID="SqlDataSourceTypes" runat="server" ConnectionString="<%$ ConnectionStrings:DBConnectionString %>"
SelectCommand="SELECT [ProductTypeName], [ProductTypeCode], [ProductTypeID] FROM [tbl_ProductType] WHERE len([ProductTypeCode])=4 "
>
</asp:SqlDataSource>
cs文件:
protected void DropDownListProductTopType_SelectedIndexChanged(object sender, EventArgs e)
{
if (-1 < DropDownListProductTopType.SelectedIndex)
{
this.SqlDataSourceTypes.FilterExpression = string.Format("[ProductTypeCode] LIKE '{0}%'", DropDownListProductTopType.SelectedValue.ToString().Trim());
this.DropDownListProductList.DataBind();
SetProductTypeCode();
}
}
GridView只能支持对DataSet,DataTable的过滤,不支持对List<T>的过滤。
解决方法:
1 )将数据源的返回类型改为DataTable类型的,MS给出的例子就是这样的。
2 )如果和我一样不喜欢DataTable,就需要修改数据获取方法了。
将过滤条件作为参数,如下面GetProductTypes的category参数就是过滤条件。
public static List<DAO.ProductTypeInfo> GetProductTypes(string category)
这种方法的缺点是过滤条件是固定的,不够灵活。
如果需要一个灵活的过滤机制,还是考虑第一种方法把。
迁移后的代码:
aspx文件:
<tr>
<td align="right">
产品类别:
</td>
<td>
<asp:DropDownList ID="DropDownListProductList" runat="server" DataSourceID="ObjectDataSource_ProductTypes"
DataTextField="ProductTypeName" DataValueField="ProductTypeID"
Width="130px" AutoPostBack="True"
OnSelectedIndexChanged="DropDownListProductList_SelectedIndexChanged">
</asp:DropDownList>
</td>
</tr>
<tr>
<td align="right">
产品代码:</td>
<td >
<asp:TextBox ID="TextBoxProductTypeCode" runat="server" Width="50px" ReadOnly="true"/>-<asp:TextBox ID="TextBoxProductCode" runat="server" Width="50px"/>
</td>
</tr>
<asp:ObjectDataSource ID="ObjectDataSource_ProductTypes" runat="server"
SelectMethod="GetProductTypes" TypeName="SystemBL">
<SelectParameters>
<asp:ControlParameter ControlID="DropDownListProductTopType" Name="category" PropertyName="SelectedValue"
Type="String" />
</SelectParameters>
</asp:ObjectDataSource>
<asp:ObjectDataSource ID="ObjectDataSource_ProductCategories" runat="server"
SelectMethod="GetProductCategories" TypeName="SystemBL">
</asp:ObjectDataSource>
cs文件:
public static List<DAO.ProductTypeInfo> GetProductTypes(string category)
{
if (null == ProductTypList)
{
ProductTypList = new List<DAO.ProductTypeInfo>();
using (DAO.SystemDataDataContext db = new DAO.SystemDataDataContext(PublicDefine.SQLConnectString))
{
foreach (DAO.ProductTypeInfo type in db.ProductTypeInfos)
{
if (4 == type.ProductTypeCode.Trim().Length)
{
ProductTypList.Add(type);
}
}
}
}
//filter
List<DAO.ProductTypeInfo> list;
if (string.Empty == category)
{
list = ProductTypList.ToList<DAO.ProductTypeInfo>();
}
else
{
list = new List<DAO.ProductTypeInfo>();
int len=category.Trim().Length;
foreach (DAO.ProductTypeInfo type in ProductTypList)
{
if (category.Trim() == type.ProductTypeCode.Substring(0, len))
{
list.Add(type);
}
}
}
//sort
list.Sort(CompareProductType);
return list;
}
4 GridView控件的自动排序
GridView控件的自动排序也是非常有用的功能。但遗憾的是只能支持DataAset,DataTable类型。
解决方法:
需要截获sorting事件,然后中止GridView的自动处理,自己调用数据获取方法来进行过滤。由于需要过滤的数据列比较多,这里还需要引入LINQ的动态查询库。
LINQ的动态库是微软提供的一个LINQ Dynamic Query library. 可以从C# Dynamic Query Library (included in the /LinqSamples/DynamicQuery directory) 下载。
aspx:
<asp:ObjectDataSource ID="ObjectDataSource_Products" runat="server"
SelectMethod="GetProductsView" TypeName="SystemBL">
<SelectParameters>
<asp:ControlParameter ControlID="DrpProductTypeList" DefaultValue="-1"
Name="type" PropertyName="SelectedValue" Type="Int32" />
<asp:Parameter DefaultValue="" Name="orderby" Type="String" />
</SelectParameters>
</asp:ObjectDataSource>
页面逻辑cs
protected void GridViewProductsList_Sorting(object sender, GridViewSortEventArgs e)
{
//取得过滤列,然后设置ObjectDataSource的对应参数
ObjectDataSource_Products.SelectParameters["orderby"].DefaultValue = e.SortExpression;
//重新获取数据
GridViewProductsList.DataBind();
//中止GridView的过滤
e.Cancel = true;
}
5 LINQ动态查询
在使用了LINQ的动态查询库之后,动态查询就和原来动态拼装SQL语句一样容易了。
using System.Linq.Dynamic;
....
public static List<DAO.ProductViewInfo> GetProductsView(int type,string orderby)
{
string orderexpress;
if (null == orderby || string.Empty == orderby)
{
orderexpress = "ProductCode";
}
else
{
orderexpress = orderby;
}
using (DAO.SystemDataDataContext db = new DAO.SystemDataDataContext(PublicDefine.SQLConnectString))
{
List<DAO.ProductViewInfo> products;
if (type > 0)
{
var result = from p in db.ProductViewInfos
where p.ProductTypeID == type
orderby (orderexpress)
select p;
products = result.ToList<DAO.ProductViewInfo>();
}
else
{
var query = db.ProductViewInfos
.OrderBy(orderexpress);
products = query.ToList<DAO.ProductViewInfo>();
}
return products;
}
}