Каков наилучший способ сохранить отфильтрованные пользователем параметры запроса в таблице базы данных? - PullRequest
6 голосов
/ 31 декабря 2011

У меня есть веб-сайт ASP.NET MVC.В моем бэкэнде у меня есть таблица с именем People со следующими столбцами:

  1. ID
  2. Имя
  3. Возраст
  4. Расположение
  5. ... (ряд других столбцов)

У меня есть общая веб-страница, которая использует привязку модели для запроса этих данных.Вот мое действие контроллера:

public ActionResult GetData(FilterParams filterParams)
{
      return View(_dataAccess.Retrieve(filterParams.Name, filterParams.Age, filterParams.location, . . .)
}

, которое отображается на что-то вроде этого:

 http://www.mysite.com/MyController/GetData?Name=Bill .. . 

Уровень dataAccess просто проверяет каждый параметр, чтобы увидеть, заполнен ли он для добавления в предложение db where,Это прекрасно работает.

Теперь я хочу иметь возможность хранить отфильтрованные запросы пользователя, и я пытаюсь найти лучший способ сохранить определенный фильтр.Так как некоторые из фильтров имеют только один параметр в queryString, в то время как другие имеют более 10 полей в фильтре, я не могу найти самый элегантный способ сохранить этот запрос «информация фильтра» в моей базе данных.

ПараметрыЯ могу подумать:

  1. Имейте полную копию таблицы (с некоторыми дополнительными столбцами), но назовите ее PeopleFilterQueries, заполните в каждой записи значение FilterName и поместите значение фильтра вкаждое из полей (Имя и т. д.)

  2. Сохраните таблицу только с FilterName и строкой, в которой я храню фактическую строку запроса Name = Bill & Location = NewYork.Таким образом, мне не нужно будет добавлять новые столбцы, если фильтры меняются или растут.

Каков наилучший метод для этой ситуации?

Ответы [ 7 ]

6 голосов
/ 04 января 2012

Если цель состоит в том, чтобы сохранить список недавно использованных фильтров, я бы сериализовал весь объект FilterParams в поле / столбец XML после привязки модели.Сохраняя его в поле XML, вы также даете себе гибкость в использовании XQuery и DML, если в дальнейшем возникнет необходимость в более подробном запросе информации.

    public ActionResult GetData(FilterParams filterParams)
    {
          // Peform action to get the information from your data access layer here
          var someData = _dataAccess.Retrieve(filterParams.Name, filterParams.Age, filterParams.location, . . .);

          // Save the search that was used to retrieve later here
          _dataAccess.SaveFilter(filterParams);
          return View(someData);
    }

А затем в вашемКласс DataAccess, вы захотите иметь два метода, один для сохранения и один для извлечения фильтров:

public void SaveFilter(FilterParams filterParams){
    var ser = new System.Xml.Serialization.XmlSerializer(typeof(FilterParams));
    using (var stream = new StringWriter())
           {
              // serialise to the stream
              ser.Serialize(stream, filterParams);
           }
  //Add new database entry here, with a serialised string created from the FilterParams obj
  someDBClass.SaveFilterToDB(stream.ToString());
}

Затем, когда вы хотите получить сохраненный фильтр, возможно, по Id:

public FilterParams GetFilter(int filterId){

      //Get the XML blob from your database as a string
      string filter = someDBClass.GetFilterAsString(filterId);

      var ser = new System.Xml.Serialization.XmlSerializer(typeof(FilterParams));

      using (var sr = new StringReader(filterParams))
      {
          return (FilterParams)ser.Deserialize(sr);
      }
}

Помните, что ваш класс FilterParams должен иметь конструктор по умолчанию (т.е. без параметров), и вы можете использовать атрибут [XmlIgnore], чтобы предотвратить сериализацию свойств в базу данных, если вы пожелаете.

public class FilterParams{
   public string Name {get;set;}
   public string Age {get;set;}

   [XmlIgnore]
   public string PropertyYouDontWantToSerialise {get;set;}
}

Примечание: SaveFilter возвращает Void, и для краткости нет обработки ошибок.

2 голосов
/ 10 января 2012

Ответ гораздо проще, чем вы его делаете:

По сути, вы должны сохранить необработанный запрос в его собственной таблице и связать его с вашей таблицей People. Не беспокойтесь о сохранении отдельных параметров фильтра.

Выберите значение для хранения (2 варианта)

  1. Сохранить строку запроса URL

    Этот идентификатор будет полезен, если вам нравятся открытые приложения в стиле API, и вы хотите что-то, что вы могли бы легко передать от клиента к серверу и использовать повторно без преобразования.

  2. Сериализация объекта Filter в виде строки

    Это действительно хороший подход, если ваша цель хранения этих фильтров остается полностью на стороне сервера, и вы хотите, чтобы данные были ближе к объекту класса.

Соотнесите ваш People стол с вашим Query Filters Table:

Лучшая стратегия здесь зависит от ваших намерений и потребностей в производительности. Некоторые предложения ниже:

  • Простая фильтрация (например, 2-3 фильтра, 3-4 варианта каждый)

    Используйте Many-To-Many, потому что количество комбинаций предполагает, что одни и те же комбинации фильтров будут много раз использоваться многими людьми.

  • Комплексная фильтрация

    Используйте One-To-Many, поскольку существует так много возможных отдельных запросов, поэтому менее вероятно, что они будут использоваться повторно достаточно часто, чтобы лишняя нормализация и снижение производительности стоили вашего времени.

Конечно, есть и другие варианты, но они будут зависеть от более детальных нюансов вашего приложения. Приведенные выше предложения будут хорошо работать, если вы говорите, пытаясь отслеживать «последние запросы» для пользователя или «любимые пользователем» параметры фильтрации ...

Личное мнение Не зная больше о вашем приложении, я бы сказал (1) сохранить строку запроса и (2) использовать таблицы, относящиеся к OTM ... если и когда ваше приложение обнаруживает необходимость дальнейшего профилирования производительности или проблемы с рефакторингом параметров фильтра, тогда вернись ... но скорее всего, это не так.

GL.

2 голосов
/ 09 января 2012

Вы не упомянули о точной цели хранения фильтра.

Если вы настаиваете на сохранении фильтра в таблице базы данных, у меня будет следующая структура таблицы.

  • FilterId
  • Поле
  • FieldValue

Пример таблицы может быть

FilterId Field    FieldValue
1        Name     Tom
1        Age      24
1        Location IL       
3        Name     Mike
...
2 голосов
/ 31 декабря 2011

Вместо сохранения строки запроса я бы сериализовал объект FilterParams как JSON / XML и сохранил результат в вашей базе данных.

Вот сериализатор JSON, который я регулярно использую:

using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;

namespace Fabrik.Abstractions.Serialization
{
    public class JsonSerializer : ISerializer<string>
    {
        public string Serialize<TObject>(TObject @object) {
            var dc = new DataContractJsonSerializer(typeof(TObject));
            using (var ms = new MemoryStream())
            {
                dc.WriteObject(ms, @object);
                return Encoding.UTF8.GetString(ms.ToArray());
            }
        }

        public TObject Deserialize<TObject>(string serialized) {
            var dc = new DataContractJsonSerializer(typeof(TObject));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(serialized)))
            {
                return (TObject)dc.ReadObject(ms);
            }
        }
    }
}

