Модели с возможностью поиска - PullRequest
1 голос
/ 07 ноября 2019

В настоящее время я работаю над проектом, использующим MongoDB в качестве базы данных, и у меня возникли некоторые вопросы о том, как решить проблему наличия модели, содержащей некоторые идентификаторы для иностранных документов, и поиска их без необходимости обращаться к BsonDocument.

Изначально у меня был этот (урезанный) класс модели:

public class TestSession
{
    [BsonId]
    public ObjectId Id { get; set; }

    [BsonElement("taskId")]
    public ObjectId? TaskId { get; set; }
}

Иногда мне нужен бетон TaskConfiguration, на который ссылается TaskId.
В этом случае я использую $lookup чтобы решить это.

Сначала я представил нового члена для хранения конкретного экземпляра TaskConfiguration, изменив класс моей модели на:

public class TestSession
{
    [BsonId]
    public ObjectId Id { get; set; }

    [BsonElement("taskId")]
    public ObjectId? TaskId { get; set; }

    [BsonIgnore]
    public TaskConfiguration Task { get; set; }
}

Затем я понял, что агрегация не может десериализовать искомый иразмотал Task значение, я думаю, из-за BsonIgnore.
Я не мог найти никаких вариантов, чтобы переопределить это, и я не мог придумать никакого другого решения для этого.

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

Полученные классывыглядят так:

public class TestSessionModel
{
    [BsonId]
    public ObjectId Id { get; set; }

    [BsonElement("taskId")]
    public ObjectId? TaskId { get; set; }
}

public class TestSession : TestSessionModel
{
    [BsonElement("task")]
    public TaskConfiguration Task { get; set; }
}

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

Мой вопрос сейчас заключается в том, является ли мой нынешний подход действительно подходом в этом случае, или есть ли лучшие / более безопасные альтернативы?

1 Ответ

1 голос
/ 08 ноября 2019

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

var res = collection.AsQueryable()
                    .Where(t => t.Id == session.Id)
                    .Join(
                        foreignColl.AsQueryable(), // foreign collection
                        s => s.TaskId,             // local field
                        c => c.Id,                 // foreign field
                        (s, c) => new TestSession  // projection
                        {
                            Id = s.Id,
                            Name = s.Name,
                            TaskId = s.TaskId,
                            Task = c
                        })
                    .Single();

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

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Entities;
using MongoDB.Entities.Core;
using System.Linq;

namespace StackOverflow
{
    public class TestSession : Entity
    {
        public string Name { get; set; }

        [BsonRepresentation(BsonType.ObjectId)]
        public string TaskID { get; set; }

        [BsonIgnore]
        public TaskConfiguration Task { get; set; }
    }

    public class TaskConfiguration : Entity
    {
        public int NumOfIterations { get; set; }
    }

    public static class Program
    {
        private static void Main()
        {
            new DB("test");

            var task = new TaskConfiguration { NumOfIterations = 10 };
            task.Save();

            var session = new TestSession { Name = "This is a test session", TaskID = task.ID };
            session.Save();

            var res = DB.Queryable<TestSession>()
                        .Where(t => t.ID == session.ID)
                        .Join(
                            DB.Queryable<TaskConfiguration>(),
                            s => s.TaskID,
                            c => c.ID,
                            (s, c) => new TestSession
                            {
                                ID = s.ID,
                                Name = s.Name,
                                TaskID = s.TaskID,
                                Task = c
                            })
                        .Single();
        }
    }
}
...