Запрос списка вложенных документов с RavenDB - PullRequest
2 голосов
/ 29 февраля 2012

Учитывая следующую структуру объекта:

public class Object
{
public string Id {get;set;}
public List<SubObject> SubObjects {get;set;}
}

public class SubObject {get;set;}
{
public string Id {get;set;}
public string Name {get;set;}
}

Как бы я структурировал запрос для возврата списка SubObject, где Name.Contains("a")

Мне кажется, что это должно быть просто, но я 'Я действительно борюсь с этим.

Ответы [ 3 ]

2 голосов
/ 29 февраля 2012

Короткий ответ, нет.Документы в RavenDb являются агрегированными корнями, и вы не можете загрузить часть агрегированного корня, просто все.Таким образом, вы можете получить все Objects, которые содержат Subobjects с Именами, содержащими 'a', но вы не можете получить подобъекты самостоятельно.Сделайте SubObjects свои документы, если вам нужно получить их отдельно.

2 голосов
/ 01 марта 2012

В вашем корневом объекте вам нужно хранить идентификаторы субобъектов. Затем, когда вы загружаете корневой объект, вам нужно использовать функцию Raven Include () в вашем запросе. Это вытянет все документы подобъекта в сеанс. Оттуда вы можете загрузить свои субобъекты. Вот пример того, как я это делал:

Вот корневой объект:

public class Application : EntityBase

Приложение имеет подобъекты типа CustomVariableGroup. Поэтому мне нужно сохранить идентификаторы (это то, что RavenDB сохранит) в объекте.

public List<string> CustomVariableGroupIds { get; set; }  // For RavenDB

И реальные субобъекты все еще хранятся в корневом объекте, но не сохраняются в Raven таким образом:

[JsonIgnore]  //  We do not want RavenDB to serialize this.
public ObservableCollection<CustomVariableGroup> CustomVariableGroups

Так что это настройка, теперь вот как это происходит в Raven. (Забудьте метод ExecuteQuery (); это мой метод, который выходит за рамки этого вопроса.)

Это вызов для получения корневого объекта. Обратите внимание на функцию Include (), где мы извлекаем идентификаторы в сеанс:

public Application GetByName(string name)
{
    return ExecuteQuery<Application>(() =>
    {
        Application application = QuerySingleResultAndSetEtag(session =>
            session.Query<Application>()
            .Include(x => x.CustomVariableGroupIds)
            .Where(app => app.Name == name).FirstOrDefault())
            as Application;

        HydrateApplication(application);

        return application;
    });
}

А вот как мы загружаем субобъекты:

public static void HydrateApplication(Application app)
{
    if (app == null) { throw new ArgumentNullException("app"); }
    if (app.CustomVariableGroupIds == null) { return; }

    app.CustomVariableGroups = new ObservableCollection<CustomVariableGroup>();

    foreach (string groupId in app.CustomVariableGroupIds)
    {                
        app.CustomVariableGroups.Add(QuerySingleResultAndSetEtag(session => session.Load<CustomVariableGroup>(groupId)) as CustomVariableGroup);
    }
}

Наконец, при сохранении корневого объекта я сохраняю идентификаторы субобъектов:

private static void SetCustomVariableGroupIds(Application application)
{
    application.CustomVariableGroupIds = new List<string>();

    if (application.CustomVariableGroups == null || application.CustomVariableGroups.Count < 1) { return; }

    foreach (CustomVariableGroup group in application.CustomVariableGroups)
    {
        application.CustomVariableGroupIds.Add(group.Id);
    }
}

Надеюсь, это поможет. Это позволяет сохранять модель предметной области "чистой", IMO. Сущности могут содержать ссылки на другие сущности, а не только денормализованные версии других сущностей.

Хорошо, и на самом деле, чтобы ответить на ваш вопрос ... После того, как ваш документ загружен, вы можете просто использовать LINQ для запроса субобъектов, поскольку теперь они действительно будут в памяти.

1 голос
/ 29 февраля 2012
Session.Query<Object>.Where(x => x.SubObject.Any(a => a.Name.StartsWith("a"))).ToList();

Я не уверен, что Contains работает, но это поможет вам начать.

...