I am running a C# app with MongoDB 2.0 driver and ran into the following error when I ran all my tests:
System.InvalidOperationException : Class map for <TopClassName> has been frozen and no further changes are allowed.
System.AggregateException : One or more errors occurred. ----> MongoDB.Bson.BsonException : Unable to find a matching member to provide the value for parameter 'inBed'
However, running every single test one at a time gives no errors. So for some reason the class map is frozen...
Here is what I have (P.S, if you spot something that is way off, let me know):
A hierarchy with 3 abstract classes and one concrete class:
public abstract class BaseEvent
{
[BsonId]
public Guid Id;
public List<int> Data;
public dynamic Condition;
public string TimeStamp;
[BsonConstructor]
protected BaseEvent(List<int> data, dynamic condition)
{
Data = data;
Condition = condition;
TimeStamp = DateTime.Now.ToString();
Id = Guid.NewGuid();
}
}
public abstract class Basic : BaseEvent
{
[BsonConstructor]
protected Basic(List<int> data, bool condition) : base(data, condition)
{}
}
public abstract class BedEvent : Basic
{
[BsonConstructor]
protected BedEvent(List<int> data, bool inBed) : base(data, inBed)
{}
}
public class DummyBed : BedEvent
{
[BsonConstructor]
public DummyBed(List<int> data, bool inBed) : base(data, inBed)
{
RegisterHelper.RegisterNewClass(this);
}
}
The RegisterHelper
is a singleton that is kept alive, more on that a bit down. The constructor of my app will register the top class BaseEvent
:
var baseEvent = BsonClassMap.RegisterClassMap<BaseEvent>(cm =>
{
cm.SetIsRootClass(true);
cm.MapMember(c => c.Data);
cm.MapMember(c => c.Condition);
cm.MapMember(c => c.TimeStamp);
cm.MapIdMember(c => c.Id).SetIdGenerator(GuidGenerator.Instance);
});
RegisterHelper.ClassRegister.Add(baseEvent);
For each concrete class, as the DummyBed
, I call a homebrewed (and likely to be the cause of the problem) register method.
This method looks at all the baseclasses and, if not found on a list, adds them recursively to all classes above them self, much like this:
public static void RegisterNewClass<T>(T theObject)
{
...
if (!lvl3Found)
{
var lvl3Map = new BsonClassMap(lvl3Type); //lvl3Type is a System.Type
lvl3Map.SetDiscriminator(lvl3Type.Name);
ClassRegister.Add(lvl3Map);
BsonClassMap.RegisterClassMap(lvl3Map);
lvl4Map.AddKnownType(lvl3Type);
}
...
}
Running tests:
[TestFixture]
public class InsertEventIntoDatabaseTest
{
private EventDatabase _eventDatabase;
[SetUp]
public void Setup()
{
_eventDatabase = new EventDatabase();
_eventDatabase.EmptyDatabase(); //Clean slate each time
}
[TearDown]
public void TearDown()
{
_eventDatabase = null;
}
[Test]
public void GetSubTypeDocument_FindDummyBed_Success()
{
var bed = new DummyBed(new List<int>() { 1, 2, 3}, true);
_eventDatabase.InsertEventInDatabase(bed);
var doc = _eventDatabase.GetDocument();
_eventDatabase.GetSubTypeDocument(typeof(DummyBed));
Assert.That(doc, Is.TypeOf<DummyBed>()); //Great success
}
[Test]
public void FindTypeEvents_FindTwo_Succes()
{
var data = new List<int>() { 1, 2, 3 };
var bed1 = new DummyBed(data, true);
var bed2 = new DummyBed(data, true);
_eventDatabase.InsertEventInDatabase(bed1);
_eventDatabase.InsertEventInDatabase(bed2);
var foundEvents = _eventDatabase.FindTypeEvents(typeof(BedEvent));
Assert.That(foundEvents.Count, Is.EqualTo(2)); // Frozen
}
...
}
However - running each test by it self gives only green check marks. So it is down to how fast it can handle events.
The database is cleared each time a new test is run, so there should be no operations running.
The methods called should wait until they finish:
public void InsertEventInDatabase(BaseEvent inputBaseEvent)
{
inputBaseEvent.Condition = (inputBaseEvent.Condition is bool ? (inputBaseEvent.Condition == true ? 100 : 0) : inputBaseEvent.Condition);
var collection = _database.GetCollection<dynamic>(DatabaseCollection);
collection.InsertOneAsync(inputBaseEvent).Wait(); //Should wait, right?
}
public List<BaseEvent> FindTypeEvents(Type typeFilter)
{
var name = _database.GetCollection<BaseEvent>(DatabaseCollection)
.Find(x => x.Id != Guid.Empty)
.ToListAsync();
return name.Result; //Should wait here as well, right?
}
Any suggestions on where to look for the cause of the problem? It is quite limit with information on the interwebs after the April update of the C# driver, so any suggestions are welcome.
Aucun commentaire:
Enregistrer un commentaire