private static void InitializeSchemaCacheItem(RepositoryCacheItem cacheItem)
        {
            using (var context = new DatastoreEntities())
            {
                var r = context.Repository.FirstOrDefault(x => x.UniqueKey == cacheItem.Key && !x.IsDeleted && x.IsInitialized);
                if (r == null)
                {
                    cacheItem.IsInitialized = true;
                    cacheItem.Exists        = false;
                    return;
                }
                ;

                var retval = new RepositorySchema
                {
                    InternalID  = r.RepositoryId,
                    ChangeStamp = r.Changestamp
                };
                retval.LoadXml(r.DefinitionData);

                cacheItem.IsInitialized = true;
                cacheItem.Exists        = true;
                cacheItem.Xml           = retval.ToXml(true);
                cacheItem.VersionHash   = retval.VersionHash; // Cache the version to reduce number of calculations
                cacheItem.InternalId    = retval.InternalID;
                cacheItem.HasParent     = (r.ParentId != null);
            }
        }
        /// <summary>
        /// Find the cache subkey. This only exists if there is a FieldFilter with the "GroupingField=Value"
        /// </summary>
        private string GetSubKey(RepositorySchema schema, DataQuery query)
        {
            FieldDefinition groupingField = null;

            //Get the data grouping field for this schema and cache
            lock (_schemaDatagrouping)
            {
                if (schema.ParentID == null && !_schemaDatagrouping.TryGetValue(schema.InternalID, out groupingField))
                {
                    groupingField = schema.FieldList.FirstOrDefault(x => x.IsDataGrouping);
                    if (groupingField == null)
                    {
                        groupingField = new FieldDefinition();
                    }
                    _schemaDatagrouping.Add(schema.InternalID, groupingField);
                }
            }

            //If there is a grouping field then use it to narrow search
            if (groupingField != null)
            {
                var ff = query.FieldFilters.FirstOrDefault(x => x.Name.Match(groupingField.Name));
                if (ff != null && ff.Comparer == ComparisonConstants.Equals && ff.Value != null)
                {
                    return(ff.Value.ToString().ToLower());
                }
            }

            return(null);
        }
 public QueryThreaded(DimensionCache dimensionCache, RepositorySchema schema, DataQuery query)
 {
     this.Query      = query;
     _dimensionCache = dimensionCache;
     _schema         = schema;
     this.Key        = Guid.NewGuid();
 }
        private static void SyncInternal(List <DataItem> list, RepositorySchema schema)
        {
            var  timer     = Stopwatch.StartNew();
            var  count     = 0;
            var  processed = 0;
            long lastRIdx  = 0;

            try
            {
                if (list == null)
                {
                    return;
                }
                if (schema == null)
                {
                    return;
                }

                var l = list.Where(x => x.__Hash == 0 && x.__RecordIndex > 0).ToList();
                if (!l.Any())
                {
                    return;
                }
                count = l.Count;

                var dataTable = SqlHelper.GetTableName(schema.ID);
                foreach (var item in l)
                {
                    var sb         = new StringBuilder();
                    var parameters = new List <SqlParameter>();

                    parameters.Add(new SqlParameter
                    {
                        DbType        = DbType.Int64,
                        IsNullable    = false,
                        ParameterName = $"@{SqlHelper.HashField}",
                        Value         = item.Hash(),
                    });

                    parameters.Add(new SqlParameter
                    {
                        DbType        = DbType.Int64,
                        IsNullable    = false,
                        ParameterName = $"@{SqlHelper.RecordIdxField}",
                        Value         = item.__RecordIndex,
                    });
                    lastRIdx = item.__RecordIndex;

                    sb.AppendLine($"UPDATE [{dataTable}] SET [{SqlHelper.HashField}] = @{SqlHelper.HashField} WHERE [{SqlHelper.RecordIdxField}] = @{SqlHelper.RecordIdxField} AND [{SqlHelper.HashField}] = 0");
                    SqlHelper.ExecuteSql(ConfigHelper.ConnectionString, sb.ToString(), parameters, false, false, 5);
                    Interlocked.Increment(ref _counter);
                    processed++;
                }
            }
            catch (Exception ex)
            {
                LoggerCQ.LogWarning($"DataManager.SyncInternal: ID={schema.ID}, Count={count}, Processed={processed}, RIdx={lastRIdx}, Elapsed={timer.ElapsedMilliseconds}");
            }
        }
