Обновленный ответ (29 июня 2018 г.)
Ключом к успеху является одно недооцененное свойство Равена - Индексы с динамическими полями .Это позволяет сохранить логическую структуру данных и избежать создания индекса разветвления .
. Способ использования состоит в том, чтобы создавать коллекции, как описано выше в варианте № 1:
public class Contact
{
public string Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public Dictionary<string, object> CustomFields { get; set; }
}
public class CustomField
{
public string Id { get; set; }
public string Code { get; set; }
public string DataType { get; set; }
public string Description { get; set; }
}
где Contact.CustomFields.Key
является ссылкой на CustonField.Id
, а Contact.CustomFields.Value
хранит значение для этого настраиваемого поля.
Чтобы отфильтровать / выполнить поиск по настраиваемым полям, нам нужен следующий индекс:
public class MyIndex : AbstractIndexCreationTask<Contact>
{
public MyIndex()
{
Map = contacts =>
from e in contacts
select new
{
_ = e.CustomFields.Select( x => CreateField ($"{nameof(Contact.CustomFields)}_{x.Key}", x.Value))
};
}
}
Этот индекс будет охватывать все пары ключ-значение словаря, поскольку они были обычными свойствами Contact
.
Получено
Существуетбольшая проблема, если вы пишете запросы в C # с использованием обычного объекта Query (тип IRavenQueryable
), а не RQL
или DocumentQuery
.Это так, как мы назвали динамические поля - это составное имя в определенном формате: dictionary_name + underscore + key_name
.Это позволяет нам создавать запросы типа
var q = s.Query<Person, MyIndex>()
.Where(p => p.CustomFields["Age"].Equals(4));
, которые изнутри конвертируются в RQL:
from index 'MyIndex' where CustomFields_Age = $p1
Это недокументировано, а здесь - это мое обсуждение с Ореном Эйни(aka Ayende Rahien), где вы можете узнать больше по этому вопросу.
PS Моя общая рекомендация - взаимодействовать с Вороном по DocumentQuery
, а не по обычному Query
( ссылка ), поскольку интеграция LINQ все еще довольно слабая, и разработчики могут продолжать сталкиваться с ошибками тут и там.
Первоначальный ответ (9 июня 2018 г.)
Как было предложено Ореном Эйни (он же Ayende Rahien), путь - вариант № 2 - включая отдельную коллекцию ContactCustomField
в запросах.
Таким образом, несмотря на использование базы данных NoSQLреляционный подход - единственный путь сюда.