簡體   English   中英

如何使用 C# MongoDb 驅動程序更新深度嵌套數組中的“類型安全”字段?

[英]How to update a field “type-safe” in a deeply nested array with C# MongoDb driver?

我正在嘗試更新深度嵌套數組中的各個字段。

    public class Maker
    {
        public int Id { get; set; }
        public List<Vehicle> Vehicles { get; set; }
    }

    public class Vehicle
    {
        public int Id { get; set; }
        public int Price { get; set; }
        public List<Part> Parts { get; set; }
    }

    public class Part
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

更新 1 級數組中的字段就像一個魅力。 更新 2 級數組中的字段失敗。

 public void UpdateNestedArrayFields()
    {
        var client = new MongoClient();
        var db = client.GetDatabase("test");
        var makers = db.GetCollection<Maker>("makers");

        // Create a maker and add a vehicle
        var newPart = new Part() { Id = 34, Name = "Wheel" };
        var newVehicle = new Vehicle() { Id = 17, Price = 1000, Parts = new List<Part>() { newPart } };
        var newMaker = new Maker() { Id = 5, Vehicles = new List<Vehicle>() { newVehicle } };

        // Update vehicle's price (WORKS)
        makers.FindOneAndUpdate(
            m => m.Id == newMaker.Id && m.Vehicles.Any(v => v.Id == newVehicle.Id),
            Builders<Maker>.Update.Set(m => m.Vehicles[-1].Price, 2000));

        // Update part's name (**FAILS**)
        makers.FindOneAndUpdate(
            m => m.Id == newMaker.Id && m.Vehicles.Single(v => v.Id == newVehicle.Id).Parts.Any(p=> p.Id == newPart.Id),
            Builders<Maker>.Update.Set(m => m.Vehicles[-1].Parts[-1].Name, "Tire"));
    }       

我知道不支持多個位置運算符,所以我的最后一行 (m.Vehicles[-1].Parts[-1].Name) 有點廢話。

顯然我不是唯一一個遇到這個問題的人,我找到了類似這樣那樣的不同解決方案。 但是,它們都不是類型安全的 生成的代碼非常丑陋且容易出錯。

所以我想知道:有沒有辦法重新設計我的代碼,使其類型安全?

我正在使用 MongoDb 4.0.9 和 C# 驅動程序 2.11.5。

編輯(01-11-2020):對於任何感興趣的人,我發現 Massimiliano Kraus 的這個非常好的擴展,它有點過時(2017 年),但仍在工作,結果證明是一個巨大的幫助。 謝謝你,馬西米利亞諾! MongoDB.DeepUpdater.CSharp

為了像這樣更新嵌套的 arrays,您需要使用 mongodb 的陣列過濾器功能。

所需的 mongo 查詢是這樣的:

db.Maker.update(
    {
        "_id": 5
    },
    {
        $set: { 'Vehicles.$[v].Parts.$[p].Name': 'Tyre' }
    },
    {
        arrayFilters: [
            { 'v._id': { $eq: 17 } },
            { 'p._id': { $eq: 34 } }
        ]
    }
)

c# 驅動程序無法以強類型方式生成上述內容。 查看這篇文章,了解運行上述高級查詢的替代半類型解決方案。

還有一個類型化嵌套數組更新的其他可能且類型更多的版本。 它沒有完全輸入,但它更接近你的需要。

它也使用ArrayFilters但以更多類型的方式

此代碼直接來自我正在處理的應用程序。

var filter = Builders<EventModel>.Filter.Eq(s => s.Id, eventId);

var settingsPath = @$"{nameof(EventModel.EventLayout)}.{nameof(EventLayoutSetting.Pages)}.$[page].{nameof(Page.Components)}.$[component].{nameof(Component.Settings)}";
var update = Builders<EventModel>.Update.
                     Set(settingsPath, settings);

var dbResult = await eventsCollection.UpdateOneAsync(filter, update, new UpdateOptions 
            {
                ArrayFilters = new List<ArrayFilterDefinition> 
                {
                    new BsonDocumentArrayFilterDefinition<BsonDocument> (new BsonDocument($"page.{nameof(Page.PageId)}",pageId)),
                    new BsonDocumentArrayFilterDefinition<BsonDocument> (new BsonDocument($"component.{nameof(Component.ComponentId)}",componentId))
                }
            });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM