简体   繁体   English

如何在会话中保存SQL查询以供以后使用

[英]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. 这是您可以做的。

  1. 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); 
  2. 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.IsPostBackelse部分的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.

相关问题 如何使用 ASP.NET C# 将 SQL 查询的结果存储在会话变量中以便以后使用 - How to store the result of SQL query in Session Variable using ASP.NET C# to use it later 如何将输入数据保存到模型中,然后将其存储在会话中以供以后使用MVC显示? - How to save the input data into model and then store it in a session for later display using MVC? 如何保存值以便以后返回? - How to save a value to return it later? 我应该如何处理 StringBuilder 中的“&”,因为稍后它被用作 XML 并解析 XML 在 SQL 服务器数据库中抛出错误 - How should I handle "&" in StringBuilder as later this is being used as XML and parsing that XML throws error in SQL Server database 如何在列中将数据表保存到SQL数据库中,然后在c#中以表格格式检索转换为pdf的数据表 - How to save a datatable to SQL database in a column and later retrieve that convert to pdf in a tabular format in c# 如何在构造函数中创建数组,稍后将使用 - How to create an array in constructor that will be used later 如何在数据库中保存UIElement并在以后还原它们? - How to save UIElements in a Database and restore them later? 如何保存MethodInfo指针并稍后调用该函数? - How to save a MethodInfo pointer and later call that function? 如何保存ref变量供以后使用? - How to save a ref variable for later use? 如何在类中保存一个方法以便稍后执行 - How to save a method in a class to be executed later
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM