2017-02-05 2 views
0

У меня есть проект, где у меня есть набор форм:Обработка запросов над соответствующими документами в RavenDB

public class Form 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
    public IList<string> FieldValueIds { get; set; } 
    public string UserId { get; set; } // the user who completed the form. 
    public string FormTemplateId { get; set; } 
} 

Что каждый «реализовать» шаблон формы, выбранного при создании формы.

public class FormTemplate 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
    public IList<string> FieldIds { get; set; } 
} 

Определяет, какие поля имеются в форме. Каждое поле

public class FormField 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
    public string Caption { get; set; } 
    public ValueType DataType { get; set; } // Enum specifying the type of data this field accepts. 
} 

Хранит информацию о полевых условиях, таких как описание и какой тип ожидает. Каждый FormField может присутствовать в нескольких FormTemplates со значениями, которые сохраняются в виде объектов FieldValue, связанных с самой Формой.

public class FieldValue 
{ 
    public string Id { get; set; } 
    public string FieldId { get; set; } 
    public string ValueAsJsonString { get; set; } 
} 

Другие объекты включают в себя пользовательский объект:

public class User 
{ 
    public string Id { get; set; } 
    public string Username { get; set; } 
    public string GivenNames { get; set; } 
    public string Surname { get; set; } 
} 

Я хотел бы быть в состоянии выполнить запрос, чтобы найти все бланки, заполненные пользователем с указанным именем, или всех форм, где поле с именем X имеет значение Y и так далее.

Я посмотрел на использование индексов, как указано в документации Indexing related documents, однако реализация, как представлено в документации бросил NotSupportedException, когда я реализовал пример следующим образом:

class FormTemplates_ByFieldAndName : AbstractIndexCreationTask<FormTemplate> 
{ 
    public class Result 
    { 
     public string Name { get; set; } 
     public IList<string> FieldNames { get; set; } 
    } 

    public FormTemplates_ByFieldAndName() 
    { 
     Map = FormTemplates => from FormTemplate in FormTemplates 
          select new 
          { 
           Name = FormTemplate.Name, 
           FieldNames = FormTemplate.FieldIds.Select(x => LoadDocument<FormField>(x).Name) 
          }; 
    } 
} 

// in code: 
IList<FormTemplate> TestResults = session.Query<FormTemplates_ByFieldAndName.Result, FormTemplates_ByFieldAndName>() 
        .Where(x => x.Name == "TemplateName" || x.FieldNames.Contains("FieldName")) 
        .OfType<FormTemplate>() 
        .ToList(); 

Как лучше всего, как я могу сказать это было выполнено правильно, однако я видел предложение заменить .Contains. Вместо этого я экспериментировал с другим подходом, применяя последовательные аргументы. Подобно:

var pre = session.Query<FormTemplates_ByFieldAndName.Result, FormTemplates_ByFieldAndName>(); 
var pr2 = pre.Where(x => x.Name == "TypeTest25"); 

List<FormTemplate> TestResults = pr2 
    .Where(x => x.FieldNames.Any(a => a == "field25")) 
    .OfType<FormTemplate>() 
    .OrderByScoreDescending() 
    .ToList(); 

Модификация системы для выполнения в более фабричной ориентированного подхода путем применения последовательных фильтров на основе переданной строки в заранее заданном формате.

Является ли это тем, как я должен идти на эту реализацию, и если нет, то что я должен менять? В частности, если я должен продолжить опцию индексирования, как применить эту технику к вложенным отношениям между Forms и FormFields через FormTemplates.

ответ

0

Вы, кажется, пытаетесь сделать это таким образом, который является главным образом реляционным, но вам не обязательно.

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

public class Form 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
    public IList<FieldValue> FieldValues { get; set; } 
    public string UserId { get; set; } // the user who completed the form. 
    public string FormTemplateId { get; set; } 
} 

public class FieldValue 
{ 
    public string Id { get; set; } 
    // can store the value directly! 
    //public string ValueAsJsonString { get; set; } 
    public object Value {get; set; } 
} 

Это будет генерировать документы, выглядит следующим образом:

{ 
    "Id": "forms/1234", 
    "Name": "Tom", 
    "FieldValues": [ 
    { 
     "Id": "FromValues/SchoolDistrictName", 
     "Value": "ABi195" 
    } 
    ], 
    "UserId": "users/tom", 
    "FormTemplateId": "FromTemplate/1234" 
} 

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

https://ravendb.net/docs/article-page/3.5/Csharp/indexes/using-dynamic-fields

+0

Ой спасибо! Я отредактировал приведенный выше пример, чтобы более точно отразить природу fieldValue.Возможно ли, чтобы мой индекс также представлял связь между объектами FormField и FieldValue? Я хочу, чтобы у меня был запрос, в котором я могу найти все формы с формойField X с ассоциированным с ним FormValue Y. Пока я могу сделать одну или другую и не такую ​​специфическую функциональность. –

+0

Да, вы можете это сделать. Именно здесь вступают в игру динамические поля –

+0

Как вы отформатируете синтаксический запрос lucene для доступа к этим динамическим полям? –