/// <summary> /// Insert the specified sbadm /// </summary> public override Core.Model.Acts.SubstanceAdministration InsertInternal(DataContext context, Core.Model.Acts.SubstanceAdministration data, IPrincipal principal) { if (data.DoseUnit != null) { data.DoseUnit = data.DoseUnit?.EnsureExists(context, principal) as Concept; } if (data.Route != null) { data.Route = data.Route?.EnsureExists(context, principal) as Concept; } else if (!data.RouteKey.HasValue) { data.RouteKey = NullReasonKeys.NoInformation; } // JF: Correct dose unit key if (AdoPersistenceService.GetConfiguration().DataCorrectionKeys.Contains("invalid-sbadm-dose-unit") && data.DoseUnitKey == Guid.Parse("a77b8d83-1cc9-4806-a268-5d1738154afa")) { data.DoseUnitKey = Guid.Parse("a4fc5c93-31c2-4f87-990e-c5a4e5ea2e76"); } data.DoseUnitKey = data.DoseUnit?.Key ?? data.DoseUnitKey; data.RouteKey = data.Route?.Key ?? data.RouteKey; return(base.InsertInternal(context, data, principal)); }
/// <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> /// Get the specified object /// </summary> internal override TModel Get(DataContext context, Guid key, IPrincipal principal) { // We need to join, but to what? // True to get the cache item var cacheService = new AdoPersistenceCache(context); var cacheItem = cacheService?.GetCacheItem <TModel>(key) as TModel; if (cacheItem != null && context.Transaction == null) { if (cacheItem.LoadState < context.LoadState) { cacheItem.LoadAssociations(context, principal); cacheService?.Add(cacheItem); } return(cacheItem); } else { var domainQuery = AdoPersistenceService.GetQueryBuilder().CreateQuery <TModel>(o => o.Key == key && o.ObsoletionTime == null).Build(); domainQuery.OrderBy <TRootEntity>(o => o.VersionSequenceId, Core.Model.Map.SortOrderType.OrderByDescending); cacheItem = this.ToModelInstance(context.FirstOrDefault <TQueryReturn>(domainQuery), context, principal); if (cacheService != null) { cacheService.Add(cacheItem); } return(cacheItem); } }
/// <summary> /// Performs the actual query /// </summary> public override IEnumerable <TModel> QueryInternal(DataContext context, Expression <Func <TModel, bool> > query, Guid queryId, int offset, int?count, out int totalResults, IPrincipal principal, bool countResults = true) { int resultCount = 0; var results = this.QueryInternal(context, query, queryId, offset, count, out resultCount, countResults).ToList(); totalResults = resultCount; if (!AdoPersistenceService.GetConfiguration().SingleThreadFetch) { return(results.AsParallel().Select(o => { var subContext = context; var newSubContext = results.Count() > 1; try { if (newSubContext) { subContext = subContext.OpenClonedContext(); } if (o is Guid) { return this.Get(subContext, (Guid)o, principal); } else { return this.CacheConvert(o, subContext, principal); } } catch (Exception e) { this.m_tracer.TraceEvent(TraceEventType.Error, e.HResult, "Error performing sub-query: {0}", e); throw; } finally { if (newSubContext) { subContext.Dispose(); } } })); } else { return(results.Select(o => { if (o is Guid) { return this.Get(context, (Guid)o, principal); } else { return this.CacheConvert(o, context, principal); } })); } }
/// <summary> /// Insert or update contents of the bundle /// </summary> /// <returns></returns> public override Bundle InsertInternal(DataContext context, Bundle data, IPrincipal principal) { if (data.Item == null) { return(data); } this.m_tracer.TraceInformation("Bundle has {0} objects...", data.Item.Count); data = this.ReorganizeForInsert(data); this.m_tracer.TraceInformation("After reorganization has {0} objects...", data.Item.Count); if (AdoPersistenceService.GetConfiguration().PrepareStatements) { context.PrepareStatements = true; } for (int i = 0; i < data.Item.Count; i++) { var itm = data.Item[i]; var idp = typeof(IDataPersistenceService <>).MakeGenericType(new Type[] { itm.GetType() }); var svc = ApplicationContext.Current.GetService(idp); var method = "Insert"; if (itm.TryGetExisting(context, principal, true) != null) { method = "Update"; } this.m_tracer.TraceInformation("Will {0} object from bundle {1}...", method, itm); this.ProgressChanged?.Invoke(this, new ProgressChangedEventArgs((float)(i + 1) / data.Item.Count, itm)); var mi = svc.GetType().GetRuntimeMethod(method, new Type[] { typeof(DataContext), itm.GetType(), typeof(IPrincipal) }); try { data.Item[i] = mi.Invoke(svc, new object[] { context, itm, principal }) as IdentifiedData; } catch (TargetInvocationException e) { throw e.InnerException; } } // Cache items foreach (var itm in data.Item) { itm.LoadState = LoadState.FullLoad; context.AddCacheCommit(itm); } return(data); }
/// <summary> /// Perform the query /// </summary> protected virtual IEnumerable <Object> QueryInternal(DataContext context, Expression <Func <TModel, bool> > query, Guid queryId, int offset, int?count, out int totalResults, bool incudeCount = true) { #if DEBUG Stopwatch sw = new Stopwatch(); sw.Start(); #endif SqlStatement domainQuery = null; try { // Query has been registered? if (queryId != Guid.Empty && this.m_queryPersistence?.IsRegistered(queryId.ToString()) == true) { totalResults = (int)this.m_queryPersistence.QueryResultTotalQuantity(queryId.ToString()); var resultKeys = this.m_queryPersistence.GetQueryResults <Guid>(queryId.ToString(), offset, count.Value); return(resultKeys.Select(p => p.Id).OfType <Object>()); } // Is obsoletion time already specified? if (!query.ToString().Contains("ObsoletionTime") && typeof(BaseEntityData).IsAssignableFrom(typeof(TModel))) { var obsoletionReference = Expression.MakeBinary(ExpressionType.Equal, Expression.MakeMemberAccess(query.Parameters[0], typeof(TModel).GetProperty(nameof(BaseEntityData.ObsoletionTime))), Expression.Constant(null)); query = Expression.Lambda <Func <TModel, bool> >(Expression.MakeBinary(ExpressionType.AndAlso, obsoletionReference, query.Body), query.Parameters); } // Domain query domainQuery = context.CreateSqlStatement <TDomain>().SelectFrom(); var expression = m_mapper.MapModelExpression <TModel, TDomain>(query, false); if (expression != null) { Type lastJoined = typeof(TDomain); if (typeof(CompositeResult).IsAssignableFrom(typeof(TQueryReturn))) { foreach (var p in typeof(TQueryReturn).GenericTypeArguments.Select(o => AdoPersistenceService.GetMapper().MapModelType(o))) { if (p != typeof(TDomain)) { // Find the FK to join domainQuery.InnerJoin(lastJoined, p); lastJoined = p; } } } domainQuery.Where <TDomain>(expression); } else { m_tracer.TraceEvent(System.Diagnostics.TraceEventType.Verbose, 0, "Will use slow query construction due to complex mapped fields"); domainQuery = AdoPersistenceService.GetQueryBuilder().CreateQuery(query); } // Count = 0 means we're not actually fetching anything so just hit the db if (count != 0) { domainQuery = this.AppendOrderBy(domainQuery); // Query id just get the UUIDs in the db if (queryId != Guid.Empty && count != 0) { ColumnMapping pkColumn = null; if (typeof(CompositeResult).IsAssignableFrom(typeof(TQueryReturn))) { foreach (var p in typeof(TQueryReturn).GenericTypeArguments.Select(o => AdoPersistenceService.GetMapper().MapModelType(o))) { if (!typeof(DbSubTable).IsAssignableFrom(p) && !typeof(IDbVersionedData).IsAssignableFrom(p)) { pkColumn = TableMapping.Get(p).Columns.SingleOrDefault(o => o.IsPrimaryKey); break; } } } else { pkColumn = TableMapping.Get(typeof(TQueryReturn)).Columns.SingleOrDefault(o => o.IsPrimaryKey); } var keyQuery = AdoPersistenceService.GetQueryBuilder().CreateQuery(query, pkColumn).Build(); var resultKeys = context.Query <Guid>(keyQuery.Build()); //ApplicationContext.Current.GetService<IThreadPoolService>().QueueNonPooledWorkItem(a => this.m_queryPersistence?.RegisterQuerySet(queryId.ToString(), resultKeys.Select(o => new Identifier<Guid>(o)).ToArray(), query), null); // Another check this.m_queryPersistence?.RegisterQuerySet(queryId.ToString(), resultKeys.Count(), resultKeys.Select(o => new Identifier <Guid>(o)).Take(1000).ToArray(), query); ApplicationContext.Current.GetService <IThreadPoolService>().QueueNonPooledWorkItem(o => { int ofs = 1000; var rkeys = o as Guid[]; while (ofs < rkeys.Length) { this.m_queryPersistence?.AddResults(queryId.ToString(), rkeys.Skip(ofs).Take(1000).Select(k => new Identifier <Guid>(k)).ToArray()); ofs += 1000; } }, resultKeys.ToArray()); if (incudeCount) { totalResults = (int)resultKeys.Count(); } else { totalResults = 0; } var retVal = resultKeys.Skip(offset); if (count.HasValue) { retVal = retVal.Take(count.Value); } return(retVal.OfType <Object>()); } else if (incudeCount) { totalResults = context.Count(domainQuery); if (totalResults == 0) { return(new List <Object>()); } } else { totalResults = 0; } if (offset > 0) { domainQuery.Offset(offset); } if (count.HasValue) { domainQuery.Limit(count.Value); } return(this.DomainQueryInternal <TQueryReturn>(context, domainQuery, ref totalResults).OfType <Object>()); } else { totalResults = context.Count(domainQuery); return(new List <Object>()); } } catch (Exception ex) { if (domainQuery != null) { this.m_tracer.TraceEvent(TraceEventType.Error, ex.HResult, context.GetQueryLiteral(domainQuery.Build())); } context.Dispose(); // No longer important throw; } #if DEBUG finally { sw.Stop(); } #endif }
/// <summary> /// Reorganize all the major items for insert /// </summary> private Bundle ReorganizeForInsert(Bundle bundle) { Bundle retVal = new Bundle() { Item = new List <IdentifiedData>() }; foreach (var itm in bundle.Item.Where(o => o != null)) { this.m_tracer.TraceInformation("Reorganizing {0}..", itm.Key); // Are there any relationships if (itm is Entity) { var ent = itm as Entity; foreach (var rel in ent.Relationships) { this.m_tracer.TraceInformation("Processing {0} / relationship / {1} ..", itm.Key, rel.TargetEntityKey); var bitm = bundle.Item.FirstOrDefault(o => o.Key == rel.TargetEntityKey); if (bitm == null) { continue; } if (retVal.Item.Any(o => o.Key == rel.TargetEntityKey)) { continue; } this.m_tracer.TraceInformation("Bumping (due to relationship): {0}", bitm); retVal.Item.Add(bitm); // make sure it gets inserted first } } else if (itm is Act) { var act = itm as Act; foreach (var rel in act.Relationships) { this.m_tracer.TraceInformation("Processing {0} / relationship / {1} ..", itm.Key, rel.TargetActKey); var bitm = bundle.Item?.FirstOrDefault(o => o.Key == rel?.TargetActKey); if (bitm == null) { continue; } if (retVal.Item.Any(o => o.Key == rel.TargetActKey)) { continue; } this.m_tracer.TraceInformation("Bumping (due to relationship): {0}", bitm); retVal.Item.Add(bitm); // make sure it gets inserted first } foreach (var rel in act.Participations) { this.m_tracer.TraceInformation("Processing {0} / participation / {1} ..", itm.Key, rel.PlayerEntityKey); var bitm = bundle.Item?.FirstOrDefault(o => o.Key == rel?.PlayerEntityKey); if (bitm == null) { continue; } if (retVal.Item.Any(o => o.Key == rel.PlayerEntityKey)) { continue; } this.m_tracer.TraceInformation("Bumping (due to participation): {0}", bitm); retVal.Item.Add(bitm); // make sure it gets inserted first } // Old versions of the mobile had an issue with missing record targets if (AdoPersistenceService.GetConfiguration().DataCorrectionKeys.Contains("correct-missing-rct")) { var patientEncounter = bundle.Item.OfType <PatientEncounter>().FirstOrDefault(); if (patientEncounter != null) { var rct = act.Participations.FirstOrDefault(o => o.ParticipationRoleKey == OpenIZ.Core.Model.Constants.ActParticipationKey.RecordTarget); if (!(rct == null || rct.PlayerEntityKey.HasValue)) { var perct = patientEncounter.Participations.FirstOrDefault(o => o.ParticipationRoleKey == ActParticipationKey.RecordTarget); act.Participations.Remove(rct); act.Participations.Add(new ActParticipation(ActParticipationKey.RecordTarget, perct.PlayerEntityKey)); } } } } this.m_tracer.TraceInformation("Re-adding: {0}", itm); retVal.Item.Add(itm); } return(retVal); }
/// <summary> /// Query internal /// </summary> protected override IEnumerable <Object> QueryInternal(DataContext context, Expression <Func <TModel, bool> > query, Guid queryId, int offset, int?count, out int totalResults, bool countResults = true) { // Is obsoletion time already specified? if (!query.ToString().Contains("ObsoletionTime")) { var obsoletionReference = Expression.MakeBinary(ExpressionType.Equal, Expression.MakeMemberAccess(query.Parameters[0], typeof(TModel).GetProperty(nameof(BaseEntityData.ObsoletionTime))), Expression.Constant(null)); query = Expression.Lambda <Func <TModel, bool> >(Expression.MakeBinary(ExpressionType.AndAlso, obsoletionReference, query.Body), query.Parameters); } // Query has been registered? if (this.m_queryPersistence?.IsRegistered(queryId.ToString()) == true) { totalResults = (int)this.m_queryPersistence.QueryResultTotalQuantity(queryId.ToString()); var keyResults = this.m_queryPersistence.GetQueryResults <Guid>(queryId.ToString(), offset, count.Value); return(keyResults.Select(p => p.Id).OfType <Object>()); } SqlStatement domainQuery = null; try { domainQuery = context.CreateSqlStatement <TDomain>().SelectFrom() .InnerJoin <TDomain, TDomainKey>(o => o.Key, o => o.Key) .Where <TDomain>(m_mapper.MapModelExpression <TModel, TDomain>(query)).Build(); } catch (Exception e) { m_tracer.TraceEvent(System.Diagnostics.TraceEventType.Verbose, e.HResult, "Will use slow query construction due to {0}", e.Message); domainQuery = AdoPersistenceService.GetQueryBuilder().CreateQuery(query).Build(); } domainQuery = this.AppendOrderBy(domainQuery); // Query id just get the UUIDs in the db if (queryId != Guid.Empty) { ColumnMapping pkColumn = TableMapping.Get(typeof(TDomainKey)).Columns.SingleOrDefault(o => o.IsPrimaryKey); var keyQuery = AdoPersistenceService.GetQueryBuilder().CreateQuery(query, pkColumn).Build(); var resultKeys = context.Query <Guid>(keyQuery.Build()); this.m_queryPersistence?.RegisterQuerySet(queryId.ToString(), resultKeys.Count(), resultKeys.Take(1000).Select(o => new Identifier <Guid>(o)).ToArray(), query); ApplicationContext.Current.GetService <IThreadPoolService>().QueueNonPooledWorkItem(o => { int ofs = 1000; var rkeys = o as Guid[]; if (rkeys == null) { return; } while (ofs < rkeys.Length) { this.m_queryPersistence?.AddResults(queryId.ToString(), rkeys.Skip(ofs).Take(1000).Select(k => new Identifier <Guid>(k)).ToArray()); ofs += 1000; } }, resultKeys.ToArray()); if (countResults) { totalResults = (int)resultKeys.Count(); } else { totalResults = 0; } var retVal = resultKeys.Skip(offset); if (count.HasValue) { retVal = retVal.Take(count.Value); } return(retVal.OfType <Object>()); } else if (countResults) { totalResults = context.Count(domainQuery); if (totalResults == 0) { return(new List <CompositeResult <TDomain, TDomainKey> >()); } } else { totalResults = 0; } if (offset > 0) { domainQuery.Offset(offset); } if (count.HasValue) { domainQuery.Limit(count.Value); } return(context.Query <CompositeResult <TDomain, TDomainKey> >(domainQuery).OfType <Object>()); }
/// <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> /// Bundle persistence /// </summary> public AuditBundlePersistenceService() { this.m_persistenceService = ApplicationServiceContext.Current.GetService <AdoPersistenceService>(); }
/// <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); }
/// <summary> /// Update the specified data /// </summary> public Core.Model.Acts.Act UpdateCoreProperties(DataContext context, Core.Model.Acts.Act data, IPrincipal principal) { if (data.ClassConcept != null) { data.ClassConcept = data.ClassConcept?.EnsureExists(context, principal) as Concept; } if (data.MoodConcept != null) { data.MoodConcept = data.MoodConcept?.EnsureExists(context, principal) as Concept; } if (data.ReasonConcept != null) { data.ReasonConcept = data.ReasonConcept?.EnsureExists(context, principal) as Concept; } if (data.StatusConcept != null) { data.StatusConcept = data.StatusConcept?.EnsureExists(context, principal) as Concept; } if (data.TypeConcept != null) { data.TypeConcept = data.TypeConcept?.EnsureExists(context, principal) as Concept; } if (data.Template != null) { data.Template = data.Template?.EnsureExists(context, principal) as TemplateDefinition; } data.ClassConceptKey = data.ClassConcept?.Key ?? data.ClassConceptKey; data.MoodConceptKey = data.MoodConcept?.Key ?? data.MoodConceptKey; data.ReasonConceptKey = data.ReasonConcept?.Key ?? data.ReasonConceptKey; data.StatusConceptKey = data.StatusConcept?.Key ?? data.StatusConceptKey ?? StatusKeys.New; // Do the update var retVal = base.UpdateInternal(context, data, principal); if (data.Extensions != null) { base.UpdateVersionedAssociatedItems <Core.Model.DataTypes.ActExtension, DbActExtension>( data.Extensions.Where(o => o != null && !o.IsEmpty()), retVal, context, principal); } if (data.Identifiers != null) { base.UpdateVersionedAssociatedItems <Core.Model.DataTypes.ActIdentifier, DbActIdentifier>( data.Identifiers.Where(o => o != null && !o.IsEmpty()), retVal, context, principal); } if (data.Notes != null) { base.UpdateVersionedAssociatedItems <Core.Model.DataTypes.ActNote, DbActNote>( data.Notes.Where(o => o != null && !o.IsEmpty()), retVal, context, principal); } if (data.Participations != null) { // Correct mixed keys if (AdoPersistenceService.GetConfiguration().DataCorrectionKeys.Contains("edmonton-participation-keyfix")) { // Obsolete all foreach (var itm in context.Query <DbActParticipation>(o => o.SourceKey == retVal.Key && o.ObsoleteVersionSequenceId == null && o.ParticipationRoleKey == ActParticipationKey.Consumable)) { itm.ObsoleteVersionSequenceId = retVal.VersionSequence; context.Update(itm); } // Now we want to re-point to correct the issue foreach (var itm in context.Query <DbActParticipation>(o => o.SourceKey == retVal.Key && o.ParticipationRoleKey == ActParticipationKey.Consumable && o.ObsoleteVersionSequenceId == retVal.VersionSequence)) { var dItm = data.Participations.Find(o => o.Key == itm.Key); if (dItm != null) { itm.TargetKey = dItm.PlayerEntityKey.Value; } itm.ObsoleteVersionSequenceId = null; context.Update(itm); } } // Update versioned association items base.UpdateVersionedAssociatedItems <Core.Model.Acts.ActParticipation, DbActParticipation>( data.Participations.Where(o => o != null && !o.IsEmpty()), retVal, context, principal); } if (data.Relationships != null) { base.UpdateVersionedAssociatedItems <Core.Model.Acts.ActRelationship, DbActRelationship>( data.Relationships.Where(o => o != null && !o.IsEmpty() && (o.SourceEntityKey == data.Key || !o.SourceEntityKey.HasValue)), retVal, context, principal); } if (data.Tags != null) { base.UpdateAssociatedItems <Core.Model.DataTypes.ActTag, DbActTag>( data.Tags.Where(o => o != null && !o.IsEmpty()), retVal, context, principal); } return(retVal); }