Затем вы можете десериализовать объект и передать ему свой код доступа к данным, как в приведенном выше примере.

1 голос
/ 11 января 2012

На мой взгляд, лучший способ сохранить «Фильтр» - это иметь какую-то текстовую строку json с каждым из «имен столбцов»

Так что в БД у вас будет что-то вроде

Настольные фильтры

FilterId = 5; FilterParams = {'age': '> 18', ...

Json предоставит множество возможностей, таких как использование age в качестве массива, чтобы иметь более одного фильтра для одного и того же «столбца» и т. Д.

Также json является своего рода стандартом, поэтому вы можете использовать эти «фильтры» вместе с другими БД в один прекрасный день или просто «отобразить» фильтр или отредактировать его в веб-форме. Если вы сохраните запрос, вы будете прикреплены к нему.

Ну, надеюсь, это поможет!

0 голосов
/ 07 января 2012

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

Профили В ASP.NET 2.0

Я должен признать, что реализация M $ немного устарела, но естьпо сути, ничего плохого в подходе.Если вы хотите сделать что-то свое, в их API есть немало хороших идей.

0 голосов
/ 06 января 2012

Предполагая, что о базе данных nosql / object, такой как Berkeley DB , не может быть и речи, я определенно выбрал бы вариант 1. Рано или поздно вы обнаружите следующие требования или другие подходящие:

  1. Разрешить людям сохранять свои фильтры, метки, теги, искать и делиться ими с помощью закладок, твитов или чего-либо еще.
  2. Изменение значения параметра или его действия, которое потребует от васверсионность ваших фильтров для обратной совместимости.
  3. Предоставление функций автозаполнения поверх фильтров, возможно, с использованием истории фильтров пользователя для информирования автозаполнения.

Выше будет несколько сложнеечтобы удовлетворить, если вы выполняете какой-либо двоичный / строковый сериализации, где вам нужно проанализировать результат, а затем обработать их.

Если вы можете использовать DB NoSql, то вы будетеполучите все преимущества магазина sql и сможете очень хорошо смоделировать «произвольное количество пар ключ / значение».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...