When you are migrating between different databases with different schemas, or any other situation when you have multiple schemas in use at the same time with NEO, you must take more care than usual. The rules are:
- Each schema must use a separate ObjectContext instance.
- Each ObjectContext must use the "appropriate" Entity Map Factory.
Most NEO users are completely unaware of Entity Map Factories, since the DefaultEntityMapFactory is automatically used and does a reasonable job. An Entity Map Factory understands how Entities, EntityMaps, Tables, and .NET assemblies are related. So it knows that a DataTable with TableName="Customer" matches class CustomerEntityMap which is defined in Assembly ... (whatever).
DefaultEntityMapFactory
The DefaultEntityMapFactory loads the main assemblies and dependent assemblies once an ObjectContext first does something interesting. It creats a map (TableName, EntityMap class in assembly) for all classes it finds which implement IEntityMap.
If you have more than one schema which shares a TableName, even if in different Data Stores, then the DefaultEntityMapFactory can't work out which EntityMap class to choose, when it uses the table with the shared name in the ObjectContext's Dataset. Currently, the last loaded assembly wins (usually the most distantly related).
DefaultEntityMapFactory also uses a static class member, so creating a new instance doesn't help.
The solution is for the ObjectContext to use a different EntityMapFactory.
Changing the ObjectContext's EntityMapFactory
Change the ObjectContext's factory property as soon as it is created.
ObjectContext context = new ObjectContext(...insert datastore instance here..);
context.EntityMapFactory = new LegacyEntityMapFactory()
SingleAssemblyEntityMapFactory
Since most NEO users are likely to have all their Entity Objects in a single assembly, I made a simplified copy of the DefaultEntityMapFactory, which permits multiple instances and only loads one assembly.
You can find it under Core/Util in cvs or probably 1.2.4+
I have now taken to defining a class for the EntityMapFactory within the same assembly as the entity objects.
using System;
using Neo.Core.Util;
using System.Reflection;
using Neo.Core;
public class LegacyEntityMapFactory : SingleAssemblyEntityMapFactory
{
private static LegacyEntityMapFactory sharedInstance;
public LegacyEntityMapFactory() : base ()
{
}
public static LegacyEntityMapFactory SharedInstance
{
get
{
if(sharedInstance == null)
sharedInstance = new LegacyEntityMapFactory();
return sharedInstance;
}
}
public override Assembly GetContainingAssembly()
{
return typeof(LegacyEntityMapFactory).Assembly;
}
}
