Дерево выражений не поддерживается в UpdateOneAsync - PullRequest
1 голос
/ 09 апреля 2019

При вызове UpdateOneAsync с помощью этой оболочки:

    public async Task<UpdateResult> UpdateDocument<T>(
        string sCollectionName, 
        Expression<Func<T, bool>> filter, 
        UpdateDefinition<T> update,
        bool bUpsert,
        System.Threading.CancellationToken cancellationToken
        )
    {
        IMongoDatabase db = _mongoClient.GetDatabase(_optionsMonitor.CurrentValue.databasename);

        IMongoCollection<T> collection = db.GetCollection<T>(sCollectionName);

        return await collection.UpdateOneAsync<T>(filter, update, new UpdateOptions() { IsUpsert = bUpsert }, cancellationToken);
    }

Примерно так:

private async Task<Models.Errors> UpdateDbOnSyncServerToBoardUpdate(
        CancellationToken cancel,
        MongoDB.Bson.BsonDocument bsonDocConfigurationToUpdate,
        DateTime dtUpdated,
        string sId,
        int iObjectId,
        string sAppName,
        string sModelName
        )
    {
        MongoDB.Driver.UpdateResult updateResult = null;
        Models.Errors errors = null;

        try
        {
            updateResult = await _db.UpdateDocument<Models.Database.NodeBoardModel>(
                Constants.NodeBoardCollectionName,
                node => node.Id == sId && 
                node.RemoteBoard.apps.SingleOrDefault(
                    app => app.appname == sAppName).objects.
                    SingleOrDefault(model => model.name == sModelName).config_docs.
                    Any(config => config.config_id == iObjectId),
                MongoDB.Driver.Builders<Models.Database.NodeBoardModel>.Update.
                Set(
                    node => node.RemoteBoard.apps[-1].objects[-1].config_docs[-1].config_doc, bsonDocConfigurationToUpdate).
                Set(
                    node => node.RemoteBoard.apps[-1].objects[-1].config_docs[-1].config_dt, dtUpdated),
                false,
                cancel
                );

Я получаю исключение NotSupportedException:

Дерево выраженийне поддерживается: {document} {RemoteBoard} {apps} .SingleOrDefault (app => (app.appname == "eACM")). objects.SingleOrDefault (model => (model.name == "tag")). config_docs

Я чувствую, что использую ключевое слово LINQ неправильно или не поддерживается MongoDb, но трудно точно сказать, в чем проблема.

Я не могусделать что-либо из трассировки стека:

в MongoDB.Driver.Linq.Processors.EmbeddedPipeline.EmbeddedPipelineBinder.BindNonMethodCall (узел выражений) в MongoDB.Driver.Linq.Processors.PipelineBinderBase 1.BindPipeline(Expression node) at MongoDB.Driver.Linq.Processors.PipelineBinderBase 1.Bind(Узел MethodCallExpression) в MongoDB.Driver.Linq.Processors.EmbeddedPipeline.EmbeddedPipelineBinder.Bind (узел выражения, родитель IBindingContext) в MongoDB.Driver.Linq.Processors.SerializationBinder.VisitMethodCall (MethodCallExpression node) в System.Linq.Expressions.MethodCallExpression.Accept (посетитель ExpressionVisitor) в MongoDB.Driver.Linq.Processors.SerializationBinder.Visit (узел Expression) в System.Linq.Expressions.ExpressionVisitor.VisitBinary (узел BinaryExpression.D в Mongol.Linq.Processors.SerializationBinder.VisitBinary (узел BinaryExpression) в System.Linq.Expressions.BinaryExpression.Accept (посетитель ExpressionVisitor) в MongoDB.Driver.Linq.Processors.SerializationBinder.Visit (узел выражения) в MongoDB.DriversinLators..PredicateTranslator.Translate [TDocument] (Expression 1 predicate, IBsonSerializer 1 параметрSerializer, IBsonSerializerRegistry serializerRegistry) в MongoDB.Driver.MongoCollectionImpl 1.ConvertWriteModelToWriteRequest(WriteModel 1 модель, Int32-индекс) в System.Linq.Enumerable.SelectIterator [TSource, 1021] [10, IE]* 3 селектора) + MoveNext () в System.Collections.Generic.List 1.AddEnumerable(IEnumerable 1 перечислимый) в System.Linq.Enumerable.ToList [TSource] (IEnumerable 1 source) at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation..ctor(CollectionNamespace collectionNamespace, IEnumerable 1 запросов, MessageEncoderSettings messageEncoderSettings) в MongoDB.Driver.MngoCollectionImpl 1.CreateBulkWriteOperation(IEnumerable 1 запросов, параметры BulkWriteOptions) в MongoDB.Driver.MongoCollectionImpl 1.BulkWriteAsync(IClientSessionHandle session, IEnumerable 1 запросов, параметры BulkWriteOptions, CancellationToken cancellationToken) в MongoDB.Driver.Фильтр 1027 * 1, UpdateDefinition 1 update, UpdateOptions options, Func 3 bulkWriteAsync) в WebApplication.Services.ConcreteDatabase.UpdateDocument [T] (String sCollectionName, Expression 1 filter, UpdateDefinition 1, Boolean bUpsert, CancellationToken cancellationToken) в C: \ GIT \ app-managerAPIMM \ ServerLevelConfiguration \ WebApplication \ Services \ ConcreteDatabase.cs: линии 131 в WebApplication.Services.SyncBoardDatabaseBackgroundService.UpdateDbOnSyncServerToBoardUpdate (CancellationToken отменяют, BsonDocument bsonDocConfigurationToUpdate, DateTime dtUpdated Строковый Sid, Int32 iObjectId Строковый sAppName, String sModelName) в C: \ GIT \приложение-менеджер \ APIMM \ ServerLevelConfiguration \ WebApplication \ Services \ SyncBoardDatabaseBackgroundService.cs: линия 353

Классы моделей:

public class NodeBoardModel
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    [BsonElement]
    public NodeBoardRemoteModel RemoteBoard { get; set; }
}