Example #5
0
        private static void TestSchema()
        {
            var q1 = RepositorySchema.CreateFromXml(File.ReadAllText(@"c:\temp\a.xml"));
            var q2 = RepositorySchema.CreateFromXml(File.ReadAllText(@"c:\temp\b.xml"));

            var v1 = q1.GetHashCode();
            var v2 = q2.GetHashCode();

            var c1 = q1.FieldList.Where(x => x.AllowIndex).Count();
            var c2 = q2.FieldList.Where(x => x.AllowIndex).Count();
        }
 public static void Sync(List <DataItem> list, RepositorySchema schema)
 {
     try
     {
         Task.Factory.StartNew(() =>
         {
             SyncInternal(list, schema);
         });
     }
     catch (Exception ex)
     {
         LoggerCQ.LogError(ex);
     }
 }
 /// <summary />
 internal DatastoreResultsAsync(DatastoreService dsService, DataQuery query)
 {
     try
     {
         _dsService = dsService;
         _query     = query;
         _hookId    = _dsService.QueryAsync(query);
         _schema    = _dsService.Schema;
     }
     catch
     {
         this.IsComplete = true;
         throw;
     }
 }
        internal static Dictionary <string, int> GetSchemaFieldMap(RepositorySchema schema, RepositorySchema parentSchema)
        {
            var fieldIndexPrimaryMap = new Dictionary <string, int>();

            var fieldIndex = 0;

            if (parentSchema != null)
            {
                parentSchema.FieldList.ForEach(x => fieldIndexPrimaryMap.Add(x.Name, fieldIndex++));
            }
            if (schema != null)
            {
                schema.FieldList.Where(x => !fieldIndexPrimaryMap.ContainsKey(x.Name)).ToList().ForEach(x => fieldIndexPrimaryMap.Add(x.Name, fieldIndex++));
            }

            return(fieldIndexPrimaryMap);
        }
        /// <summary />
        public ActionDiagnostics UpdateSchema(RepositorySchema schema)
        {
            if (schema == null)
            {
                throw new Exception("The schema is not set.");
            }
            if (schema.ID != this.RepositoryId)
            {
                throw new Exception("The schema does not match the RepositoryID.");
            }

            var result = DataModelService.UpdateSchema(schema);

            if (result?.Errors?.Length > 0)
            {
                throw new Exception(result.Errors.First());
            }
            return(result);
        }
        /// <summary />
        public virtual void CreateRepository(RepositorySchema repositorySchema)
        {
            ValidateService();

            if (repositorySchema.ID == Guid.Empty)
            {
                throw new Exception("Invalid ID for repository");
            }
            if (RepositoryExists())
            {
                return;
            }

            using (var factory = SystemCoreInteractDomain.GetCoreFactory(ServerName, Port))
            {
                var core = factory.CreateChannel();
                (core as IContextChannel).OperationTimeout = new TimeSpan(0, 0, 120); //Timeout=2m
                core.SaveRepository(repositorySchema);
            }
        }
        public void Set(DatastoreEntities context, RepositorySchema schema, DataQuery query, int repositoryId, Guid id, DataQueryResults results)
        {
            if (!ConfigHelper.AllowCaching)
            {
                return;
            }
            if (results == null)
            {
                return;
            }

            //Do not cache big items
            if (results.RecordList.Count > 100)
            {
                return;
            }
            if (!string.IsNullOrEmpty(query.Keyword) && !this.FTSReadyCache.IsReady(id))
            {
                return;
            }
            //if (!string.IsNullOrEmpty(query.Keyword) && !ConfigHelper.AllowCacheWithKeyword) return;

            var  timer       = Stopwatch.StartNew();
            var  cache       = RepositoryCacheManager.GetCache(id, RepositoryManager.GetSchemaParentId(repositoryId));
            long lockTime    = 0;
            var  changeStamp = 0;
            var  queryHash   = 0;
            var  subCacheKey = GetSubKey(schema, query);

            try
            {
                //Some queries should be cached a long time
                var longCache = !query.FieldFilters.Any() &&
                                !query.FieldSorts.Any() &&
                                string.IsNullOrEmpty(query.Keyword) &&
                                !query.SkipDimensions.Any();
                var extraMinutes = longCache ? 480 : 0;

                var coreHash = 0;
                CacheResultsQuery item;

                using (var q = new AcquireReaderLock(ServerUtilities.RandomizeGuid(cache.ID, RSeed), "QueryCache"))
                {
                    lockTime += q.LockTime;
                    queryHash = query.GetHashCode();
                    if (!query.ExcludeCount && query.IncludeDimensions && !query.IncludeEmptyDimensions)
                    {
                        coreHash = query.CoreHashCode();
                    }

                    changeStamp = RepositoryManager.GetRepositoryChangeStamp(context, repositoryId);
                    lock (cache)
                    {
                        item = cache?.FirstOrDefault(x => x.QueryHash == queryHash && x.ChangeStamp == changeStamp);
                    }

                    //If data has not changed and results are in cache then do nothing except mark as accessed
                    if (item != null)
                    {
                        item.Results   = results;
                        item.Timestamp = DateTime.Now.AddMinutes(extraMinutes);
                        item.SubKey    = subCacheKey;
                        return;
                    }
                }

                lock (cache)
                {
                    using (var q = new AcquireWriterLock(ServerUtilities.RandomizeGuid(cache.ID, RSeed), "QueryCache"))
                    {
                        lockTime += q.LockTime;

                        //Create a new cache item
                        item = new CacheResultsQuery()
                        {
                            QueryHash     = queryHash,
                            QueryCoreHash = coreHash,
                            RepositoryId  = repositoryId,
                            ChangeStamp   = changeStamp,
                            Results       = results,
                            QueryString   = query.ToString(),
                            ParentId      = RepositoryManager.GetSchemaParentId(repositoryId),
                            Timestamp     = DateTime.Now.AddMinutes(extraMinutes),
                            SubKey        = subCacheKey,
                        };
                        cache.Add(item);
                    }
                }
            }
            catch (Exception ex)
            {
                timer.Stop();
                LoggerCQ.LogError(ex, $"RepositoryId={id}, Elapsed={timer.ElapsedMilliseconds}, ID={id}, LockTime={lockTime}, Count={cache.Count}, QueryHash={queryHash}, ChangeStamp={changeStamp}");
                throw;
            }
            finally
            {
                timer.Stop();
                if (timer.ElapsedMilliseconds > 50)
                {
                    LoggerCQ.LogWarning($"Slow cache set: Elapsed={timer.ElapsedMilliseconds}, LockTime={lockTime}, Count={cache.Count}, ID={id}, Query=\"{query.ToString()}\"");
                }
                LoggerCQ.LogTrace($"QueryCache: Set: SubCacheKey={subCacheKey}");
            }
        }
        public DataQueryResults Get(DatastoreEntities context, RepositorySchema schema, DataQuery query, int repositoryId, Guid id, out bool isCore)
        {
            isCore = false;
            if (!ConfigHelper.AllowCaching)
            {
                return(null);
            }

            long lockTime    = 0;
            int  queryHash   = 0;
            int  coreHash    = 0;
            int  changeStamp = 0;

            var task1 = Task.Factory.StartNew(() =>
            {
                queryHash   = query.GetHashCode();
                coreHash    = query.CoreHashCode();
                changeStamp = RepositoryManager.GetRepositoryChangeStamp(context, repositoryId);
            });

            var timer = new Stopwatch();
            var cache = RepositoryCacheManager.GetCache(id, RepositoryManager.GetSchemaParentId(repositoryId));

            try
            {
                using (var q = new AcquireReaderLock(ServerUtilities.RandomizeGuid(cache.ID, RSeed), "QueryCache"))
                {
                    lockTime = q.LockTime;
                    timer.Start();

                    //Ensure that the pre-calculations are complete
                    task1.Wait();

                    CacheResultsQuery item = null;
                    lock (cache)
                    {
                        item = cache?.FirstOrDefault(x => x.QueryHash == queryHash && x.ChangeStamp == changeStamp);
                    }

                    if (item == null) //return null;
                    {
                        if (ConfigHelper.AllowCoreCache)
                        {
                            //TODO: OPTIMIZE: this is a linear search of thousands of items!!!!
                            //If did not find a match then find see if core properties match
                            //If so we can use the dimension and count values and just replace the records collection
                            lock (cache)
                            {
                                item = cache?.FirstOrDefault(x => x.QueryCoreHash == coreHash && x.ChangeStamp == changeStamp);
                            }
                        }
                        if (item == null)
                        {
                            return(null);
                        }
                        isCore = true;
                        item.HitCount++;
                        return(item.Results);
                    }
                    item.Timestamp = DateTime.Now;
                    item.HitCount++;
                    return(item.Results);
                }
            }
            catch (Exception ex)
            {
                timer.Stop();
                LoggerCQ.LogError(ex, $"RepositoryId={id}, Elapsed={timer.ElapsedMilliseconds}, LockTime={lockTime}, Count={cache.Count}, QueryHash={queryHash}, ChangeStamp={changeStamp}, ID={id}");
                throw;
            }
            finally
            {
                timer.Stop();
                if (timer.ElapsedMilliseconds > 50)
                {
                    LoggerCQ.LogWarning($"Slow cache get: Elapsed={timer.ElapsedMilliseconds}, LockTime={lockTime}, Count={cache.Count}, ID={id}, QueryString=\"{query.ToString()}\"");
                }
            }
        }
        internal RepositorySchema GetSchema(Guid repositoryId, bool clear = false)
        {
            var schemaXml = GetSchemaValue(repositoryId, clear, c => c.Xml);

            return(RepositorySchema.CreateFromXml(schemaXml));
        }
        internal static RepositorySchema LoadSchemaForType(Type dsType, bool inheritedFieldList = false)
        {
            if (dsType == null)
            {
                throw new Exception("The type must be set");
            }

            if (!dsType.GetInterfaces().Any(x => x.Name == typeof(IDatastoreItem).Name))
            {
                throw new Exception($"The item must implement {typeof(IDatastoreItem).Name}.");
            }

            var dsRepositoryAttribute = dsType.GetCustomAttributes().FirstOrDefault(x => x is DatastoreRepositoryAttribute) as DatastoreRepositoryAttribute;

            if (dsRepositoryAttribute == null)
            {
                throw new InvalidOperationException("Cannot create repository for the specified type. Missing DataStoreRepositoryAttribute.");
            }

            var schema = new RepositorySchema();

            schema.Name        = dsRepositoryAttribute.Name;
            schema.ObjectAlias = dsRepositoryAttribute.ObjectAlias;

            Guid rid;

            Guid.TryParse(dsRepositoryAttribute.Id, out rid);
            if (rid == Guid.Empty)
            {
                rid = Guid.NewGuid();
            }
            schema.ID = rid;

            if (!string.IsNullOrEmpty(dsRepositoryAttribute.ParentId))
            {
                schema.ParentID = new Guid(dsRepositoryAttribute.ParentId);
            }
            schema.FieldIndexing = dsRepositoryAttribute.FieldIndexing;

            //var properties = GetTemplateFields(dsType);
            var properties = new List <MemberInfo>();

            properties.AddRange(dsType.GetProperties());
            properties.AddRange(dsType.GetFields());
            #region Loop Fields
            foreach (MemberInfo prop in properties)
            {
                var field = prop.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(DatastoreFieldAttribute)) as CustomAttributeData;
                if (field != null)
                {
                    var isNullable       = false;
                    var fieldDefition    = default(FieldDefinition);
                    var defFieldType     = RepositorySchema.DataTypeConstants.String;
                    var defLength        = 100;
                    var propertyTypeName = "";
                    if (prop is PropertyInfo)
                    {
                        propertyTypeName = ((PropertyInfo)prop).PropertyType.Name;
                        if (propertyTypeName.Contains("Nullable"))
                        {
                            isNullable       = true;
                            propertyTypeName = ((PropertyInfo)prop).PropertyType.GenericTypeArguments.Select(x => x.Name).FirstOrDefault();
                        }
                    }
                    else if (prop is FieldInfo)
                    {
                        propertyTypeName = ((FieldInfo)prop).FieldType.Name;
                        if (propertyTypeName.Contains("Nullable"))
                        {
                            isNullable       = true;
                            propertyTypeName = ((FieldInfo)prop).FieldType.GenericTypeArguments.Select(x => x.Name).FirstOrDefault();
                        }
                    }

                    switch (propertyTypeName)
                    {
                    case "String[]":
                        defFieldType = RepositorySchema.DataTypeConstants.List;
                        isNullable   = true;
                        break;

                    case "String":
                        defFieldType = RepositorySchema.DataTypeConstants.String;
                        isNullable   = true;
                        break;

                    case "Int16":
                    case "Int32":
                    case "UInt32":
                    case "Byte":
                        defFieldType = RepositorySchema.DataTypeConstants.Int;
                        break;

                    case "Int64":
                        defFieldType = RepositorySchema.DataTypeConstants.Int64;
                        break;

                    case "Bool":
                    case "Boolean":
                        defFieldType = RepositorySchema.DataTypeConstants.Bool;
                        break;

                    case "DateTime":
                        defFieldType = RepositorySchema.DataTypeConstants.DateTime;
                        break;

                    case "Double":
                    case "Single":
                    case "Decimal":
                        defFieldType = RepositorySchema.DataTypeConstants.Float;
                        break;

                    case "Char":
                        defFieldType = RepositorySchema.DataTypeConstants.String;
                        defLength    = 1;
                        break;

                    case "GeoCode":
                        defFieldType = RepositorySchema.DataTypeConstants.GeoCode;
                        isNullable   = true;
                        break;

                    default:
                        break;
                    }

                    var name            = GetAttributeValue <string>(field, "Name", prop.Name);
                    var dataType        = GetAttributeValue <RepositorySchema.DataTypeConstants>(field, "DataType", defFieldType);
                    var fieldType       = GetAttributeValue <RepositorySchema.FieldTypeConstants>(field, "FieldType", RepositorySchema.FieldTypeConstants.Field);
                    var isPrimaryKey    = GetAttributeValue <bool>(field, "IsPrimaryKey", false);
                    var isDataGrouping  = GetAttributeValue <bool>(field, "IsDataGrouping", false);
                    var length          = GetAttributeValue <int>(field, "Length", defLength);
                    var allowTextSearch = GetAttributeValue <bool>(field, "AllowTextSearch", false);
                    var isPivot         = GetAttributeValue <bool>(field, "IsPivot", false);
                    var pivotGroup      = GetAttributeValue <string>(field, "PivotGroup", String.Empty);
                    var pivotOrder      = GetAttributeValue <int>(field, "PivotOrder", 0);
                    var description     = GetAttributeValue <string>(field, "Description", String.Empty);
                    var searchAsc       = GetAttributeValue <bool>(field, "SearchAsc", true);
                    var allowIndex      = GetAttributeValue <bool>(field, "AllowIndex", true);

                    if (fieldType == RepositorySchema.FieldTypeConstants.Dimension)
                    {
                        fieldDefition = new DimensionDefinition();
                    }
                    else
                    {
                        fieldDefition = new FieldDefinition();
                    }

                    fieldDefition.Name            = name;
                    fieldDefition.DataType        = dataType;
                    fieldDefition.FieldType       = fieldType;
                    fieldDefition.IsPrimaryKey    = isPrimaryKey;
                    fieldDefition.IsDataGrouping  = isDataGrouping;
                    fieldDefition.AllowNull       = isNullable;
                    fieldDefition.Length          = length;
                    fieldDefition.AllowTextSearch = allowTextSearch;
                    fieldDefition.Name            = name;
                    fieldDefition.IsPivot         = isPivot;
                    fieldDefition.PivotGroup      = pivotGroup;
                    fieldDefition.PivotOrder      = pivotOrder;
                    fieldDefition.Description     = description;
                    fieldDefition.SearchAsc       = searchAsc;
                    fieldDefition.AllowIndex      = allowIndex;

                    //If PK and nullable then error
                    if (isPrimaryKey && isNullable)
                    {
                        throw new Exception("The primary key cannot be nullable.");
                    }

                    if (isPrimaryKey && !allowIndex)
                    {
                        throw new Exception("The primary key must be indexed.");
                    }

                    //Default to unlimited string length
                    if (defFieldType == RepositorySchema.DataTypeConstants.String && defLength < 0)
                    {
                        defLength = 0;
                    }

                    if (fieldType == RepositorySchema.FieldTypeConstants.Dimension)
                    {
                        switch (defFieldType)
                        {
                        case RepositorySchema.DataTypeConstants.Bool:
                        case RepositorySchema.DataTypeConstants.String:
                        case RepositorySchema.DataTypeConstants.List:
                        case RepositorySchema.DataTypeConstants.Int:
                        case RepositorySchema.DataTypeConstants.Int64:
                        case RepositorySchema.DataTypeConstants.DateTime:
                            break;

                        default:
                            throw new Exception($"Field '{name}': The data type '{defFieldType}' cannot be a dimension.");
                        }
                    }

                    if (fieldType == RepositorySchema.FieldTypeConstants.Dimension)
                    {
                        var dimension = fieldDefition as DimensionDefinition;
                        if (dimension == null)
                        {
                            throw new Exception("Dimension is null");
                        }

                        var didx = GetAttributeValue <int?>(field, "Didx", null);
                        if (didx.HasValue)
                        {
                            dimension.DIdx = didx.Value;
                        }

                        dimension.Parent        = GetAttributeValue <string>(field, "Parent", String.Empty);
                        dimension.DimensionType = GetAttributeValue <RepositorySchema.DimensionTypeConstants>(field, "DimensionType", RepositorySchema.DimensionTypeConstants.Normal);
                        var numericBreak = GetAttributeValue <long?>(field, "NumericBreak", null);
                        if ((dimension.DataType == RepositorySchema.DataTypeConstants.Int || dimension.DataType == RepositorySchema.DataTypeConstants.Int64) && numericBreak.HasValue)
                        {
                            dimension.NumericBreak = numericBreak.Value;
                        }
                        else if (numericBreak.HasValue)
                        {
                            throw new Exception("Numeric breaks are only applicable for Integer fields.");
                        }

                        //If the datatype is list then the DimensionType must be list
                        if (dimension.DataType == RepositorySchema.DataTypeConstants.List)
                        {
                            dimension.DimensionType = RepositorySchema.DimensionTypeConstants.List;
                        }
                    }

                    if (GetAttributeValue <bool>(field, "UserPermission", false))
                    {
                        schema.UserPermissionField = fieldDefition;
                    }

                    schema.FieldList.Add(fieldDefition);
                }
            }
            #endregion

            var hasGeo          = schema.FieldList.Any(x => x.DataType == RepositorySchema.DataTypeConstants.GeoCode);
            var hasGroupingData = (schema.FieldList.Where(x => x.IsDataGrouping).Count() > 1);

            if (schema.FieldList.Count == 0)
            {
                throw new Exception("The item must have fields defined.");
            }
            if (schema.FieldList.Count(x => x.IsPrimaryKey) != 1)
            {
                throw new Exception("The item must have exactly one primary key defined.");
            }
            if (schema.FieldList.Count != schema.FieldList.Select(x => x.Name.ToLower()).Distinct().Count())
            {
                throw new Exception("The item cannot have duplicate fields.");
            }
            if (schema.FieldList.Where(x => x.IsDataGrouping).Count() > 1)
            {
                throw new Exception("The item cannot have more than one data group field.");
            }
            if (hasGeo && hasGroupingData)
            {
                throw new Exception("The item cannot have a data grouping and GeoCode field.");
            }

            //This is a child so remove parent fields from schema
            if (schema.ParentID != null && !inheritedFieldList)
            {
                if (!dsType.BaseType.GetInterfaces().Any(x => x.Name == typeof(IDatastoreItem).Name))
                {
                    throw new Exception($"The item base must implement {typeof(IDatastoreItem).Name}.");
                }
                var parentSchema = LoadSchemaForType(dsType.BaseType);
                schema = schema.Subtract(parentSchema);
            }

            foreach (var ditem in schema.DimensionList.Where(x => !string.IsNullOrEmpty(x.Parent)).ToList())
            {
                //Verify that no parent dimension is self-referential
                if (ditem.Parent.Match(ditem.Name))
                {
                    throw new Exception($"The dimension '{ditem.Name}' cannot be its own parent.");
                }

                //Error check that parent dimension actually exists
                if (!schema.DimensionList.Any(x => x.Name == ditem.Parent))
                {
                    throw new Exception($"The dimension '{ditem.Name}' defines a non-existent parent.");
                }
            }

            //TODO: Verify that no parent dimensions cause a cycle (A->B->A)

            return(schema);
        }
