In MDriven I'd like to get the type discriminator for a modeled class at runtime. I thought I had done it before, but can't seem to find it and can't figure it out.
I mean the integer that appears first in the external id string, e.g. "72" in external id "72!i64!12345678".
I need to get the discriminator based on C# type, i.e. typeof(MyClass), without having any object instance available. This makes it impossible to extract the discriminator from the external id string, because I have no such string available at the time and can't create one.
I'm using Eco.Services.Impl.ExternalIdServiceImpl_DbType
so the external id's type discriminator matches the type discriminator in the database, in case that matters. But how do I lookup the discriminator for a type, in runtime?
After finding source code for Eco.Services.Impl.ExternalIdServiceImpl_DbType
I was able to create this solution:
public static string GetClassDiscriminator<T>(this IEcoServiceProvider sp)
{
IEcoTypeSystem typeSys = sp.GetEcoService<ITypeSystemService>().TypeSystem;
IClass cls = typeSys.AllClasses.Cast<IClass>().First(c => c.ObjectType == typeof(T));
if (sp.GetEcoService<IExternalIdService>() is Eco.Services.Impl.ExternalIdServiceImpl_DbType)
{
ORMappingDefinition mapping = ((PersistenceMapperDb)DiamondsPMP.Instance.PersistenceMapper).EffectiveRunTimeMappingProvider.Mapping;
if (mapping == null)
throw new InvalidOperationException(PersistenceStringRes.MappingProviderNotInitialized);
ClassDefinition classdef = mapping.Classes[typeSys.AllClasses[0].Name];
if (classdef.Discriminators.Count == 0)
throw new InvalidOperationException(PersistenceStringRes.RootclassHasNoDiscriminatorDefined);
DiscriminatorDef discriminator = classdef.Discriminators.Cast<DiscriminatorDef>().First();
DiscriminatorValue discvalue = discriminator.DiscriminatorValuesByClassId(cls.InternalIndex);
if (discvalue == null)
throw new InvalidOperationException(PersistenceStringRes.ClassHasNoDiscriminatorValueDefined);
if (discvalue.IsFinal && cls.SubTypes.Count > 0)
throw new InvalidOperationException(PersistenceStringRes.DiscriminatorIsFinal);
return discvalue.Value;
}
else
return cls.InternalIndex.ToString();
}
The sp.GetEcoService<IExternalIdService>() is Eco.Services.Impl.ExternalIdServiceImpl_DbType
is required in my case, because in my unit tests i use PersistenceMapperMemory
, which uses the index in TypeSystem.AllClasses
as type discriminator, which is also the value returned by IClass.InternalIndex
.
I also note that IExternalIdService.ObjectForIdSeperateClassInfo()
is buggy. It acts as if Eco.Services.Impl.ExternalIdServiceImpl
is being used, returning an IObjectInstance
of the wrong type (using the class' index in TypeSystem.AllClasses
).