Suppose you have the next class. It contains the systems in which the agent has worked
public class AgentHistory
{
public ObjectId Id { get; set; }
public Guid SystemId { get; set; }
public Guid CampaignId { get; set; }
public List<Agent> Agents { get; set; }
}
Now when I get a new agent I do the next thing:
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;
}
And the next method in repository:
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 );
}
I get the next exception .NET type Riverdale.Domain.BO.Agent cannot be mapped to a BsonValue. What am I doing wrong? What is the right approach to updating embedded collections?
Here is a simpler console app which throws(just as a demo):
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);
}
}
You don't have to be so verbose:
BsonValue.Create()
andBsonArray.Create
should not be required.In fact, the latter is the cause of your problem:
BsonArray.Create
creates arrays of value types. You need an array of objects, however. If you take a look at the available overloads ofBsonArray.Create
, I guess you'll be invokingBsonArray.Create(IEnumerable)
, which is not desirable.Have you tried to simply use
instead?
In JSON, the difference looks like this:
For example,
Simple Array:
[ "mongodb", "awesomness", ... ]
Array of Objects:
[ { userId: 2314234, comment: "Foo" }, { ... }, ... ]