【问题标题】:Update Embedded document in mongodb using C#使用 C# 更新 mongodb 中的嵌入式文档
【发布时间】:2011-11-11 10:17:40
【问题描述】:

假设你有下一堂课。它包含代理工作的系统

public class AgentHistory
{
    public ObjectId Id { get; set; }
    public Guid SystemId { get; set; }
    public Guid CampaignId { get; set; }
    public List<Agent> Agents { get; set; }
}

现在,当我得到一个新代理时,我会做接下来的事情:

 public override AgentHistory Save(AgentHistory agent)
    {
        if (agent == null)
            throw new ArgumentNullException("agent");
        if (_repository.Exists(agent))
        {
            AgentHistory dbEntity = _repository.FindById(agent.SystemId, agent.CampaignId);
            dbEntity.Agents.AddRange(agent.Agents);
            _repository.UpdateAgentHistory(dbEntity);
        }
        else
        {
            _repository.Save(agent);
        }
        return agent;
    }

以及存储库中的下一个方法:

public void UpdateAgentHistory(AgentHistory updatedEntity)
    {
        QueryComplete query = Query.EQ("_id", BsonValue.Create(updatedEntity.Id));

        MongoCollection.Update(query, Update.Set("Agents", BsonArray.Create(updatedEntity.Agents)), UpdateFlags.None, SafeMode.True );
    }

我得到下一个异常.NET type Riverdale.Domain.BO.Agent cannot be mapped to a BsonValue.我做错了什么?更新嵌入式集合的正确方法是什么?

这是一个更简单的控制台应用程序,它会抛出(仅作为演示):

  public class Agent
    {
        [BsonId]
        public string LocalIdentifier { get; set; }

        public string AgentName { get; set; }
    }

    public class A
    {
        public ObjectId Id { get; set; }
        public Guid SystemId { get; set; }
        public Guid CampaignId { get; set; }
        public Agent[] Agents { get; set; }
    }

    public class AgentHistoryRepository
    {
        public bool Exists(A agentHistory)
        {
            return _mongoCollection.FindOne(BuildIdentityQuery(agentHistory)) != null;
        }

        public void Delete(A agentHistory)
        {
            _mongoCollection.Remove(BuildIdentityQuery(agentHistory));
        }

        public List<string> GetAgentsForASystem(Guid systemGuid)
        {
            QueryComplete query = Query.EQ("SystemId", systemGuid);
            return _mongoCollection.Find(query).SelectMany(x => x.Agents.Select(z => z.AgentName)).Distinct().ToList();
        }

        public List<string> GetAgentsForACampaign(Guid systemGuid, Guid campaignGuid)
        {
            QueryComplete query = Query.EQ("CampaignId", campaignGuid);
            if (systemGuid != Guid.Empty)
                query = Query.And(new[] {query, Query.EQ("SystemId", systemGuid)});
            return _mongoCollection.Find(query).SelectMany(x => x.Agents.Select(z => z.AgentName)).Distinct().ToList();
        }

        public AgentHistoryRepository()
        {
            string connectionString = "mongodb://localhost/Sample";
            var mgsb = new MongoUrlBuilder(connectionString);
            var MongoServer = MongoDB.Driver.MongoServer.Create(mgsb.ToMongoUrl());
            var MongoDatabase = MongoServer.GetDatabase(mgsb.DatabaseName);
            _mongoCollection = MongoDatabase.GetCollection<A>("AgentHistory");
        }


        private MongoCollection<A> _mongoCollection;

        private QueryComplete BuildIdentityQuery(A agentHistory)
        {
            QueryComplete query = Query.And(Query.EQ("SystemId", agentHistory.SystemId),
                                            Query.EQ("CampaignId", agentHistory.CampaignId));
            return query;
        }

    public void Save(A entity)
        {
            _mongoCollection.Insert(entity, SafeMode.True);
        }

        public void UpdateAgents(A entity)
        {
            _mongoCollection.Update(BuildIdentityQuery(entity), Update.Set("Agents", entity.Agents.ToBsonDocument()));
        }
    }

    internal class Program
    {
        public static void Main()
        {

            var objectToSave =  new A {Id = ObjectId.GenerateNewId(), CampaignId=Guid.NewGuid(), SystemId =Guid.NewGuid() ,
                                     Agents = new [] {new Agent{LocalIdentifier="agent", AgentName= "name"}}};

            var repo = new AgentHistoryRepository();
            repo.UpdateAgents(objectToSave);
            objectToSave.Agents = new[] { new Agent { LocalIdentifier = "agent2", AgentName = "name2" } };
            repo.UpdateAgents(objectToSave);
            var objectToSave2 = new A
            {
                Id = ObjectId.GenerateNewId(),
                CampaignId = Guid.NewGuid(),
                SystemId = objectToSave.SystemId,
                Agents = new [] { new Agent { LocalIdentifier = "agent", AgentName = "name" } }
            };
            repo.UpdateAgents(objectToSave2);
            foreach (var agentName in repo.GetAgentsForASystem(objectToSave.SystemId))
                Console.WriteLine(agentName);
        }
    }

【问题讨论】:

  • 你能展示一下代理类吗?
  • 公共类代理 { 公共字符串 LocalIdentifier { get;放; } 公共字符串 AgentName { 获取;放; } }

标签: c# mongodb mongodb-.net-driver


【解决方案1】:

您不必如此冗长:BsonValue.Create()BsonArray.Create 不应该是必需的。

事实上,后者是您的问题的原因:BsonArray.Create 创建了值类型数组。但是,您需要一组对象。如果您查看BsonArray.Create 的可用重载,我猜您将调用BsonArray.Create(IEnumerable),这是不可取的。

你有没有试过简单地使用

MongoCollection.Update(query, Update.Set("Agents", updatedEntity.Agents), ...);

改为?

在 JSON 中,区别如下所示:

值数组:[ val, val, ... ]

对象数组:[ { ... }, { ... }, ... ]

例如,

简单数组:[ "mongodb", "awesomness", ... ]

对象数组:[ { userId: 2314234, comment: "Foo" }, { ... }, ... ]

【讨论】:

  • 它仍然无法映射该类型,无论如何你添加的语法正是我想要的,谢谢
  • 我猜_mongoCollection.Update(BuildIdentityQuery(entity), Update.AddToSetEachWrapped("Agents", entity.Agents), SafeMode.True); 应该可以工作,因为Update.Set(也)不接受任何列表或文件。但是,您不能“重置”列表,您只能添加 删除。或者,只需更新整个对象或将列表包装在自己的对象中,然后使用Update.SetWrapped
  • 酷,它有效。你能解释一下为什么 Update.Set 不接受任何列表或文件吗?
  • 我不知道为什么要这样设计;我假设序列化复杂对象更复杂(即更慢)。它现在的实现方式,它可以保证良好的性能。调用自定义序列化程序等也可能起作用。
  • 有时我会得到像 screencast.com/t/plkzxj2b7Sb7 这样的奇怪结果。无法真正理解其工作背后的机制
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-18
  • 2011-05-21
  • 1970-01-01
  • 2016-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多