[英]How to save a SQL query in session to be used later
I have a function which runs a query each time a button is pressed or each time any of the 7 DropDownList selection has been changed. 我有一个函数,每次按下按钮或每次更改7个DropDownList选择中的任何一个时,都会运行查询。 How can I change the existing method to use Session or ViewState so my page will run the query once and then query against the Session or ViewState instead of going out to my SQL server for every request?
如何更改现有方法以使用Session或ViewState,以便我的页面将运行一次查询,然后针对Session或ViewState进行查询,而不是针对每个请求都前往SQL Server?
Code-Behind: 代码隐藏:
protected void Page_Load(object sender, EventArgs e)
{
strMainQuery = @"SELECT 'http://dddfgdgdfg?objectid=' + CT.OBJECTID + '&classid=1224' 'Task Detail'
,LTRIM(RTRIM(CT.ATTR2846)) 'Service'
,LTRIM(RTRIM(CT.ATTR2812)) 'Status'
,CONVERT(VARCHAR(14), CT.ATTR2752, 110) 'Due Date'
,LTRIM(RTRIM(CT.ATTR2739)) 'Task Name'
,LTRIM(RTRIM(UA.REALNAME)) 'Owner'
,LTRIM(RTRIM(CT.ATTR2799)) 'Client'
FROM HSI.RMOBJECTINSTANCE1224 CT INNER JOIN HSI.RMOBJECTINSTANCE1232 S ON CT.ATTR2846 = S.ATTR2821 INNER JOIN HSI.USERACCOUNT UA ON S.FK2852 = (UA.USERNUM * -1)";
if (!Page.IsPostBack)
{
ViewState["sortOrder"] = "Asc";
ViewState["sortExp"] = "Due Date";
PullData("Due Date", "Asc"); //ASC: A (top) to Z (bottom) || # (low to high) || Date (oldest to newest)
}
else
{
PullData(ViewState["sortExp"].ToString(), ViewState["sortOrder"].ToString());
}
}
public void PullData(string sortExp, string sortDir)
{
string query = "";
DataTable taskData = new DataTable();
connString = ""; //connection string
if (ddlTaskName.SelectedIndex > 0)
{
strClause += " AND CT.ATTR2739 = '" + ddlTaskName.SelectedItem.Text + "'";
}
else
{
strClause += " AND CT.ATTR2739 LIKE '%'";
}
if (ddlService.SelectedIndex > 0)
{
strClause += " AND CT.ATTR2846 = '" + ddlService.SelectedItem.Text + "'";
}
else
{
strClause += " AND CT.ATTR2846 LIKE '%'";
}
if (ddlStatus.SelectedIndex > 0)
{
strClause += " AND CT.ATTR2812 = '" + ddlStatus.SelectedItem.Text + "'";
}
else
{
strClause += " AND CT.ATTR2812 LIKE '%'";
}
if (ddlDueDate.SelectedIndex > 0)
{
strClause += " AND CONVERT(VARCHAR(14), CT.ATTR2752, 110) = '" + ddlDueDate.SelectedItem.Text + "'";
}
else
{
strClause += " AND CONVERT(VARCHAR(14), CT.ATTR2752, 110) LIKE '%'";
}
if (ddlOwner.SelectedIndex > 0)
{
strClause += " AND UA.REALNAME = '" + ddlOwner.SelectedItem.Text + "'";
}
else
{
strClause += " AND UA.REALNAME LIKE '%'";
}
if (ddlClient.SelectedIndex > 0)
{
strClause += " AND CT.ATTR2799 = '" + ddlClient.SelectedItem.Text + "'";
}
else
{
strClause += " AND CT.ATTR2799 LIKE '%'";
}
if (ddlTaskName.SelectedIndex == 0 && ddlService.SelectedIndex == 0 && ddlStatus.SelectedIndex == 0 && ddlDueDate.SelectedIndex == 0 && ddlOwner.SelectedIndex == 0 && ddlClient.SelectedIndex == 0)
{
query = strMainQuery + " WHERE CT.ACTIVESTATUS = 0";
}
else
{
query = strMainQuery + " WHERE CT.ACTIVESTATUS = 0" + strClause;
}
using (SqlConnection conn = new SqlConnection(connString))
{
try
{
SqlCommand cmd = new SqlCommand(query, conn);
// create data adapter
SqlDataAdapter da = new SqlDataAdapter(query, conn);
// this will query your database and return the result to your datatable
DataSet myDataSet = new DataSet();
da.Fill(myDataSet);
DataView myDataView = new DataView();
myDataView = myDataSet.Tables[0].DefaultView;
if (sortExp != string.Empty)
{
//MessageBox.Show(sortExp);
//MessageBox.Show(sortDir);
myDataView.Sort = string.Format("{0} {1}", sortExp, sortDir);
}
yourTasksGV.DataSource = myDataView;
yourTasksGV.DataBind();
TasksUpdatePanel.Update();
conn.Close();
}
catch (Exception ex)
{
string error = ex.Message;
}
}
}
As you can see, each time PullData
is called, it is going out to the SQL server and running the query which will eventually slow down once I start to have more and more data. 如您所见,每次调用
PullData
,它都会进入SQL服务器并运行查询,一旦我开始拥有越来越多的数据,该查询最终将减慢速度。
How can I convert the existing method to query once and save to a Session/ViewState so I don't have to query against SQL server each time? 如何将现有方法转换为只查询一次并保存到Session / ViewState,这样我就不必每次都针对SQL Server进行查询?
Before running the query, check the cache. 在运行查询之前,请检查缓存。 If its there, use it.
如果有,请使用它。 If not, run the query and add the resulting data into Cache.
如果不是,请运行查询并将结果数据添加到缓存中。
You could use Cache.Insert Method (String, Object, CacheDependency, DateTime, TimeSpan) . 您可以使用Cache.Insert方法(字符串,对象,CacheDependency,DateTime,TimeSpan) 。 You can find some great caching tips: ASP.NET Caching: Techniques and Best Practices .
您可以找到一些很棒的缓存技巧: ASP.NET缓存:技术和最佳实践 。
Here is how I would structure the PullData method: 这是我将如何构造PullData方法的方法:
public void PullData(string sortExp, string sortDir)
{
// build your query string
// ...
// Now create a hash of that query string
string cacheKey = HashHelper(query);
DataSet ds = null;
// check cache if key exists
if(Cache[cacheKey] != null)
{
// read dataset from cache
ds = (DataSet)Cache[cacheKey];
}
else
{
// perform sql command and fill your dataset
// ....
// save dataset to cache for 30 minutes or whatever you like
Cache.Insert(cacheKey, ds, null, DateTime.Now.AddMinutes(30), TimeSpan.Zero);
}
// Get DataView based on sort options
DataView myDataView = new DataView();
myDataView = ds.Tables[0].DefaultView;
if (sortExp != string.Empty)
{
myDataView.Sort = string.Format("{0} {1}", sortExp, sortDir);
}
yourTasksGV.DataSource = myDataView;
yourTasksGV.DataBind();
TasksUpdatePanel.Update();
// keep calm and carry on
}
Here is my Hash Helper 这是我的哈希助手
private string HashHelper(string query)
{
using (SHA256Managed hashEngine = new SHA256Managed())
{
byte[] data = hashEngine.ComputeHash(Encoding.UTF8.GetBytes(query));
StringBuilder hash = new StringBuilder(64);
for (int i = 0; i < data.Length; i++)
{
hash.Append(data[i].ToString("x2"));
}
return hash.ToString();
}
}
With your current structure of code you can not do it. 使用当前的代码结构,您将无法做到。 Because your
strMainQuery
has the sql statement without the WHERE
clause and as the dropdown value changes you are dynamically building the conditions for the WHERE
clause. 因为您的
strMainQuery
具有不带WHERE
子句的sql语句,并且随着下拉值的更改,所以您正在动态构建WHERE
子句的条件。 So you can't store that result set in session as the values change with every dropdown selection. 因此,由于每个下拉选项的值都会更改,因此您无法在会话中存储该结果集。
Here is what you can do. 这是您可以做的。
Retrieve all records for strMainQuery
without any WHERE condition and store the results in session or some other state management. 在没有任何WHERE条件的情况下检索
strMainQuery
所有记录, strMainQuery
结果存储在会话或其他状态管理中。 So your PullData
method will contain 因此,您的
PullData
方法将包含
SqlCommand cmd = new SqlCommand(strMainQuery, conn);
As the dropdown value changes access the session object and use LINQ to filter the data based on the values for different dropdown. 随着下拉值的更改,访问会话对象,并使用LINQ根据不同下拉列表的值过滤数据。 This will at least help you not to access the database server for every dropdown value changes, rather
这至少将帮助您不要在每次下拉值更改时都访问数据库服务器,而是
Fetch once => store it => and do additional data filtering using LINQ 一次获取=>将其存储=>并使用LINQ进行其他数据过滤
Before you bind the grid in the below lines do the data filtering. 在下面几行中绑定网格之前,请进行数据过滤。
// do the data filtering against the data source based on dropdown selected values yourTasksGV.DataSource = myDataView; yourTasksGV.DataBind();
I do see that you are calling PullData
in both !Page.IsPostBack
as well as in the else
part the PageLoad
which means that this function PullData
will be called every time there is a postback triggered by any other controls on the page. 我确实看到您在
!Page.IsPostBack
和else
部分的PageLoad
中都调用了PullData
,这意味着每当页面上的任何其他控件触发回发时,都会调用此函数PullData
。 Rather add a OnSelectedIndexChanged
event for the dropdowns and call the PullData
method. 而是为下拉列表添加一个
OnSelectedIndexChanged
事件,然后调用PullData
方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.