/// <summary> /// Perform the actual update. /// </summary> /// <param name="context">Context.</param> /// <param name="data">Data.</param> public TData Update(SQLiteDataContext context, TData data) { // JF- Probably no need to do this now // Make sure we're updating the right thing //if (data.Key.HasValue) //{ // var cacheItem = ApplicationContext.Current.GetService<IDataCachingService>()?.GetCacheItem(data.GetType(), data.Key.Value); // if (cacheItem != null) // { // cacheItem.CopyObjectData(data); // data = cacheItem as TData; // } //} var retVal = this.UpdateInternal(context, data); //if (retVal != data) System.Diagnostics.Debugger.Break(); context.AddCacheCommit(retVal); return(retVal); }
/// <summary> /// Update the specified object /// </summary> protected override TModel UpdateInternal(SQLiteDataContext context, TModel data) { if (data.IsEmpty()) { return(data); } foreach (var rp in this.m_properties) { var instance = rp.GetValue(data); if (instance != null && rp.Name != "SourceEntity") // HACK: Prevent infinite loops on associtive entities { instance = ModelExtensions.TryGetExisting(instance as IIdentifiedEntity, context); if (instance != null) { rp.SetValue(data, instance); } ModelExtensions.UpdateParentKeys(data, rp); } } return(base.UpdateInternal(context, data)); }
/// <summary> /// Ensure exists /// </summary> protected override TModel InsertInternal(SQLiteDataContext context, TModel data) { foreach (var rp in typeof(TModel).GetRuntimeProperties().Where(o => typeof(IdentifiedData).GetTypeInfo().IsAssignableFrom(o.PropertyType.GetTypeInfo()))) { if (rp.GetCustomAttribute <DataIgnoreAttribute>() != null) { continue; } var instance = rp.GetValue(data); if (instance != null) { instance = ModelExtensions.TryGetExisting(instance as IIdentifiedEntity, context); if (instance != null) { rp.SetValue(data, instance); } ModelExtensions.UpdateParentKeys(data, rp); } } return(base.InsertInternal(context, data)); }
/// <summary> /// Ensure exists /// </summary> protected override TModel InsertInternal(SQLiteDataContext context, TModel data) { if (data.IsEmpty()) { return(data); } foreach (var rp in this.m_properties) { var instance = rp.GetValue(data); if (instance != null) { instance = ModelExtensions.TryGetExisting(instance as IIdentifiedEntity, context); if (instance != null) { rp.SetValue(data, instance); } ModelExtensions.UpdateParentKeys(data, rp); } } return(base.InsertInternal(context, data)); }
/// <summary> /// To model instance /// </summary> object ISQLitePersistenceService.ToModelInstance(object domainInstance, SQLiteDataContext context) { return(this.ToModelInstance(domainInstance, context)); }
/// <summary> /// Get the specified data /// </summary> object ISQLitePersistenceService.Get(SQLiteDataContext context, Guid id) { return(this.Get(context, id)); }
/// <summary> /// Obsolete /// </summary> object ISQLitePersistenceService.Obsolete(SQLiteDataContext context, object data) { return(this.Obsolete(context, (TData)data)); }
/// <summary> /// Insert the specified data /// </summary> object ISQLitePersistenceService.Insert(SQLiteDataContext context, object data) { return(this.Insert(context, (TData)data)); }
/// <summary> /// Query internal without caring about limiting /// </summary> /// <param name="context"></param> /// <param name="expr"></param> /// <returns></returns> public IEnumerable <TData> Query(SQLiteDataContext context, Expression <Func <TData, bool> > expr) { int t; return(this.QueryInternal(context, expr, 0, -1, out t, Guid.Empty, false, null)); }
/// <summary> /// Performs the actual query /// </summary> /// <param name="context">Context.</param> /// <param name="query">Query.</param> protected abstract IEnumerable <TData> QueryInternal(SQLiteDataContext context, String storedQueryName, IDictionary <String, Object> parms, int offset, int count, out int totalResults, Guid queryId, bool countResults, ModelSort <TData>[] orderBy);
/// <summary> /// Performs the actual obsoletion /// </summary> /// <param name="context">Context.</param> /// <param name="data">Data.</param> protected abstract TData ObsoleteInternal(SQLiteDataContext context, TData data);
/// <summary> /// Performthe actual insert. /// </summary> /// <param name="context">Context.</param> /// <param name="data">Data.</param> protected abstract TData InsertInternal(SQLiteDataContext context, TData data);
/// <summary> /// Froms the model instance. /// </summary> /// <returns>The model instance.</returns> /// <param name="modelInstance">Model instance.</param> public abstract Object FromModelInstance(TData modelInstance, SQLiteDataContext context);
/// <summary> /// Maps the data to a model instance /// </summary> /// <returns>The model instance.</returns> /// <param name="dataInstance">Data instance.</param> public abstract TData ToModelInstance(Object dataInstance, SQLiteDataContext context);
/// <summary> /// Get all the matching TModel object from source /// </summary> public IEnumerable GetFromSource(SQLiteDataContext context, Guid sourceId, decimal?versionSequenceId) { int tr = 0; return(this.Query(context, o => o.SourceEntityKey == sourceId, Guid.Empty, 0, 100, out tr, false, null)); }
/// <summary> /// Load specified associations /// </summary> public static void LoadAssociations <TModel>(this TModel me, SQLiteDataContext context, params string[] excludeProperties) where TModel : IIdentifiedEntity { //using (context.LockConnection()) //{ if (me == null) { throw new ArgumentNullException(nameof(me)); } else if (me.LoadState == LoadState.FullLoad || context.DelayLoadMode == LoadState.PartialLoad && context.LoadAssociations == null) { return; } else if (context.Connection.IsInTransaction) { 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).GetTypeInfo().IsAssignableFrom(o.PropertyType.StripGeneric().GetTypeInfo())).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.LoadAssociations != null) { var loadAssociations = context.LoadAssociations.Where(o => o.StartsWith(me.GetType().GetTypeInfo().GetCustomAttribute <XmlTypeAttribute>()?.TypeName)) .Select(la => la.Contains(".") ? la.Substring(la.IndexOf(".") + 1) : la).ToArray(); if (loadAssociations.Length == 0) { return; } properties = properties.Where(p => loadAssociations.Any(la => la == p.Name)).ToList(); } // Iterate over the properties and load the properties foreach (var pi in properties) { if (excludeProperties?.Contains(pi.Name) == true) { continue; } // Map model type to domain var adoPersister = SQLitePersistenceService.GetPersister(pi.PropertyType.StripGeneric()); // Loading associations, so what is the associated type? if (typeof(IList).GetTypeInfo().IsAssignableFrom(pi.PropertyType.GetTypeInfo()) && adoPersister is ISQLiteAssociativePersistenceService && 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 ISQLiteAssociativePersistenceService; // We want to que ry based on our PK and version if applicable decimal?versionSequence = (me as IVersionedEntity)?.VersionSequence; var assoc = assocPersister.GetFromSource(context, me.Key.Value, versionSequence); 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.GetTypeInfo().DeclaredConstructors.FirstOrDefault(o => o.GetParameters().Length == 1 && o.GetParameters()[0].ParameterType == typeof(IEnumerable <>).MakeGenericType(type)); type = type.GetTypeInfo().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 = Activator.CreateInstance(pi.PropertyType, assoc); var listValue = ci.Invoke(new object[] { assoc }); pi.SetValue(me, listValue); } else if (typeof(IIdentifiedEntity).GetTypeInfo().IsAssignableFrom(pi.PropertyType.GetTypeInfo())) // Single { // Single property, we want to execute a get on the key property var redirectAtt = pi.GetCustomAttribute <SerializationReferenceAttribute>(); if (redirectAtt == null) { continue; // cannot get key property } // We want to issue a query var keyProperty = pi.DeclaringType.GetRuntimeProperty(redirectAtt.RedirectProperty); 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); context.AddData(keyValue.ToString(), value); } pi.SetValue(me, value); } } #if DEBUG sw.Stop(); s_tracer.TraceVerbose("Load associations for {0} took {1} ms", me, sw.ElapsedMilliseconds); #endif me.LoadState = excludeProperties.Length > 0 ? LoadState.PartialLoad : LoadState.FullLoad; ApplicationContext.Current.GetService <IDataCachingService>()?.Add(me as IdentifiedData); //} }
/// <summary> /// Try get by classifier /// </summary> public static IIdentifiedEntity TryGetExisting(this IIdentifiedEntity me, SQLiteDataContext context, bool forceDbSearch = false) { // Is there a classifier? var idpInstance = SQLitePersistenceService.GetPersister(me.GetType()) as ISQLitePersistenceService; if (idpInstance == null) { return(null); } //if (me.Key?.ToString() == "e4d3350b-b0f5-45c1-80ba-49e3844cbcc8") // System.Diagnostics.Debugger.Break(); IIdentifiedEntity existing = null; if (!forceDbSearch) { if (me.Key != null) { existing = context.TryGetCacheItem(me.Key.Value); } if (existing != null) { return(existing); } else if (!context.Connection.IsInTransaction) { existing = context.TryGetData(me.Key.Value.ToString()) as IdentifiedData; } else if (me.Key.HasValue) { existing = context.FindTransactedItem(me.Key.Value); } if (forceDbSearch && me.Key.HasValue) { ApplicationContext.Current.GetService <IDataCachingService>().Remove(me.Key.Value); } } // Is the key not null? if (me.Key != Guid.Empty && me.Key != null && existing == null) { existing = idpInstance.Get(context, me.Key.Value) as IIdentifiedEntity; } else { var classAtt = me.GetType().GetTypeInfo().GetCustomAttribute <KeyLookupAttribute>(); if (classAtt != null && existing == null) { // Get the domain type var dataType = SQLitePersistenceService.Mapper.MapModelType(me.GetType()); var tableMap = TableMapping.Get(dataType); // Get the classifier attribute value var classProperty = me.GetType().GetRuntimeProperty(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().GetRuntimeProperty(classProperty.GetCustomAttribute <SerializationReferenceAttribute>()?.RedirectProperty ?? classProperty.Name); } // Column var column = tableMap.GetColumn(SQLitePersistenceService.Mapper.MapModelProperty(me.GetType(), dataType, classProperty)); // Now we want to query SqlStatement stmt = new SqlStatement().SelectFrom(dataType) .Where($"{column.Name} = ?", classifierValue).Build(); var mapping = context.Connection.GetMapping(dataType); var dataObject = context.Connection.Query(mapping, stmt.SQL, stmt.Arguments.ToArray()).FirstOrDefault(); if (dataObject != null) { existing = idpInstance.ToModelInstance(dataObject, context) as IIdentifiedEntity; } } } if (existing != null && me.Key.HasValue) { context.AddData(me.Key.Value.ToString(), existing); } return(existing); }
/// <summary> /// Performs the actual query /// </summary> /// <param name="context">Context.</param> /// <param name="query">Query.</param> protected abstract IEnumerable <TData> QueryInternal(SQLiteDataContext context, Expression <Func <TData, bool> > query, int offset, int count, out int totalResults, Guid queryId, bool countResults, ModelSort <TData>[] orderBy);