Skip to main content
 首页 » 编程设计

c#之mongoDB: C# driver V2 如何更新嵌套集合中的项目

2024年04月30日32jackei

我有以下类设计:

public class UserDayStore 
{ 
    public Guid Id { get; set; } 
    public string UserName { get; set; } 
    public string Password { get; set; } 
    public DateTime EndOfSubscription { get; set; } 
    public bool active { get; internal set; } 
    public DateTime LastModified; 
 
    public List<DbDayRecord>  Days { get; set; } 
} 

与

public class DbDayRecord 
{ 
    public Guid StoreId { get; set; } 
    public DateTime LastModified { get; set; } 
    public DateTime DateOfDay { get; set; } 
 
    public String Quote { get; set; } 
 
} 

添加 UserDayStore 没有问题,也可以将嵌套项添加到 List<Days>没关系。当我尝试更新 DayRecord 时,更新已完成,正如我在 Robomongo 中看到的那样。但是,当我尝试在此之后在 UserStore 集合中搜索文档时,我得到了这个异常:

System.FormatException

An error occurred while deserializing the Days property of class QuoteMyDayServer.ServerLogic.UserDayStore: Cannot deserialize a 'List' from BsonType 'Document'.

bei MongoDB.Driver.Linq.MongoQueryProviderImpl1.Execute(Expression expression) bei MongoDB.Driver.Linq.MongoQueryProviderImpl1.Execute[TResult](Expression expression) bei System.Linq.Queryable.First[TSource](IQueryable1 source) bei QuoteMyDayServer.ServerLogic.QuoteDatabase.<SetUserState>d__10.MoveNext() in C:\Entwicklung\Apps\QuoteMyDay\Server\QuoteMyDayServer\QuoteMyDayServer\ServerLogic\QuoteDatabase.cs:Zeile 147. --- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde --- bei System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) bei System.Runtime.CompilerServices.TaskAwaiter1.GetResult() bei NancyTests.MongoTests.d__8.MoveNext() in C:\Entwicklung\Apps\QuoteMyDay\Server\QuoteMyDayServer\NancyTests\MongoTests.cs:Zeile 148. --- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde --- bei System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) bei Xunit.Sdk.TestInvoker`1.<>c__DisplayClass46_1.<b__1>d.MoveNext() in C:\BuildAgent\work\cb37e9acf085d108\src\xunit.execution\Sdk\Frameworks\Runners\TestInvoker.cs:Zeile 227. --- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde --- bei System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) bei Xunit.Sdk.ExecutionTimer.d__4.MoveNext() in C:\BuildAgent\work\cb37e9acf085d108\src\xunit.execution\Sdk\Frameworks\ExecutionTimer.cs:Zeile 48. --- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde --- bei System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) bei Xunit.Sdk.ExceptionAggregator.d__9.MoveNext() in C:\BuildAgent\work\cb37e9acf085d108\src\xunit.core\Sdk\ExceptionAggregator.cs:Zeile 90.

System.FormatException

Cannot deserialize a 'List' from BsonType 'Document'.

bei MongoDB.Bson.Serialization.Serializers.EnumerableSerializerBase2.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) bei MongoDB.Bson.Serialization.Serializers.SerializerBase1.MongoDB.Bson.Serialization.IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) bei MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize(IBsonSerializer serializer, BsonDeserializationContext context) bei MongoDB.Bson.Serialization.BsonClassMapSerializer`1.DeserializeMemberValue(BsonDeserializationContext context, BsonMemberMap memberMap)

如果存在具有相同“DateOfDay”的 DayRecord,这是更新 DayRecord 的方法,否则它将插入一个新的 DayRecord。

    public async Task<bool> UpdateDayRecord(Guid storeID, DbDayRecord dayRecord) 
    { 
        var stores = GetUserStores(); 
 
        var builder = Builders<UserDayStore>.Filter; 
        var filter = builder.Eq("Id", storeID); 
        var result = await stores.FindAsync(filter); 
 
        if (!await result.AnyAsync()) // Check is a Store with that Id exists 
        { 
            return false; 
        } 
        dayRecord.StoreId = storeID; 
 
        filter =  builder.ElemMatch("Days", Builders<DbDayRecord>.Filter.Eq("DateOfDay", dayRecord.DateOfDay)); 
        result = await stores.FindAsync(filter); 
 
 
        if (await result.AnyAsync()) 
        { 
 
            var update = Builders<UserDayStore>.Update.Set("Days", dayRecord).CurrentDate("LastModified"); 
 
            var updateResult = await stores.UpdateOneAsync(filter, update); 
 
            return (updateResult.ModifiedCount == 1); 
        } 
        else 
        { 
 
            filter = Builders<UserDayStore>.Filter.Eq("Id", storeID); 
            var update = Builders<UserDayStore>.Update.AddToSet("Days", dayRecord).CurrentDate("LastModified"); 
 
            var updateResult = await stores.UpdateOneAsync(filter, update); 
 
            return (updateResult.ModifiedCount == 1); 
        } 
    } 

调用该方法并更新现有的 DayRecord 后,我在尝试访问 UserDayStore 时遇到上述异常:

    public async Task<Guid> GetStoreId (string username) 
    {  
        var stores = GetUserStores(); 
 
        var filter = Builders<UserDayStore>.Filter.Eq("UserName", username); 
 
        var result = await stores.FindAsync(filter); 
 
        return result.First().Id; 
    } 

它在 FindAsync 调用中失败。

这是更新后的 JSON 文档的样子

{ 
    "_id" : LUUID("e858f1cc-c81d-7244-b8a0-8beec3c8e10d"), 
    "LastModified" : ISODate("2016-04-23T10:43:17.293Z"), 
    "UserName" : "TestUser", 
    "Password" : "4242", 
    "EndOfSubscription" : ISODate("2016-06-22T22:00:00.000Z"), 
    "active" : true, 
    "Days" : { 
        "StoreId" : LUUID("e858f1cc-c81d-7244-b8a0-8beec3c8e10d"), 
        "LastModified" : ISODate("2016-04-24T00:00:00.000Z"), 
        "DateOfDay" : ISODate("2016-04-23T00:00:00.000Z"), 
        "Quote" : "Testquote1" 
    } 
} 

请您参考如下方法:

我认为您的问题是您的 Update 语句在一种情况下使用 Set 而在另一种情况下使用 AddToSet。 AddToSet是基于数组的操作,Set直接赋值。您应该在这两种情况下使用 AddToSet 以确保数组存在于 MongoDB 中。

FormatException 是因为我们期待一个数组(因为类型是列表),而不是我们得到一个文档。