UpdateOneAsync 不支持表达式树
Expression tree is not supported on UpdateOneAsync
调用 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:
The expression tree is not supported: {document}{RemoteBoard}{apps}.SingleOrDefault(app => (app.appname == "eACM")).objects.SingleOrDefault(model => (model.name == "tag")).config_docs
我感觉我使用 LINQ 关键字的方式不对,或者 MongoDb 不支持的方式,但很难准确判断问题出在哪里。
我无法对堆栈跟踪进行任何处理:
at MongoDB.Driver.Linq.Processors.EmbeddedPipeline.EmbeddedPipelineBinder.BindNonMethodCall(Expression node)
at MongoDB.Driver.Linq.Processors.PipelineBinderBase1.BindPipeline(Expression node)
at MongoDB.Driver.Linq.Processors.PipelineBinderBase
1.BindMethodCall(MethodCallExpression node)
at MongoDB.Driver.Linq.Processors.EmbeddedPipeline.EmbeddedPipelineBinder.Bind(Expression node, IBindingContext parent)
at MongoDB.Driver.Linq.Processors.SerializationBinder.VisitMethodCall(MethodCallExpression node)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at MongoDB.Driver.Linq.Processors.SerializationBinder.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
at MongoDB.Driver.Linq.Processors.SerializationBinder.VisitBinary(BinaryExpression node)
at System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor)
at MongoDB.Driver.Linq.Processors.SerializationBinder.Visit(Expression node)
at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate[TDocument](Expression1 predicate, IBsonSerializer
1 parameterSerializer, IBsonSerializerRegistry serializerRegistry)
at MongoDB.Driver.MongoCollectionImpl1.ConvertWriteModelToWriteRequest(WriteModel
1 model, Int32 index)
at System.Linq.Enumerable.SelectIterator[TSource,TResult](IEnumerable1 source, Func
3 selector)+MoveNext()
at System.Collections.Generic.List1.AddEnumerable(IEnumerable
1 enumerable)
at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)
at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation..ctor(CollectionNamespace collectionNamespace, IEnumerable
1 requests, MessageEncoderSettings messageEncoderSettings)
at MongoDB.Driver.MongoCollectionImpl1.CreateBulkWriteOperation(IEnumerable
1 requests, BulkWriteOptions options)
at MongoDB.Driver.MongoCollectionImpl1.BulkWriteAsync(IClientSessionHandle session, IEnumerable
1 requests, BulkWriteOptions options, CancellationToken cancellationToken)
at MongoDB.Driver.MongoCollectionImpl1.UsingImplicitSessionAsync[TResult](Func
2 funcAsync, CancellationToken cancellationToken)
at MongoDB.Driver.MongoCollectionBase1.UpdateOneAsync(FilterDefinition
1 filter, UpdateDefinition1 update, UpdateOptions options, Func
3 bulkWriteAsync)
at WebApplication.Services.ConcreteDatabase.UpdateDocument[T](String sCollectionName, Expression1 filter, UpdateDefinition
1 update, Boolean bUpsert, CancellationToken cancellationToken) in C:\GIT\app-manager\APIMM\ServerLevelConfiguration\WebApplication\Services\ConcreteDatabase.cs:line 131
at WebApplication.Services.SyncBoardDatabaseBackgroundService.UpdateDbOnSyncServerToBoardUpdate(CancellationToken cancel, BsonDocument bsonDocConfigurationToUpdate, DateTime dtUpdated, String sId, Int32 iObjectId, String sAppName, String sModelName) in C:\GIT\app-manager\APIMM\ServerLevelConfiguration\WebApplication\Services\SyncBoardDatabaseBackgroundService.cs:line 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; }
}
当您尝试构建 Update
语句时,问题就开始了。正如您可能知道的那样,作为索引传递的 -1
将是 to the $ positional operator. The documentation 表示
The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value
此外,您正在尝试使用 SingleOrDefault
构建过滤条件,而 .NET MongoDB 驱动程序无法将其转换为任何 MongoDB 查询语法运算符。
如何解决?
您可以尝试使用 positional filtered operator 语法而不是使用位置运算符。
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);
调用 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:
The expression tree is not supported: {document}{RemoteBoard}{apps}.SingleOrDefault(app => (app.appname == "eACM")).objects.SingleOrDefault(model => (model.name == "tag")).config_docs
我感觉我使用 LINQ 关键字的方式不对,或者 MongoDb 不支持的方式,但很难准确判断问题出在哪里。
我无法对堆栈跟踪进行任何处理:
at MongoDB.Driver.Linq.Processors.EmbeddedPipeline.EmbeddedPipelineBinder.BindNonMethodCall(Expression node) at MongoDB.Driver.Linq.Processors.PipelineBinderBase
1.BindPipeline(Expression node) at MongoDB.Driver.Linq.Processors.PipelineBinderBase
1.BindMethodCall(MethodCallExpression node) at MongoDB.Driver.Linq.Processors.EmbeddedPipeline.EmbeddedPipelineBinder.Bind(Expression node, IBindingContext parent) at MongoDB.Driver.Linq.Processors.SerializationBinder.VisitMethodCall(MethodCallExpression node) at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor) at MongoDB.Driver.Linq.Processors.SerializationBinder.Visit(Expression node) at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node) at MongoDB.Driver.Linq.Processors.SerializationBinder.VisitBinary(BinaryExpression node) at System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor) at MongoDB.Driver.Linq.Processors.SerializationBinder.Visit(Expression node) at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate[TDocument](Expression1 predicate, IBsonSerializer
1 parameterSerializer, IBsonSerializerRegistry serializerRegistry) at MongoDB.Driver.MongoCollectionImpl1.ConvertWriteModelToWriteRequest(WriteModel
1 model, Int32 index) at System.Linq.Enumerable.SelectIterator[TSource,TResult](IEnumerable1 source, Func
3 selector)+MoveNext() at System.Collections.Generic.List1.AddEnumerable(IEnumerable
1 enumerable) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation..ctor(CollectionNamespace collectionNamespace, IEnumerable
1 requests, MessageEncoderSettings messageEncoderSettings) at MongoDB.Driver.MongoCollectionImpl1.CreateBulkWriteOperation(IEnumerable
1 requests, BulkWriteOptions options) at MongoDB.Driver.MongoCollectionImpl1.BulkWriteAsync(IClientSessionHandle session, IEnumerable
1 requests, BulkWriteOptions options, CancellationToken cancellationToken) at MongoDB.Driver.MongoCollectionImpl1.UsingImplicitSessionAsync[TResult](Func
2 funcAsync, CancellationToken cancellationToken) at MongoDB.Driver.MongoCollectionBase1.UpdateOneAsync(FilterDefinition
1 filter, UpdateDefinition1 update, UpdateOptions options, Func
3 bulkWriteAsync) at WebApplication.Services.ConcreteDatabase.UpdateDocument[T](String sCollectionName, Expression1 filter, UpdateDefinition
1 update, Boolean bUpsert, CancellationToken cancellationToken) in C:\GIT\app-manager\APIMM\ServerLevelConfiguration\WebApplication\Services\ConcreteDatabase.cs:line 131 at WebApplication.Services.SyncBoardDatabaseBackgroundService.UpdateDbOnSyncServerToBoardUpdate(CancellationToken cancel, BsonDocument bsonDocConfigurationToUpdate, DateTime dtUpdated, String sId, Int32 iObjectId, String sAppName, String sModelName) in C:\GIT\app-manager\APIMM\ServerLevelConfiguration\WebApplication\Services\SyncBoardDatabaseBackgroundService.cs:line 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; }
}
当您尝试构建 Update
语句时,问题就开始了。正如您可能知道的那样,作为索引传递的 -1
将是
The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value
此外,您正在尝试使用 SingleOrDefault
构建过滤条件,而 .NET MongoDB 驱动程序无法将其转换为任何 MongoDB 查询语法运算符。
如何解决?
您可以尝试使用 positional filtered operator 语法而不是使用位置运算符。
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);