Как лучше всего хранить / запрашивать несколько типов в Коллекция RavenDB?

Я разрабатываю систему ведения журнала, которая будет хранить записи журнала в RavenDB, и для этой конкретной системы я хочу хранить (а затем запрашивать) документы, которые имеют различные структуры данных в зависимости от типа регистрируемого события.Рассмотрим следующие события, которые я, возможно, захочу регистрировать:

  1. Пользователь входит в систему - Сохраняет идентификатор пользователя
  2. Пользователь удаляет файл - Сохраняет идентификатор пользователя и имя удаляемого файла

У меня есть несколько разных способов. здесь ...

Вариант A. Создайте два совершенно разных типа

class LoginEvent
{
  public int UserId { get; set; }
}

class FileDeleteEvent
{
  public int UserId { get; set; }
  public string Filename { get; set; }
}

Этот подход приводит к созданию двух разных коллекций в RavenDB, и к ним легко выполнять запросы. Однако для получения объединения всех записей журнала требуется несколько запросов и несколько обращений к серверу - один для LoginEvents и второй для FileDeleteEvents. Только с двумя типами событий это не имеет большого значения, но проблема значительно усугубляется по мере увеличения количества типов событий.

Вариант Б. Создать базовый класс и унаследовать от него

abstract class Event
{
}

class LoginEvent : Event
{
  public int UserId { get; set; }
}

class FileDeleteEvent : Event
{
  public int UserId { get; set; }
  public string Filename { get; set; }
}

Я пробовал этот подход, но RavenDB, похоже, хранит и запрашивает документы по их фактическим типам, а не по их типам приведения, когда я сделал Query (). ToArray () Я не получил результатов. Чтобы вернуть документы, мне пришлось бы запросить их отдельные типы, что фактически эквивалентно варианту А, описанному выше.

Вариант C. Создание различных классов свойств

enum EventType { Login, FileDelete }

class Event
{
  public EventType EventType { get; set; }
  public object Info { get; set; }
}

class LoginInfo
{
  public int UserId { get; set; }
}

class FileDeleteInfo
{
  public int UserId { get; set; }
  public string Filename { get; set; }
}

При таком подходе мы всегда сохраняем запись типа Event, но мы заполняем ее свойство Info соответствующим классом Info, который предоставляет подробные сведения, относящиеся к типу события. Сначала этот вариант казался лучшим, поскольку он хранит все записи журнала в единой коллекции событий и упрощает запрос всей коллекции. Однако, допустим, мне нужны только события FileDelete, в которых имя файла - «test.txt». Это становится немного сложнее.

Например, следующее выдает несколько неясную ошибку о том, что поле «Имя файла» не индексируется:

var events = session.Query()
  .Where(a => a.EventType == EventType.FileDelete)
  .Where(a => ((FileDeleteInfo)a.Info).Filename == "test.txt")
  .ToArray();

Следующее, помимо того, что не то, что я хочу, возвращает нулевые результаты:

var events = session.Query()
  .Select(a => a.Info)
  .OfType()
  .Where(a => a.Filename == "test.txt")
  .ToArray();

Действительно, следующий прогноз, поддерживаемая операция согласно документации, даже не возвращает ожидаемый тип, просто набор странных промежуточных результатов, которые не имеют смысла:

var events = session.Query()
  .Select(a => a.Info)
  .ToArray();

Итак, хотя этот вариант, вероятно, хорош с точки зрения хранения данных, он не работает из-за перспектива запрашиваемости. (Предполагая, что я создаю правильный запрос - может быть другой способ, который я не рассматриваю).

Вариант D. Создать гигантский класс событий со всеми возможными свойствами

enum EventType { Login, FileDelete }

class Event
{
  public EventType EventType { get; set; }
  public int UserId { get; set; }
  public string Filename { get; set; }
  .
  .
  .
}

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

Вариант E. Забудьте RavenDB и используйте Entity Framework + Sql

Я могу сделать это довольно тривиально и эффективно запрашивать, используя шаблон наследования EF по таблицам. Обратной стороной этого подхода является то, что Sql является серьезным излишеством для этой проблемы - нам не нужна согласованность данных и другая строгость, которую обеспечивают реляционные системы. И, по моему опыту, вставки Sql намного медленнее, чем хранение документов в RavenDB (важное соображение для системы журналирования).

Итак, есть варианты ... как вы думаете? Я что-то пропустил?

Возможно, связано: Указание имени коллекции в RavenDB

8
задан Community 23 May 2017 в 12:16
поделиться