public class NodeBoardRemoteModel
{
    [BsonElement]
    public List<NodeBoardAppModel> apps { get; set; }
}

public class NodeBoardAppModel
{
    [BsonElement]
    public string appname { get; set; }

    [BsonElement]
    public List<NodeBoardObjectModel> objects { get; set; }
}

public class NodeBoardObjectModel
{
    [BsonElement]
    public string name { get; set; }

    [BsonElement]
    public List<NodeBoardObjectConfigurationModel> config_docs { get; set; }
}

public class NodeBoardObjectConfigurationModel
{
    [BsonElement]
    public BsonDocument config_doc { get; set; }

    [BsonElement]
    public DateTime config_dt { get; set; }

    [BsonElement]
    public int config_id { get; set; }
}

1 Ответ

2 голосов
/ 09 апреля 2019

Проблема начинается, когда вы пытаетесь построить оператор Update.Как вы, вероятно, знаете, -1, переданное в качестве индекса, будет переведено в позиционный оператор $ .Документация гласит, что

Позиционный оператор $ не может использоваться для запросов, которые пересекают более одного массива, таких как запросы, пересекающие массивы, вложенные в другиемассивов, потому что замена для $ placeholder представляет собой одно значение

Кроме того, вы пытаетесь построить условие фильтрации с помощью SingleOrDefault, а драйвер .NET MongoDB не может преобразовать это в любой MongoDBоператор синтаксиса запроса.

Как это исправить?

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

var filter = Builders<NodeBoardModel>.Filter.Eq(f => f.Id, sId);
var update = Builders<NodeBoardModel>.Update.Set("RemoteBoard.apps.$[app].objects.$[object].config_docs.$[configdoc].config_dt", dtUpdated);

var arrayFilters = new List<ArrayFilterDefinition>();
ArrayFilterDefinition<BsonDocument> appFilter = new BsonDocument("app.appname", new BsonDocument("$eq", sAppName));
ArrayFilterDefinition<BsonDocument> objectFilter = new BsonDocument("object.name", new BsonDocument("$eq", sModelName));
ArrayFilterDefinition<BsonDocument> configDocFilter = new BsonDocument("configdoc.config_id", new BsonDocument("$eq", iObjectId));

arrayFilters.AddRange(new[] { appFilter, objectFilter, configDocFilter });

var updateOptions = new UpdateOptions { ArrayFilters = arrayFilters };

var res = Col.UpdateOne(filter, update, updateOptions);
...