如何修复{document} .Id不支持错误

时间:2017-11-22 13:19:11

标签: c# mongodb

我的mongo域对象中有继承:

public abstract class Entity : IEntity
{
   [BsonId]     
   [BsonRepresentation(BsonType.ObjectId)]
   public string Id { get; set; }
   [BsonIgnore]
   public abstract string CollectionName { get; }
}

[BsonDiscriminator(Required = true)]
[BsonKnownTypes(typeof(Sub1), typeof(Sub2), typeof(Sub3))]
public class Main:Entity
{
   public string Name {get; set;}
   public string Address {get; set;}
}

[BsonDiscriminator(SubType.Sub1)]
public class Sub1: Main, IWorkAttached
{}

[BsonDiscriminator(SubType.Sub2)]
public class Sub2: Main, IWorkAttached
{}

[BsonDiscriminator(SubType.Sub3)]
public class Sub3: Main
{}

public interface IWorkAttached
{
   public string WorkId {get; set;}
}

我有更新实体的方法:

public void Update(IWorkAttached entity)
{
   var col = _db.GetCollection<IWorkAttached>("ColName");
   var updDefinition = Builders<IWorkAttached>.Update
      .Set(t => t.Name, entity.Name)
      .Set(t => t.Address, entity.Address)
      .Set(t => t.WorkId, entity.WorkId) // interface property

   col.UpdateOne(t => t.Id == entity.Id, updDefinition)
}

我们的想法是有一种方法可以更新两种类型的实体(Sub1Sub2)然后我可以将它用于两个实体:

var sub1 = new Sub1 {...};
var sub2 = new Sub2 {...};

Update(sub1);
Update(sub2);

但是,它不起作用。我得到以下异常:

  

{document} .Id不受支持。

如果我在Update方法中使用特定类型而不是接口,那么一切正常。是否有可能以这种方式使用mongo驱动程序?

堆栈跟踪:

   at MongoDB.Driver.Linq.Translators.PredicateTranslator.GetFieldExpression(Expression expression)
   at MongoDB.Driver.Linq.Translators.PredicateTranslator.TranslateComparison(Expression variableExpression, ExpressionType operatorType, ConstantExpression constantExpression)
   at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate(Expression node)
   at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate(Expression node, IBsonSerializerRegistry serializerRegistry)
   at MongoDB.Driver.MongoCollectionImpl`1.ConvertWriteModelToWriteRequest(WriteModel`1 model, Int32 index)
   at System.Linq.Enumerable.<SelectIterator>d__154`2.MoveNext()
   at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation.BatchHelper.<FindOrderedRuns>d__8.MoveNext()
   at MongoDB.Driver.Core.Misc.ReadAheadEnumerable`1.ReadAheadEnumerator.MoveNext()
   at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation.BatchHelper.<GetBatches>d__6.MoveNext()
   at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation.<ExecuteAsync>d__39.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at MongoDB.Driver.OperationExecutor.<ExecuteWriteOperationAsync>d__3`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at MongoDB.Driver.MongoCollectionImpl`1.<ExecuteWriteOperationAsync>d__62`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at MongoDB.Driver.MongoCollectionImpl`1.<BulkWriteAsync>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at MongoDB.Driver.MongoCollectionBase`1.<UpdateOneAsync>d__47.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

6 个答案:

答案 0 :(得分:1)

我遇到了同样的问题。在MongoDB代码中调试之后,我看到在使用接口而不是特定类型时应用了不同的序列化器。在这种情况下, DiscriminatedInterfaceSerializer 用作接口的序列化器,而 BsonClassMapSerializer 用于特定类型。

使用此接口的序列化程序,实现类的类映射不链接到接口。因此,我不知道Id是bson id字段,应该映射到&#39; _id&#39;键。这就是引发异常的原因。

对我有用的解决方案是使用 ImpliedImplementationInterfaceSerializer

[BsonSerializer(typeof(ImpliedImplementationInterfaceSerializer<IEntity, Entity>))]
public interface IEntity 
{ 
   // snip...
}

此属性注册序列化程序并定义为IEntity使用Entity的bson类映射,以便正确映射Id属性。 感谢@Robert Baker在答案中找到了这个解决方案:Deserialize object as an interface with MongoDB C# Driver

答案 1 :(得分:1)

我在项目中遇到了同样的问题,但是在另一种方法中,我的解决方案是编写完整的过滤器,而不是使用t => t.Id == entity.Id

var filter = Builders<Account>.Filter.Eq("_id", new ObjectId(accountId));
account = _accountsCollection.Find(filter).First();

答案 2 :(得分:1)

确保您的媒体资源中有 date price priceEUR 1 2019-12-21 140 155.358 2 2019-10-25 91 100.7734 3 2019-10-24 91 100.7643 4 2019-12-13 70 77.56 ,这是我的问题。

答案 3 :(得分:0)

仅供参考,此处同样的问题是由于Lambda表达式中使用的数据类型不受支持或表达式复杂。

var awakenUsers = await _db.Get<DataEntity.UserProfile>(u
    => validInviteeMobs.Contains(u.MobNo)
    && (DateTime.UtcNow - u.LastAccessTime) >= new TimeSpan(72, 0, 0));
  

System.InvalidOperationException:(11/27/2018 05:20:37-{document} {LastAccessTime})不支持。      在MongoDB.Driver.Linq.Translators.PredicateTranslator.GetFieldExpression(表达式表达式)

将其更改为示例后:

var awakenDeadline = DateTime.UtcNow.AddHours(-72);

var awakenUsers = await _db.Get<DataEntity.UserProfile>(u
    => validInviteeMobs.Contains(u.MobNo)
    && u.LastAccessTime <= awakenDeadline);

效果很好

答案 4 :(得分:0)

由于某种原因,当我将结构更改为类时遇到了这个问题,是的,调用类/结构的方法实现了一个接口。通过改回结构来解决它。

答案 5 :(得分:0)

就我而言,我覆盖了 Equals 运算符。 Mongo 不喜欢这样,所以只需将它移到 lambda 中就可以了。 干杯!

public class User : EntityBase
{
    public Guid OrganizationID { get; set; }
    public string UserName { get; set; }
    public string Email { get; set; }

    public override bool Equals(object obj)
    {
        if (obj is User user)
            return this.ID == user.ID
                || string.Equals(this.UserName, user.UserName, StringComparison.InvariantCultureIgnoreCase);
        return false;
    }


}

public async Task<User> SaveUser(User user)
    {
        var repo = _crudRepositoryFactory.Get<User>();
        var exisitngUser = await repo.First(x => x == user);

        if (exisitngUser == null)
        {
            await repo.Create(user);
            return user;
        }
        var res = await repo.Update(user, x => x == user);
        return res.Item2;
    }

我改成

public async Task<User> SaveUser(User user)
    {
        var repo = _crudRepositoryFactory.Get<User>();
        var exisitngUser = await repo.First(x => x.ID == user.ID
            || (x.UserName == user.UserName && x.OrganizationID == user.OrganizationID));

        if (exisitngUser == null)
        {
            await repo.Create(user);
            return user;
        }
        var res = await repo.Update(user, x => x.ID == user.ID
            || (x.UserName == user.UserName && x.OrganizationID == user.OrganizationID));
        return res.Item2;
    }