Использование ObjectDataSource с GridView в динамическом сценарии

У меня есть страница поиска, на которой выполняется поиск 3,5 миллионов записей для людей на основе их имени, идентификатора клиента, адреса и т. Д. Запросы варьируются от сложных до простых.

В настоящее время этот код использует SqlDataSource и GridView. Когда пользователь вводит термин поиска и нажимает клавишу ВВОД, TextBoxChanged даже запускает функцию поиска (термин, тип), которая изменяет запрос, который использует SqlDataSource, добавляет параметры и повторно связывает GridView.

Он работает хорошо, но я стал одержим более эффективным переписыванием кода. Я хочу, чтобы подкачка выполнялась SQL Server вместо неэффективности SqlDataSource в режиме DataSet.

Введите ObjectDataSource. Предупреждение: я никогда не использовал его до сегодняшнего дня.

Я провел большую часть дня, собирая этот класс:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

/// <summary>
/// Summary description for MultiSearchData
/// </summary>
public class MultiSearchData
{
    private string _connectionString = string.Empty;
    private string _sortColumns = string.Empty;
    private string _selectQuery = string.Empty;
    private int _lastUpdate;
    private int _lastRowCountUpdate;
    private int _lastRowCount;
    private SqlParameterCollection _sqlParams;

    public MultiSearchData()
    {

    }

    private void UpdateDate()
    {
        _lastUpdate = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
    }

    private string ReplaceFirst(string text, string search, string replace)
    {
        int pos = text.IndexOf(search);
        if (pos < 0)
        {
            return text;
        }
        return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
    }

    public string SortColumns
    {
        get { return _sortColumns; }
        set { _sortColumns = value; }
    }

    public SqlParameterCollection SqlParams
    {
        get { return _sqlParams; }
        set { _sqlParams = value; }
    }

    public string ConnectionString
    {
        get { return _connectionString; }
        set { _connectionString = value; }
    }

    public string SelectQuery
    {
        get { return _selectQuery; }
        set
        {
            if (value != _selectQuery)
            {
                _selectQuery = value;
                UpdateDate();
            }
        }
    }

    public DataTable GetFullDataTable()
    {
        return GetDataTable(AssembleSelectSql());
    }

    public DataTable GetPagedDataTable(int startRow, int pageSize, string sortColumns)
    {
        if (sortColumns.Length > 0)
            _sortColumns = sortColumns;

        return GetDataTable(AssemblePagedSelectSql(startRow, pageSize));
    }

    public int GetRowCount()
    {

        if (_lastRowCountUpdate == _lastUpdate)
        {
            return _lastRowCount;
        }
        else
        {
            string strCountQuery = _selectQuery.Remove(7, _selectQuery.IndexOf("FROM") - 7);
            strCountQuery = strCountQuery.Replace("SELECT FROM", "SELECT COUNT(*) FROM");

            using (SqlConnection conn = new SqlConnection(_connectionString))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand(strCountQuery, conn))
                {
                    if (_sqlParams.Count > 0)
                    {
                        foreach (SqlParameter param in _sqlParams)
                        {
                            cmd.Parameters.Add(param);
                        }
                    }
                    _lastRowCountUpdate = _lastUpdate;
                    _lastRowCount = (int)cmd.ExecuteScalar();
                    return _lastRowCount;
                }
            }
        }
    }

    public DataTable GetDataTable(string sql)
    {
        DataTable dt = new DataTable();

        using (SqlConnection conn = new SqlConnection(_connectionString))
        {
            using (SqlCommand GetCommand = new SqlCommand(sql, conn))
            {
                conn.Open();

                if (_sqlParams.Count > 0)
                {
                    foreach (SqlParameter param in _sqlParams)
                    {
                        GetCommand.Parameters.Add(param);
                    }
                }
                using (SqlDataReader dr = GetCommand.ExecuteReader())
                {
                    dt.Load(dr);
                    conn.Close();
                    return dt;
                }
            }
        }


    }

    private string AssembleSelectSql()
    {
        StringBuilder sql = new StringBuilder();

        sql.Append(_selectQuery);

        return sql.ToString();
    }

    private string AssemblePagedSelectSql(int startRow, int pageSize)
    {
        StringBuilder sql = new StringBuilder();
        string originalQuery = ReplaceFirst(_selectQuery, "FROM", ", ROW_NUMBER() OVER (ORDER BY " + _sortColumns + ") AS ResultSetRowNumber FROM");
        sql.Append("SELECT * FROM (");
        sql.Append(originalQuery);
        sql.Append(") AS PagedResults");
        sql.AppendFormat(" WHERE ResultSetRowNumber > {0} AND ResultSetRowNumber <= {1}", startRow.ToString(), (startRow + pageSize).ToString());

        return sql.ToString();
    }
}

