LINQ возвращает другой порядок сортировки для той же функции - PullRequest
0 голосов
/ 03 июля 2019

На Page_Load я установил свой GridView с помощью: myGridView.DataSource = context.Table.OrderByDescending(x => x.Date).ToList();. Затем я сохраняю значения SortBy и SortDirection в ViewState с: ViewState["SortBy"] = "Date" и ViewState["SortDirection"] = "DESC". Если я запускаю SELECT * FROM Table Order By Date DESC, я получаю те же записи в том же порядке, что и GridView (звучит глупо, что я указал на это, но терпите меня).

У меня также есть кнопка, которая фильтрует GridView на основе некоторых TextBox. Допустим, у меня есть tbName, tbType, tbFrom и tbTo. Это код выглядит так:

protected void btnRefresh_Click(object sender, EventArgs e)
{
    try
    {
        using (GasMarketerDBEntities context = new GasMarketerDBEntities())
        {
             if (context.Table.Count() > 0)
             {
                 DateTime date;
                 List<Table> results = context.Table.ToList();
                 if (!string.IsNullOrEmpty(tbName.Text))
                 {
                    results = results.Where(x => x.Name == tbName.Text).ToList();
                 }
                 if (!string.IsNullOrEmpty(tbType.Text))
                 {
                    results = results.Where(x => x.Type == tbType.Text).ToList();
                 }
                 if (!string.IsNullOrEmpty(tbFrom.Text) && DateTime.TryParse(tbFrom.Text, out date))
                 {
                     results = results.Where(x => x.Date >= date).ToList();
                 }
                 if (!string.IsNullOrEmpty(tbTo.Text) && DateTime.TryParse(tbTo.Text, out date))
                 {
                     results = results.Where(x => x.Date <= date).ToList();
                 }
                 if (myGridView.EditIndex != -1)
                 {
                     //GridView is in Edit Mode
                     myGridView.EditIndex = -1;
                 }
                 if (ViewState["SortDirection"].ToString() == "ASC")
                 {
                     switch (ViewState["SortBy"].ToString())
                     {
                         case "Date":
                            results = results.OrderBy(x => x.Date).ToList();
                            break;
                         case "Name":
                            results = results.OrderBy(x => x.Name).ToList();
                            break;
                         case "Type":
                            results = results.OrderBy(x => x.Type).ToList();
                            break;
                     }
                 }
                 else
                 {
                     switch (ViewState["SortBy"].ToString())
                     {
                         case "Date":
                            results = results.OrderByDescending(x => x.Date).ToList();
                            break;
                         case "Name":
                            results = results.OrderByDescending(x => x.Name).ToList();
                            break;
                         case "Type":
                            results = results.OrderByDescending(x => x.Type).ToList();
                            break;
                    }
                }
                gvNominations.DataSource = results;
            }
            else
            {
                gvNominations.DataSource = null;
            }
        }
        gvNominations.DataBind();
        Session["DataSource"] = gvNominations.DataSource;
    }
    catch (Exception ex)
    {
        if (ex.InnerException != null)
        {
            while (ex.InnerException != null)
            {
                ex = ex.InnerException;
            }
        }
        ((System.Web.UI.HtmlControls.HtmlGenericControl)Master.FindControl("errorMessage")).InnerText = "[btnRefresh_Click]: " + ex.Message;
        }
    }
}

Если я не помещаю какие-либо значения в поля фильтра и нажимаю Обновить, он пропускает все эти проверки, если проверяет, и попадает в раздел сортировки, который, будучи неизменным, должен работать как Дата DESC. И это делает . Странная часть состоит в том, что как только строка results = results.OrderByDescending(x => x.Date).ToList(); запускается (так же, как в предложении Where, когда мы устанавливаем результаты в List<Table> results = context.Table.OrderByDescending(x => x.Date).ToList()), порядок не совпадает. Последние записи находятся вверху, но, похоже, они сортируются в другом втором поле.

Edit:

убрал OrderByDescending в настройке results в начале btnRefresh_Click. Если мне кажется, что это работает, но мне интересно, почему я не могу начать с того же набора данных, затем применим OrderByDescending позже в блоке переключателя и получим тот же порядок, который установлен в OrderByDescending в Page_Load

1 Ответ

1 голос
/ 03 июля 2019

Один важный момент в вашем примере.Избегайте использования .ToList() слишком рано в вашем запросе.Создайте IQueryable, затем выполните его с ToList(), как только все ваши фильтры и порядок будут применены.Это большой запах кода с EF, который приводит к производительности и чрезмерному использованию ошибок памяти, которые люди ошибочно приписывают Entity Framework.

Например:

List<Table> results = context.Table.ToList();

Это в основном загружает "SELECT* ИЗ таблицы "из базы данных в память.Вместо этого создайте запрос и выполните его один раз в конце.Это уменьшает количество данных, отправляемых обратно с сервера.

using (GasMarketerDBEntities context = new GasMarketerDBEntities())
{
    DateTime date;
    var query = context.Table.AsQueryable;
    if (!string.IsNullOrEmpty(tbName.Text))
        results = results.Where(x => x.Name == tbName.Text);
    if (!string.IsNullOrEmpty(tbType.Text))
        results = results.Where(x => x.Type == tbType.Text);
    if (!string.IsNullOrEmpty(tbFrom.Text) && DateTime.TryParse(tbFrom.Text, out date))
        results = results.Where(x => x.Date >= date);
    if (!string.IsNullOrEmpty(tbTo.Text) && DateTime.TryParse(tbTo.Text, out date))
        results = results.Where(x => x.Date <= date);

    if (myGridView.EditIndex != -1)
        myGridView.EditIndex = -1;

    if (ViewState["SortDirection"].ToString() == "ASC")
    {
        switch (ViewState["SortBy"].ToString())
         {
             case "Date":
                 results = results.OrderBy(x => x.Date);
                 break;
             case "Name":
                 results = results.OrderBy(x => x.Name);
                 break;
             case "Type":
                 results = results.OrderBy(x => x.Type);
                 break;
         }
     }
     else
     {
         switch (ViewState["SortBy"].ToString())
         {
             case "Date":
                 results = results.OrderByDescending(x => x.Date);
                 break;
             case "Name":
                 results = results.OrderByDescending(x => x.Name);
                 break;
             case "Type":
                 results = results.OrderByDescending(x => x.Type);
                 break;
        }
    }
    var results = query.ToList(); // Single ToList call to materialize.
    gvNominations.DataSource = results;
    gvNominations.DataBind();
    // Session["DataSource"] = gvNominations.DataSource; Don't persist these entities
}

Лучше, чем возвращать объекты, было бы использовать .Select() для заполнения модели представления только столбцами, которые вы хотите отобразить.Это сокращает объем данных, передаваемых по проводам из БД на веб-сервер и с веб-сервера на клиент.Это также может позволить вам выбирать данные из ссылочных объектов без необходимости явно включать эти ссылочные объекты или накладные расходы / ошибки, которые могут возникнуть при попытке сериализации объектов с отношениями.

    var results = query.Select(x => new TableListEntry
    {
        Id = x.Id,
        Name = x.Name,
        Date = x.Date,
        Type = x.Type,
        // ... etc.
    }).ToList();

Модели просмотра также безопасны длясохраняться до состояния сеанса или чего-то еще.Не сохраняйте сущности и избегайте передачи сущностей клиенту.Сущности должны существовать только в пределах их DbContext.Сериализация их клиентам приводит к проблемам с циклическими ссылками, приводящими к отключению сериализаторов, а также к проблемам ассоциации / повторной ассоциации, если вы позже попытаетесь использовать их в рамках другого DbContext.

...