最近在將一個原來用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;
}
}