/// <summary> /// Represents as a model instance /// </summary> public override ActParticipation ToModelInstance(object dataInstance, DataContext context, IPrincipal principal) { if (dataInstance == null) { return(null); } var participationPart = dataInstance as DbActParticipation; var retVal = new ActParticipation() { EffectiveVersionSequenceId = participationPart.EffectiveVersionSequenceId, ObsoleteVersionSequenceId = participationPart.ObsoleteVersionSequenceId, ActKey = participationPart.SourceKey, PlayerEntityKey = participationPart.TargetKey, ParticipationRoleKey = participationPart.ParticipationRoleKey, LoadState = context.LoadState, Quantity = participationPart.Quantity, Key = participationPart.Key, SourceEntityKey = participationPart.SourceKey }; if (context.LoadState == Core.Model.LoadState.FullLoad) { var concept = AdoPersistenceService.GetPersister(typeof(Concept)).Get(participationPart.ParticipationRoleKey); if (concept != null) { retVal.ParticipationRole = concept as Concept; } } return(retVal); }
/// <summary> /// Represents as a model instance /// </summary> public override EntityRelationship ToModelInstance(object dataInstance, DataContext context, IPrincipal principal) { if (dataInstance == null) { return(null); } var entPart = dataInstance as DbEntityRelationship; return(new EntityRelationship() { EffectiveVersionSequenceId = entPart.EffectiveVersionSequenceId, ObsoleteVersionSequenceId = entPart.ObsoleteVersionSequenceId, HolderKey = entPart.SourceKey, TargetEntityKey = entPart.TargetKey, RelationshipType = context.LoadState == Core.Model.LoadState.FullLoad ? AdoPersistenceService.GetPersister(typeof(Concept)).Get(entPart.RelationshipTypeKey) as Concept : null, RelationshipTypeKey = entPart.RelationshipTypeKey, Quantity = entPart.Quantity, LoadState = context.LoadState, Key = entPart.Key, SourceEntityKey = entPart.SourceKey }); }
/// <summary> /// Try get by classifier /// </summary> public static IIdentifiedEntity TryGetExisting(this IIdentifiedEntity me, DataContext context, IPrincipal principal, bool forceDatabase = false) { // Is there a classifier? var idpInstance = AdoPersistenceService.GetPersister(me.GetType()) as IAdoPersistenceService; var cacheService = new AdoPersistenceCache(context); IIdentifiedEntity existing = null; // Forcing from database load from if (forceDatabase && me.Key.HasValue) { // HACK: This should really hit the database instead of just clearing the cache ApplicationContext.Current.GetService <IDataCachingService>()?.Remove(me.Key.Value); } //var tableType = AdoPersistenceService.GetMapper().MapModelType(me.GetType()); //if (me.GetType() != tableType) //{ // var tableMap = TableMapping.Get(tableType); // var dbExisting = context.FirstOrDefault(tableType, context.CreateSqlStatement().SelectFrom(tableType).Where($"{tableMap.Columns.FirstOrDefault(o=>o.IsPrimaryKey).Name}=?", me.Key.Value)); // if (dbExisting != null) // existing = idpInstance.ToModelInstance(dbExisting, context, principal) as IIdentifiedEntity; //} if (me.Key != Guid.Empty && me.Key != null) { existing = idpInstance.Get(context, me.Key.Value, principal) as IIdentifiedEntity; } var classAtt = me.GetType().GetCustomAttribute <KeyLookupAttribute>(); if (classAtt != null && existing == null) { // Get the domain type var dataType = AdoPersistenceService.GetMapper().MapModelType(me.GetType()); var tableMap = TableMapping.Get(dataType); // Get the classifier attribute value var classProperty = me.GetType().GetProperty(classAtt.UniqueProperty); object classifierValue = classProperty.GetValue(me); // Get the classifier // Is the classifier a UUID'd item? if (classifierValue is IIdentifiedEntity) { classifierValue = (classifierValue as IIdentifiedEntity).Key.Value; classProperty = me.GetType().GetProperty(classProperty.GetCustomAttribute <SerializationReferenceAttribute>()?.RedirectProperty ?? classProperty.Name); } // Column var column = tableMap.GetColumn(AdoPersistenceService.GetMapper().MapModelProperty(me.GetType(), dataType, classProperty)); // Now we want to query SqlStatement stmt = context.CreateSqlStatement().SelectFrom(dataType) .Where($"{column.Name} = ?", classifierValue); Guid objIdCache = Guid.Empty; IDbIdentified dataObject = null; // We've seen this before String classKey = $"{dataType}.{classifierValue}"; if (m_classIdCache.TryGetValue(classKey, out objIdCache)) { existing = cacheService?.GetCacheItem(objIdCache) as IdentifiedData; } if (existing == null) { dataObject = context.FirstOrDefault(dataType, stmt) as IDbIdentified; if (dataObject != null) { lock (m_classIdCache) if (!m_classIdCache.ContainsKey(classKey)) { m_classIdCache.Add(classKey, dataObject.Key); } var existCache = cacheService?.GetCacheItem((dataObject as IDbIdentified).Key); if (existCache != null) { existing = existCache as IdentifiedData; } else { existing = idpInstance.ToModelInstance(dataObject, context, principal) as IIdentifiedEntity; } } } } return(existing); }
/// <summary> /// This method will load all basic properties for the specified model object /// </summary> public static void LoadAssociations <TModel>(this TModel me, DataContext context, IPrincipal principal, params String[] loadProperties) where TModel : IIdentifiedEntity { // I duz not haz a chzbrgr? if (me == null || me.LoadState >= context.LoadState) { return; } else if (context.Transaction != null) // kk.. I haz a transaction { return; } #if DEBUG /* * Me neez all the timez * * /\_/\ * >^.^<.---. * _'-`-' )\ * (6--\ |--\ (`.`-. * --' --' ``-' */ Stopwatch sw = new Stopwatch(); sw.Start(); #endif // Cache get classification property - thiz makez us fasters PropertyInfo classProperty = null; if (!s_classificationProperties.TryGetValue(typeof(TModel), out classProperty)) { classProperty = typeof(TModel).GetRuntimeProperty(typeof(TModel).GetTypeInfo().GetCustomAttribute <ClassifierAttribute>()?.ClassifierProperty ?? "____XXX"); if (classProperty != null) { classProperty = typeof(TModel).GetRuntimeProperty(classProperty.GetCustomAttribute <SerializationReferenceAttribute>()?.RedirectProperty ?? classProperty.Name); } lock (s_lockObject) if (!s_classificationProperties.ContainsKey(typeof(TModel))) { s_classificationProperties.Add(typeof(TModel), classProperty); } } // Classification property? String classValue = classProperty?.GetValue(me)?.ToString(); // Cache the props so future kitties can call it IEnumerable <PropertyInfo> properties = null; var propertyCacheKey = $"{me.GetType()}.FullName[{classValue}]"; if (!s_runtimeProperties.TryGetValue(propertyCacheKey, out properties)) { lock (s_runtimeProperties) { properties = me.GetType().GetRuntimeProperties().Where(o => o.GetCustomAttribute <DataIgnoreAttribute>() == null && o.GetCustomAttributes <AutoLoadAttribute>().Any(p => p.ClassCode == classValue || p.ClassCode == null) && typeof(IdentifiedData).IsAssignableFrom(o.PropertyType.StripGeneric())).ToList(); if (!s_runtimeProperties.ContainsKey(propertyCacheKey)) { s_runtimeProperties.Add(propertyCacheKey, properties); } } } // Load fast or lean mode only root associations which will appear on the wire if (context.LoadState == LoadState.PartialLoad) { if (me.LoadState == LoadState.PartialLoad) // already partially loaded :/ { return; } else { me.LoadState = LoadState.PartialLoad; properties = properties.Where(o => o.GetCustomAttribute <XmlAttributeAttribute>() != null || o.GetCustomAttribute <XmlElementAttribute>() != null).ToList(); } } // Iterate over the properties and load the properties foreach (var pi in properties) { if (loadProperties.Length > 0 && !loadProperties.Contains(pi.Name)) { continue; } // Map model type to domain var adoPersister = AdoPersistenceService.GetPersister(pi.PropertyType.StripGeneric()); // Loading associations, so what is the associated type? if (typeof(IList).IsAssignableFrom(pi.PropertyType) && adoPersister is IAdoAssociativePersistenceService && me.Key.HasValue) // List so we select from the assoc table where we are the master table { // Is there not a value? var assocPersister = adoPersister as IAdoAssociativePersistenceService; // We want to query based on our PK and version if applicable decimal? versionSequence = (me as IBaseEntityData)?.ObsoletionTime.HasValue == true ? (me as IVersionedEntity)?.VersionSequence : null; var assoc = assocPersister.GetFromSource(context, me.Key.Value, versionSequence, principal); ConstructorInfo ci = null; if (!m_constructors.TryGetValue(pi.PropertyType, out ci)) { var type = pi.PropertyType.StripGeneric(); while (type != typeof(Object) && ci == null) { ci = pi.PropertyType.GetConstructor(new Type[] { typeof(IEnumerable <>).MakeGenericType(type) }); type = type.BaseType; } if (ci != null) { lock (s_lockObject) if (!m_constructors.ContainsKey(pi.PropertyType)) { m_constructors.Add(pi.PropertyType, ci); } } else { throw new InvalidOperationException($"This is odd, you seem to have a list with no constructor -> {pi.PropertyType}"); } } var listValue = ci.Invoke(new object[] { assoc }); pi.SetValue(me, listValue); } else if (typeof(IIdentifiedEntity).IsAssignableFrom(pi.PropertyType)) // Single { // Single property, we want to execute a get on the key property var pid = pi; if (pid.Name.EndsWith("Xml")) // Xml purposes only { pid = pi.DeclaringType.GetProperty(pi.Name.Substring(0, pi.Name.Length - 3)); } var redirectAtt = pid.GetCustomAttribute <SerializationReferenceAttribute>(); // We want to issue a query var keyProperty = redirectAtt != null?pi.DeclaringType.GetProperty(redirectAtt.RedirectProperty) : pi.DeclaringType.GetProperty(pid.Name + "Key"); if (keyProperty == null) { continue; } var keyValue = keyProperty?.GetValue(me); if (keyValue == null || Guid.Empty.Equals(keyValue)) { continue; // No key specified } // This is kinda messy.. maybe iz to be changez object value = null; if (!context.Data.TryGetValue(keyValue.ToString(), out value)) { value = adoPersister.Get(context, (Guid)keyValue, principal); context.AddData(keyValue.ToString(), value); } pid.SetValue(me, value); } } #if DEBUG sw.Stop(); s_traceSource.TraceEvent(TraceEventType.Verbose, 0, "Load associations for {0} took {1} ms", me, sw.ElapsedMilliseconds); #endif if (me.LoadState == LoadState.New) { me.LoadState = LoadState.FullLoad; } }
/// <summary> /// Ensures a model has been persisted /// </summary> public static IIdentifiedEntity EnsureExists(this IIdentifiedEntity me, DataContext context, IPrincipal principal) { if (me == null) { return(null); } // Me var vMe = me as IVersionedEntity; String dkey = String.Format("{0}.{1}", me.GetType().FullName, me.Key); IIdentifiedEntity existing = me.TryGetExisting(context, principal); var idpInstance = AdoPersistenceService.GetPersister(me.GetType()); // Don't touch the child just return reference if (!AdoPersistenceService.GetConfiguration().AutoInsertChildren) { if (existing != null) { if (me.Key != existing.Key || vMe?.VersionKey != (existing as IVersionedEntity)?.VersionKey) { me.CopyObjectData(existing); // copy data into reference } return(existing); } else { throw new KeyNotFoundException(me.Key.Value.ToString()); } } // Existing exists? if (existing != null && me.Key.HasValue) { // Exists but is an old version if ((existing as IVersionedEntity)?.VersionKey != vMe?.VersionKey && vMe?.VersionKey != null && vMe?.VersionKey != Guid.Empty) { // Update method IVersionedEntity updated = idpInstance.Update(context, me, principal) as IVersionedEntity; me.Key = updated.Key; if (vMe != null) { vMe.VersionKey = (updated as IVersionedEntity).VersionKey; } return(updated); } return(existing); } else if (existing == null) // Insert { IIdentifiedEntity inserted = idpInstance.Insert(context, me, principal) as IIdentifiedEntity; me.Key = inserted.Key; if (vMe != null) { vMe.VersionKey = (inserted as IVersionedEntity).VersionKey; } return(inserted); } return(existing); }