Не знаю, красиво ли. Оно работает. Я задаю ему запрос в методе ObjectCreating:

protected void dataMultiSearchData_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
    MultiSearchData info;
    info = Cache["MultiSearchDataObject"] as MultiSearchData;

    if (null == info)
    {
        info = new MultiSearchData();
    }


    info.SortColumns = "filteredcontact.fullname";
    info.ConnectionString = "Data Source=SERVER;Initial Catalog=TheDatabase;Integrated Security=sspi;Connection Timeout=60";
    info.SelectQuery = @"SELECT filteredcontact.contactid,
                              filteredcontact.new_libertyid,
                              filteredcontact.fullname,
                              '' AS line1,
                              filteredcontact.emailaddress1,
                              filteredcontact.telephone1,
                              filteredcontact.birthdateutc AS birthdate,
                              filteredcontact.gendercodename
                        FROM  filteredcontact 
                        WHERE fullname LIKE 'Griffin%' AND filteredcontact.statecode = 0";

    e.ObjectInstance = info;
}
protected void dataMultiSearchData_ObjectDisposing(object sender, ObjectDataSourceDisposingEventArgs e)
{
    MultiSearchData info = e.ObjectInstance as MultiSearchData;

    MultiSearchData temp = Cache["MultiSearchDataObject"] as MultiSearchData;

    if (null == temp)
    {
        Cache.Insert("MultiSearchDataObject", info);
    }

    e.Cancel = true;
}

Как только класс получает запрос, он обертывает его в SQL-запросе, удобном для разбиения на страницы, и мы отправляемся в гонки. Я реализовал кеширование, чтобы можно было пропустить некоторые дорогостоящие запросы. И Т. Д.

Моя проблема в том, что это полностью нарушает мой довольно маленький мир поиска (термин, тип). То, что запрос не задан в методе создания объектов, полностью меня расстраивает.

Я весь день пытался придумать лучший способ сделать это, но у меня все время получается действительно беспорядочный ... делайте все это в модели ObjectCreating, которая просто сводит меня с ума.

Как бы ты это сделал? Как мне сохранить эффективность этого нового метода, сохранив при этом организационную простоту моей прежней модели?

Я слишком ОКР?


person clifgriffin    schedule 29.09.2010    source источник
comment
Метод ObjectCreating над термином запроса встроен. Связанный класс поддерживает параметры, я просто еще не реализовал его, так как не могу решить, как организовать реализацию. :)   -  person clifgriffin    schedule 29.09.2010
comment
почему вы не используете хранимые процедуры? использование встроенного sql - это боль, которую нужно поддерживать.   -  person Nick Kahn    schedule 02.10.2010
comment
Или, еще лучше, ORM. Действительно легко взять запрос LINQ и преобразовать его в запрос Count или сделать его страницей с безопасностью типов и т. Д.   -  person StriplingWarrior    schedule 02.12.2010


Ответы (1)


Я решил, что это невозможно. Кроме того, после тестирования этого класса я обнаружил, что он работает не лучше, чем SqlDataSource, но его гораздо труднее поддерживать.

Таким образом я отказался от этого проекта. Я надеюсь, что кто-то сочтет этот код полезным в какой-то момент.

person clifgriffin    schedule 02.12.2010