Example #15
0
        private void ProcessDeleted()
        {
            try
            {
                using (var context = new DatastoreEntities(ConfigHelper.ConnectionString))
                {
                    const int CHUNKSIZE  = 20000;
                    var       deleteList = context.DeleteQueue.Where(x => x.IsReady).ToList();
                    foreach (var dItem in deleteList)
                    {
                        var rKey = context.Repository.Where(x => x.RepositoryId == dItem.RepositoryId).Select(x => x.UniqueKey).FirstOrDefault();
                        if (rKey != Guid.Empty)
                        {
                            var schema = RepositoryManager.GetSchema(rKey);
                            if (schema != null)
                            {
                                #region Parent Schema
                                RepositorySchema parentSchema = null;
                                if (schema.ParentID != null)
                                {
                                    if (string.IsNullOrEmpty(schema.ObjectAlias))
                                    {
                                        throw new Exception("An inherited repository must have an alias.");
                                    }

                                    parentSchema = RepositoryManager.GetSchema(schema.ParentID.Value, true);
                                    if (parentSchema == null)
                                    {
                                        throw new Exception("Parent schema not found");
                                    }

                                    if (!context.Repository.Any(x => x.UniqueKey == schema.ParentID && x.ParentId == null))
                                    {
                                        throw new Exception("Cannot create an repository from a non-base parent");
                                    }
                                    schema = parentSchema.Merge(schema);
                                }
                                #endregion

                                var listDimensions = schema.FieldList
                                                     .Where(x => x.DataType == RepositorySchema.DataTypeConstants.List &&
                                                            x is DimensionDefinition)
                                                     .Cast <DimensionDefinition>()
                                                     .ToList();

                                foreach (var dimension in listDimensions)
                                {
                                    var timer     = Stopwatch.StartNew();
                                    var listTable = SqlHelper.GetListTableName(schema.ID, dimension.DIdx);
                                    if (parentSchema != null && parentSchema.DimensionList.Any(x => x.DIdx == dimension.DIdx))
                                    {
                                        listTable = SqlHelper.GetListTableName(schema.ParentID.Value, dimension.DIdx);
                                    }

                                    var newParam = new SqlParameter {
                                        DbType = DbType.Int64, IsNullable = false, ParameterName = $"@ParentRowId", Value = dItem.RowId
                                    };

                                    var sbList = new StringBuilder();
                                    sbList.AppendLine($"--MARKER 19");
                                    sbList.AppendLine($"SET ROWCOUNT {CHUNKSIZE};");
                                    sbList.AppendLine("set nocount off;");
                                    sbList.AppendLine($"WITH S([{SqlHelper.RecordIdxField}])");
                                    sbList.AppendLine("AS");
                                    sbList.AppendLine("(");
                                    sbList.AppendLine($"select [RecordIdx] from [DeleteQueueItem] {SqlHelper.NoLockText()}");
                                    sbList.AppendLine($"where [ParentRowId] = {newParam.ParameterName}");
                                    sbList.AppendLine(")");
                                    sbList.AppendLine($"DELETE FROM [{listTable}]");
                                    sbList.AppendLine($"FROM S inner join [{listTable}] on S.[{SqlHelper.RecordIdxField}] = [{listTable}].[{SqlHelper.RecordIdxField}];");
                                    var lastCount = 0;
                                    do
                                    {
                                        lastCount = SqlHelper.ExecuteSql(ConfigHelper.ConnectionString, sbList.ToString(), new[] { newParam });
                                    } while (lastCount >= CHUNKSIZE);

                                    timer.Stop();
                                } //Dimension
                            }
                        }

                        //Remove from queue
                        context.DeleteQueueItem.Where(x => x.ParentRowId == dItem.RowId).Delete();
                        context.DeleteQueue.Where(x => x.RowId == dItem.RowId).Delete();
                        context.SaveChanges();
                    }
                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }
        private CacheResults GetCache(DatastoreEntities context, int id, RepositorySchema schema)
        {
            try
            {
                var dimensionValueTableName       = SqlHelper.GetDimensionValueTableName(schema.ID);
                var dimensionValueTableNameParent = string.Empty;

                lock (_cache)
                {
                    var dimensionStamp = RepositoryManager.GetDimensionChanged(context, id);
                    var retval         = _cache.FirstOrDefault(x => x.RepositoryId == id);

                    //Check repository DimensionStamp and if changed the reload dimensions
                    if (retval != null && retval.DimensionStamp != dimensionStamp)
                    {
                        Clear(id);
                        retval = null;
                    }

                    if (retval == null)
                    {
                        #region Parent table stuff
                        if (schema.ParentID != null)
                        {
                            if (!_parentSchemaCache.ContainsKey(schema.ID))
                            {
                                var parentSchema = RepositoryManager.GetSchema(schema.ParentID.Value);
                                _parentSchemaCache.Add(schema.ID, schema.Subtract(parentSchema));
                            }
                            dimensionValueTableNameParent = SqlHelper.GetDimensionValueTableName(schema.ParentID.Value);
                        }
                        #endregion

                        retval = new CacheResults()
                        {
                            RepositoryId = id, ParentId = RepositoryManager.GetSchemaParentId(id)
                        };
                        _cache.Add(retval);

                        var sb = new StringBuilder();
                        sb.AppendLine($"select v.DIdx, v.DVIdx, v.Value from [{dimensionValueTableName}] v");

                        //If there is a parent schema then UNION its dimension tables
                        if (schema.ParentID != null)
                        {
                            sb.AppendLine($"union select v.DIdx, v.DVIdx, v.Value from [{dimensionValueTableNameParent}] v");
                        }

                        sb.AppendLine("order by DIdx, DVIdx");

                        var ds = SqlHelper.GetDataset(ConfigHelper.ConnectionString, sb.ToString(), null);
                        retval.Results = new List <DimensionItem>();

                        //Load all dimensions
                        foreach (var dimension in schema.DimensionList)
                        {
                            retval.Results.Add(new DimensionItem
                            {
                                DIdx = dimension.DIdx,
                                Name = dimension.Name,
                            });
                        }

                        foreach (DataRow dr in ds.Tables[0].Rows)
                        {
                            var    didx  = (long)dr["DIdx"];
                            long   dvidx = 0;
                            string v     = null;
                            if (dr["DVIdx"] != System.DBNull.Value)
                            {
                                dvidx = (long)dr["DVIdx"];
                                v     = (string)dr["Value"];
                            }
                            var d = retval.Results.FirstOrDefault(x => x.DIdx == didx);
                            if (d == null)
                            {
                                d = new DimensionItem {
                                    DIdx = (int)didx, Name = schema.DimensionList.Where(x => x.DIdx == didx).Select(x => x.Name).FirstOrDefault()
                                };
                                retval.Results.Add(d);
                            }
                            if (dvidx != 0)
                            {
                                d.RefinementList.Add(new RefinementItem {
                                    DVIdx = dvidx, FieldValue = v, DIdx = didx
                                });
                            }

                            //Rearrange all refinements alpha (for debugging and such)
                            //retval.Results.ForEach(ditem => ditem.RefinementList = ditem.RefinementList.OrderBy(x => x.FieldValue).ToList());
                        }
                    }
                    retval.DimensionStamp = dimensionStamp;
                    retval.Timestamp      = DateTime.Now; //Accessed
                    return(retval);
                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }
        public List <DimensionItem> Get(DatastoreEntities context, RepositorySchema schema, int id, IEnumerable <DataFieldUpdate> list = null)
        {
            if (schema == null)
            {
                throw new Exception("The schema is null");
            }

            try
            {
                var dimensionValueTableName       = SqlHelper.GetDimensionValueTableName(schema.ID);
                var dimensionValueTableNameParent = string.Empty;
                var parameters = new List <SqlParameter>();
                var didxParam  = 0;

                lock (_cache)
                {
                    var retval = GetCache(context, id, schema);

                    #region Do this after "GetCache" call as it will flush the cache if need be
                    //If there is a parent repository then get parent schema as will will need to know which dimension table to use for different fields
                    RepositorySchema diff = null;
                    if (schema.ParentID != null)
                    {
                        if (!_parentSchemaCache.ContainsKey(schema.ID))
                        {
                            var parentSchema = RepositoryManager.GetSchema(schema.ParentID.Value);
                            _parentSchemaCache.Add(schema.ID, schema.Subtract(parentSchema));
                        }
                        diff = _parentSchemaCache[schema.ID];
                        dimensionValueTableNameParent = SqlHelper.GetDimensionValueTableName(schema.ParentID.Value);
                    }
                    #endregion

                    var sb = new StringBuilder();
                    parameters = new List <SqlParameter>();
                    didxParam  = 0;
                    var dvidxParam = 0;

                    #region Find new refinements in list

                    //Create a cache of all next keys
                    var _nextKeys = new Dictionary <DimensionItem, long>();
                    //TODO: this is taking too long on every request (~1%)
                    retval.Results.ForEach(z => _nextKeys.Add(z, z.RefinementList.OrderByDescending(x => x.DVIdx).Select(x => x.DVIdx).FirstOrDefault() + 1));

                    var paramIndex = 0;
                    var needSave   = false;
                    if (list != null)
                    {
                        foreach (var item in list.Where(x => x.FieldValue != null))
                        {
                            var values    = new HashSet <string>();
                            var dimension = schema.FieldList.FirstOrDefault(x => x.Name == item.FieldName) as DimensionDefinition;
                            if (dimension != null)
                            {
                                if (dimension.DataType == RepositorySchema.DataTypeConstants.List)
                                {
                                    var l = (string[])item.FieldValue;
                                    foreach (var v in l)
                                    {
                                        if (!values.Contains(v))
                                        {
                                            values.Add(v);
                                        }
                                    }
                                }
                                else
                                {
                                    if ((dimension.DataType == RepositorySchema.DataTypeConstants.Int || dimension.DataType == RepositorySchema.DataTypeConstants.Int64) && dimension.NumericBreak != null && dimension.NumericBreak > 0)
                                    {
                                        var v      = Convert.ToInt64(item.FieldValue);
                                        var scaled = ((v / dimension.NumericBreak) * dimension.NumericBreak).ToString();
                                        if (!values.Contains(scaled))
                                        {
                                            values.Add(scaled);
                                        }
                                    }
                                    else
                                    {
                                        var v = SqlHelper.GetTypedDimValue(dimension.DataType, item.FieldValue);
                                        if (!values.Contains(v))
                                        {
                                            values.Add(v);
                                        }
                                    }
                                }
                            }


                            //for unique values if not exist then insert
                            foreach (var v in values?.Where(x => x != null).ToList())
                            {
                                long baseDVIdx;
                                if (schema.ParentID != null && diff.DimensionList.Any(x => x.DIdx == dimension.DIdx))
                                {
                                    baseDVIdx = ((dimension.DIdx - Constants.DGROUPEXT) + 1) * Constants.DVALUEGROUPEXT; //Child Repository
                                }
                                else
                                {
                                    baseDVIdx = ((dimension.DIdx - Constants.DGROUP) + 1) * Constants.DVALUEGROUP; //Normal
                                }
                                var dbDimension = retval.Results.FirstOrDefault(x => x.DIdx == dimension.DIdx);
                                if (!dbDimension.RefinementList.Any(x => x.FieldValue == v))
                                {
                                    if (!_nextKeys.ContainsKey(dbDimension)) //If was empty then default to base index
                                    {
                                        _nextKeys.Add(dbDimension, baseDVIdx);
                                    }
                                    if (_nextKeys[dbDimension] == 1) //If was empty then default to base index
                                    {
                                        _nextKeys[dbDimension] = baseDVIdx;
                                    }

                                    var nextDVIdx = _nextKeys[dbDimension];
                                    _nextKeys[dbDimension]++;

                                    var newParam = new SqlParameter {
                                        DbType = DbType.String, IsNullable = false, ParameterName = $"@__z{paramIndex}", Value = v
                                    };
                                    parameters.Add(newParam);
                                    paramIndex++;
                                    if (diff == null)
                                    {
                                        //This is for stand-alone tables. There is only one dimension table
                                        var paramDIdx = new SqlParameter {
                                            DbType = DbType.Int64, IsNullable = false, ParameterName = $"@__didx{didxParam}", Value = dimension.DIdx
                                        };
                                        parameters.Add(paramDIdx);
                                        var paramDVIdx = new SqlParameter {
                                            DbType = DbType.Int64, IsNullable = false, ParameterName = $"@__dvidx{dvidxParam}", Value = nextDVIdx
                                        };
                                        parameters.Add(paramDVIdx);
                                        didxParam++;
                                        dvidxParam++;

                                        sb.AppendLine($"if not exists(select * from [{dimensionValueTableName}] where [DIdx] = {paramDIdx.ParameterName} and [DVIdx] = {paramDVIdx.ParameterName})");
                                        sb.AppendLine($"insert into [{dimensionValueTableName}] ([DIdx], [DVIdx], [Value]) values ({paramDIdx.ParameterName}, {paramDVIdx.ParameterName}, {newParam.ParameterName})");
                                    }
                                    else
                                    {
                                        //This is for inherited tables. Figure out which dimension table to use
                                        var tempTable = dimensionValueTableNameParent;
                                        if (diff.DimensionList.Any(x => x.DIdx == dimension.DIdx))
                                        {
                                            tempTable = dimensionValueTableName;
                                        }

                                        var paramDIdx = new SqlParameter {
                                            DbType = DbType.Int64, IsNullable = false, ParameterName = $"@__didx{didxParam}", Value = dimension.DIdx
                                        };
                                        parameters.Add(paramDIdx);
                                        var paramDVIdx = new SqlParameter {
                                            DbType = DbType.Int64, IsNullable = false, ParameterName = $"@__dvidx{dvidxParam}", Value = nextDVIdx
                                        };
                                        parameters.Add(paramDVIdx);
                                        didxParam++;
                                        dvidxParam++;

                                        sb.AppendLine($"if not exists(select * from [{tempTable}] where [DIdx] = {paramDIdx.ParameterName} and [DVIdx] = {paramDVIdx.ParameterName})");
                                        sb.AppendLine($"insert into [{tempTable}] ([DIdx], [DVIdx], [Value]) values ({paramDIdx.ParameterName}, {paramDVIdx.ParameterName}, {newParam.ParameterName})");
                                    }

                                    needSave = true;
                                }
                            }
                        }

                        if (needSave)
                        {
                            SqlHelper.ExecuteSql(ConfigHelper.ConnectionString, sb.ToString(), parameters, false);
                            Clear(id);
                            SqlHelper.MarkDimensionsChanged(id);
                            retval   = GetCache(context, id, schema);
                            needSave = false;
                        }
                    }
                    #endregion

                    return(retval.Results);
                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }