Exemple #1
0
 /// <summary>
 /// Hack the query
 /// </summary>
 public bool HackQuery(QueryBuilder builder, SqlStatement sqlStatement, SqlStatement whereClause, Type tmodel, PropertyInfo property, string queryPrefix, QueryPredicate predicate, object values, IEnumerable <TableMapping> scopedTables, params KeyValuePair <string, object>[] queryFilter)
 {
     if (typeof(SecurityUser) == tmodel && property.Name == nameof(SecurityUser.UserEntity))
     {
         var userkey         = TableMapping.Get(typeof(DbUserEntity)).GetColumn(nameof(DbUserEntity.SecurityUserKey), false);
         var personSubSelect = builder.CreateQuery <UserEntity>(queryFilter.Select(p => new KeyValuePair <String, Object>(p.Key.Replace("userEntity.", ""), p.Value)), null, userkey);
         var userIdKey       = TableMapping.Get(typeof(DbSecurityUser)).PrimaryKey.FirstOrDefault();
         whereClause.And($"{userIdKey.Name} IN (").Append(personSubSelect).Append(")");
         return(true);
     }
     return(false);
 }
        public void TestCreateWithNonAutoIncrementPrimaryKey()
        {
            var table = TableMapping.Get <TestObjectWithNonAutoIncrementPrimaryKey>();

            var id = table.Columns["Id"];

            Assert.Equal(id.ClrType, typeof(long));
            // No way to test the PropertyInfo directly
            Assert.Equal(id.Metadata.CollationSequence, "BINARY");
            Assert.Equal(id.Metadata.DeclaredType, "INTEGER");
            Assert.True(id.Metadata.HasNotNullConstraint);
            Assert.False(id.Metadata.IsAutoIncrement);
            Assert.True(id.Metadata.IsPrimaryKeyPart);
        }
        /// <summary>
        /// Converts a <see cref="DbMailMessage"/> instance to a <see cref="MailMessage"/> instance.
        /// </summary>
        /// <param name="dataInstance">The db alert message instance.</param>
        /// <param name="context">The data context.</param>
        /// <param name="principal">The authentication context.</param>
        /// <returns>Returns the converted instance.</returns>
        public override MailMessage ToModelInstance(object dataInstance, DataContext context)
        {
            var modelInstance = base.ToModelInstance(dataInstance, context);

            modelInstance.Flags = (MailMessageFlags)(dataInstance as DbMailMessage).Flags;
            var tableMapping = TableMapping.Get(typeof(DbSecurityUser));

            SqlStatement rcptStatement = context.CreateSqlStatement()
                                         .SelectFrom(tableMapping.OrmType, tableMapping.Columns.First(o => o.IsPrimaryKey))
                                         .InnerJoin <DbSecurityUser, DbMailMessageRcptTo> (o => o.Key, o => o.SourceKey)
                                         .Where <DbMailMessageRcptTo>(o => o.Key == modelInstance.Key).Build();

            modelInstance.RcptToXml = context.Query <DbSecurityUser>(rcptStatement).Select(o => o.Key).ToList();
            return(modelInstance);
        }
            /// <summary>
            /// Ensure the effective version sequence is set
            /// </summary>
            public override TModel UpdateInternal(DataContext context, TModel data)
            {
                if (!data.EffectiveVersionSequenceId.HasValue)
                {
                    var dbSourceType = this.m_settingsProvider.GetMapper().MapModelType(data.SourceType);
                    var tableMap     = TableMapping.Get(dbSourceType);
                    var sql          = context.CreateSqlStatement()
                                       .SelectFrom(dbSourceType, tableMap.GetColumn(nameof(IDbVersionedData.VersionSequenceId)))
                                       .Where($"{tableMap.GetColumn(nameof(IDbVersionedData.Key)).Name} = ?", data.SourceEntityKey)
                                       .And($"{tableMap.GetColumn(nameof(IDbVersionedData.ObsoletionTime)).Name} IS NOT NULL")
                                       .Append($"ORDER BY {tableMap.GetColumn(nameof(IDbVersionedData.VersionSequenceId))} DESC");

                    data.EffectiveVersionSequenceId = context.FirstOrDefault <Int32>(sql);
                }
                return(base.UpdateInternal(context, data));
            }
Exemple #5
0
        public void TestInitTable()
        {
            var table = TableMapping.Get <TestObject>();

            using (var db = SQLite3.OpenInMemory())
            {
                db.InitTable <TestObject>();
                var dbIndexes = db.GetIndexInfo(table.TableName);
                Assert.Equal(table.Indexes, dbIndexes);

                var dbColumns = db.GetTableInfo(table.TableName);
                Assert.Equal(
                    table.Columns.Select(x => new KeyValuePair <string, TableColumnMetadata>(x.Key, x.Value.Metadata)),
                    dbColumns);
            }
        }
Exemple #6
0
        public void TestInitTableWithMigration()
        {
            var tableOriginal    = TableMapping.Get <TestMutableObject>();
            var tableOriginalOrm = Orm.ResultSet.RowToObject <TestMutableObject>();

            var tableNew    = TableMapping.Get <TestMutableObjectUpdated>();
            var tableNewOrm = Orm.ResultSet.RowToObject <TestMutableObjectUpdated>();

            using (var db = SQLite3.OpenInMemory())
            {
                db.InitTable <TestMutableObject>();
                var dbIndexes = db.GetIndexInfo(tableOriginal.TableName);
                Assert.Equal(tableOriginal.Indexes, dbIndexes);

                var dbColumns = db.GetTableInfo(tableOriginal.TableName);
                Assert.Equal(
                    tableOriginal.Columns.Select(x => new KeyValuePair <string, TableColumnMetadata>(x.Key, x.Value.Metadata)),
                    dbColumns);

                var insertedOriginal = db.InsertOrReplace(new TestMutableObject()
                {
                    Value = "test"
                }, tableOriginalOrm);

                db.InitTable <TestMutableObjectUpdated>();
                dbIndexes = db.GetIndexInfo(tableOriginal.TableName);
                Assert.Equal(tableNew.Indexes, dbIndexes);

                dbColumns = db.GetTableInfo(tableOriginal.TableName);
                Assert.Equal(
                    tableNew.Columns.Select(x => new KeyValuePair <string, TableColumnMetadata>(x.Key, x.Value.Metadata)),
                    dbColumns);

                TestMutableObjectUpdated found;
                if (db.TryFind <TestMutableObjectUpdated>(insertedOriginal.Id.Value, tableNewOrm, out found))
                {
                    Assert.Equal(found.NotNullReference, "default");
                }
                else
                {
                    Assert.True(false);
                }
            }
        }
        /// <summary>
        /// Get secure key for the unknown application name
        /// </summary>
        public byte[] GetSecureKey(string name)
        {
            using (DataContext dataContext = this.m_configuration.Provider.GetWriteConnection())
                try
                {
                    dataContext.Open();

                    var dbType = TableMapping.Get(typeof(DbSecurityApplication));
                    var stmt   = dataContext.CreateSqlStatement().SelectFrom(dbType.OrmType, dbType.Columns.First(o => o.SourceProperty.Name == nameof(DbSecurityApplication.Secret)))
                                 .Where <DbSecurityApplication>(o => o.PublicId == name);

                    var secret = dataContext.FirstOrDefault <String>(stmt.Build());

                    // Secret is the key
                    return(secret.ParseHexString());
                }
                catch (Exception e)
                {
                    this.m_traceSource.TraceEvent(EventLevel.Error, "Error setting secret for {0} : {1}", name, e);
                    throw new DataPersistenceException($"Error getting secure key for {name}", e);
                }
        }
        private static string CompileExpr(this Expression This)
        {
            if (This is BinaryExpression)
            {
                var bin = (BinaryExpression)This;

                var leftExpr  = bin.Left.CompileExpr();
                var rightExpr = bin.Right.CompileExpr();

                if (rightExpr == "NULL" && bin.NodeType == ExpressionType.Equal)
                {
                    if (bin.NodeType == ExpressionType.Equal)
                    {
                        return($"({leftExpr} IS NULL)");
                    }
                    else if (rightExpr == "NULL" && bin.NodeType == ExpressionType.NotEqual)
                    {
                        return($"({leftExpr} IS NOT NULL)");
                    }
                }

                return($"({leftExpr} {GetSqlName(bin)} {rightExpr})");
            }
            else if (This is ParameterExpression)
            {
                var param = (ParameterExpression)This;
                return($":{param.Name}");
            }
            else if (This is MemberExpression)
            {
                var member = (MemberExpression)This;

                if (member.Expression != null && member.Expression.NodeType == ExpressionType.Parameter)
                {
                    // This is a column in the table, output the column name
                    var tableName  = TableMapping.Get(member.Expression.Type).TableName;
                    var columnName = ((PropertyInfo)member.Member).GetColumnName();
                    return($"\"{tableName}\".\"{columnName}\"");
                }
                else
                {
                    return(member.EvaluateExpression().ConvertToSQLiteValue().ToSqlString());
                }
            }
            else if (This.NodeType == ExpressionType.Not)
            {
                var operandExpr = ((UnaryExpression)This).Operand;
                return($"NOT({operandExpr.CompileExpr()})");
            }
            else if (This is ConstantExpression)
            {
                return(This.EvaluateExpression().ConvertToSQLiteValue().ToSqlString());
            }
            else if (This is MethodCallExpression)
            {
                var call = (MethodCallExpression)This;
                var args = new String[call.Arguments.Count];

                var obj = call.Object != null?call.Object.CompileExpr() : null;

                for (var i = 0; i < args.Length; i++)
                {
                    args[i] = call.Arguments[i].CompileExpr();
                }

                if (call.Method.Name == "Like" && args.Length == 2)
                {
                    return($"({args[0]} LIKE {args[1]})");
                }
                else if (call.Method.Name == "Contains" && args.Length == 2)
                {
                    return($"({args[1]} IN {args[0]})");
                }
                else if (call.Method.Name == "Contains" && args.Length == 1)
                {
                    if (call.Object != null && call.Object.Type == typeof(string))
                    {
                        return($"({obj} LIKE ('%' || {args[0]} || '%'))");
                    }
                    else
                    {
                        return($"({args[0]} IN {obj})");
                    }
                }
                else if (call.Method.Name == "StartsWith" && args.Length == 1)
                {
                    return($"({obj} LIKE ({args[0]} || '%'))");
                }
                else if (call.Method.Name == "EndsWith" && args.Length == 1)
                {
                    return($"({obj} LIKE ('%' || {args[0]}))");
                }
                else if (call.Method.Name == "Equals" && args.Length == 1)
                {
                    return($"({obj} = ({args[0]}))");
                }
                else if (call.Method.Name == "Is" && args.Length == 2)
                {
                    return($"({args[0]} IS {args[1]})");
                }
                else if (call.Method.Name == "IsNot" && args.Length == 2)
                {
                    return($"({args[0]} IS NOT {args[1]})");
                }
            }
            else if (This.NodeType == ExpressionType.Convert)
            {
                var u = (UnaryExpression)This;

                // Let SQLite handle the casting for us
                var operand = u.Operand;
                return(operand.CompileExpr());

                // FIXME: Might still want to support a direct cast here if the
                // operand is a constant value or a function that is evaluated

                /*
                 * var ty = u.Type;
                 * var value = EvaluateExpression(u.Operand);
                 *
                 * return value.ConvertTo(ty).ConvertToSQLiteValue().ToSqlString();*/
            }
            else if (This.NodeType == ExpressionType.Default)
            {
                var d  = (DefaultExpression)This;
                var ty = d.Type;
                if (ty == typeof(void))
                {
                    return("");
                }
            }
            else if (This.NodeType == ExpressionType.Lambda)
            {
                var expr = (LambdaExpression)This;
                return(CompileExpr(expr.Body));
            }

            throw new NotSupportedException($"Cannot compile: {This.NodeType.ToString()}");
        }
Exemple #9
0
        /// <summary>
        /// Try get by classifier
        /// </summary>
        public static IIdentifiedEntity TryGetExisting(this IIdentifiedEntity me, LocalDataContext context, bool forceDbSearch = false)
        {
            // Is there a classifier?
            var idpInstance = LocalPersistenceService.GetPersister(me.GetType()) as ILocalPersistenceService;

            if (idpInstance == null)
            {
                return(null);
            }
            //if (me.Key?.ToString() == "e4d3350b-b0f5-45c1-80ba-49e3844cbcc8")
            //    System.Diagnostics.Debugger.Break();

            IIdentifiedEntity existing = null;

            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;
            }

            var classAtt = me.GetType().GetTypeInfo().GetCustomAttribute <KeyLookupAttribute>();

            if (classAtt != null && existing == null)
            {
                // Get the domain type
                var dataType = LocalPersistenceService.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(LocalPersistenceService.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);
        }
Exemple #10
0
        /// <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  = AdoAuditPersistenceService.GetPersister(me.GetType()) as IAdoPersistenceService;
            var cacheService = ApplicationServiceContext.Current.GetService <IDataCachingService>();

            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
                ApplicationServiceContext.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) as IIdentifiedEntity;
            }

            var classAtt = me.GetType().GetCustomAttribute <KeyLookupAttribute>();

            if (classAtt != null && existing == null)
            {
                // Get the domain type
                var dataType = AdoAuditPersistenceService.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(AdoAuditPersistenceService.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 ??
                               context.GetCacheCommit(objIdCache);
                }
                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) as IIdentifiedEntity;
                        }
                    }
                }
            }

            return(existing);
        }
        /// <summary>
        /// Hack the particular query
        /// </summary>
        public bool HackQuery(QueryBuilder builder, SqlStatement sqlStatement, SqlStatement whereClause, Type tmodel, PropertyInfo property, String queryPrefix, QueryPredicate predicate, object values, IEnumerable <TableMapping> scopedTables)
        {
            // Hack mnemonic queries
            if (typeof(Concept).GetTypeInfo().IsAssignableFrom(property.PropertyType.GetTypeInfo()) && predicate.SubPath == "mnemonic")
            {
                // Has this already been joined?
                var mapType = property.DeclaringType;
                if (mapType.GetTypeInfo().IsAbstract)
                {
                    mapType = tmodel;
                }
                var declType    = TableMapping.Get(this.m_mapper.MapModelType(mapType));
                var keyProperty = property.PropertyType == typeof(Guid) ? property : mapType.GetRuntimeProperty(property.Name + "Key");
                var declProp    = declType.GetColumn(this.m_mapper.MapModelProperty(mapType, declType.OrmType, keyProperty));
                if (declProp.ForeignKey == null)
                {
                    return(false);                             // No FK link
                }
                var    tblMap       = TableMapping.Get(this.m_mapper.MapModelType(property.PropertyType));
                var    fkTbl        = TableMapping.Get(declProp.ForeignKey.Table);
                string directFkName = $"{queryPrefix}{fkTbl.TableName}";

                // We have to join to the FK table
                if (!declProp.IsAlwaysJoin)
                {
                    var fkColumn = fkTbl.GetColumn(declProp.ForeignKey.Column);
                    sqlStatement.Append($" INNER JOIN {fkTbl.TableName} AS {directFkName}_{declProp.Name} ON ({queryPrefix}{declType.TableName}.{declProp.Name} = {directFkName}_{declProp.Name}.{fkColumn.Name})");
                    directFkName += $"_{declProp.Name}";
                }

                // We aren't yet joined to our table, we need to join to our table though!!!!
                if (declProp.ForeignKey.Table != tblMap.OrmType)
                {
                    var fkKeyColumn = fkTbl.Columns.FirstOrDefault(o => o.ForeignKey?.Table == tblMap.OrmType && o.Name == tblMap.PrimaryKey.First().Name) ??
                                      tblMap.Columns.FirstOrDefault(o => o.ForeignKey?.Table == fkTbl.OrmType && o.Name == fkTbl.PrimaryKey.First().Name);
                    if (fkKeyColumn == null)
                    {
                        return(false);                     // couldn't find the FK link
                    }
                    // Now we want to filter our FK
                    var tblName = $"{queryPrefix}{declProp.Name}_{tblMap.TableName}";
                    sqlStatement.Append($" INNER JOIN {tblMap.TableName} AS {tblName} ON ({directFkName}.{fkKeyColumn.Name} = {tblName}.{fkKeyColumn.Name})");

                    // Append the where clause
                    whereClause.And(builder.CreateWhereCondition(property.PropertyType, predicate.SubPath, values, $"{queryPrefix}{declProp.Name}_", new List <TableMapping>()
                    {
                        tblMap
                    }, tblName));
                }
                else
                {
                    // Append the where clause
                    whereClause.And(builder.CreateWhereCondition(property.PropertyType, predicate.SubPath, values, $"{queryPrefix}{declProp.Name}_", new List <TableMapping>()
                    {
                        tblMap
                    }, $"{directFkName}"));
                }

                return(true);
            }
            else
            {
                return(false);
            }
        }
        /// <summary>
        /// Query internal for versioned data elements
        /// </summary>
        protected override IEnumerable <Object> DoQueryInternal(DataContext context, Expression <Func <TModel, bool> > primaryQuery, Guid queryId, int offset, int?count, out int totalResults, ModelSort <TModel>[] orderBy, bool countResults = true, bool overrideFuzzyTotalSetting = false)
        {
#if DEBUG
            Stopwatch sw = new Stopwatch();
            sw.Start();
#endif

            // Query has been registered?
            if (queryId != Guid.Empty && this.m_queryPersistence?.IsRegistered(queryId) == true)
            {
                return(this.GetStoredQueryResults(queryId, offset, count, out totalResults));
            }

            // Queries to be performed
            IOrmResultSet retVal = null;
            Expression <Func <TModel, bool> >[] queries = new Expression <Func <TModel, bool> >[] { primaryQuery };
            // Are we intersecting?
            if (context.Data.TryGetValue("UNION", out object others) &&
                others is Expression <Func <TModel, bool> >[])
            {
                context.Data.Remove("UNION");
                queries = queries.Concat((Expression <Func <TModel, bool> >[])others).ToArray();
            }

            try
            {
                // Execute queries
                foreach (var q in queries)
                {
                    var query = q;
                    // Is obsoletion time already specified? (this is important for versioned objects if we want to get the most current version of the object)
                    if (!query.ToString().Contains("ObsoletionTime") && !query.ToString().Contains("VersionKey"))
                    {
                        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);
                    }

                    SqlStatement domainQuery = null;
                    var          expr        = this.m_settingsProvider.GetMapper().MapModelExpression <TModel, TDomain, bool>(query, false);

                    // Fast query?
                    if (orderBy?.Length > 0 || q.ToString().Contains("VersionKey"))
                    {
                        if (expr != null)
                        {
                            domainQuery = context.CreateSqlStatement <TDomain>().SelectFrom(typeof(TDomain), typeof(TDomainKey))
                                          .InnerJoin <TDomain, TDomainKey>(o => o.Key, o => o.Key)
                                          .Where <TDomain>(expr).Build();
                        }
                        else
                        {
                            domainQuery = this.m_settingsProvider.GetQueryBuilder().CreateQuery(query).Build();
                        }

                        // Create or extend queries
                        if (retVal == null)
                        {
                            retVal = this.DomainQueryInternal <CompositeResult <TDomain, TDomainKey> >(context, domainQuery);
                        }
                        else
                        {
                            retVal = retVal.Union(this.DomainQueryInternal <CompositeResult <TDomain, TDomainKey> >(context, domainQuery));
                        }
                    }
                    else
                    {
                        var linkCol       = TableMapping.Get(typeof(TDomain)).GetColumn(typeof(TDomain).GetProperty(nameof(DbIdentified.Key)));
                        var versionSeqCol = TableMapping.Get(typeof(TDomain)).GetColumn(typeof(TDomain).GetProperty(nameof(DbVersionedData.VersionSequenceId)));
                        if (expr != null)
                        {
                            domainQuery = context.CreateSqlStatement <TDomain>().SelectFrom(linkCol, versionSeqCol)
                                          .InnerJoin <TDomain, TDomainKey>(o => o.Key, o => o.Key)
                                          .Where <TDomain>(expr).Build();
                        }
                        else
                        {
                            domainQuery = this.m_settingsProvider.GetQueryBuilder().CreateQuery(query, linkCol, versionSeqCol).Build();
                        }

                        // Create or extend queries
                        if (retVal == null)
                        {
                            retVal = this.DomainQueryInternal <Guid>(context, domainQuery);
                        }
                        else
                        {
                            retVal = retVal.Union(this.DomainQueryInternal <Guid>(context, domainQuery));
                        }
                    }
                }

                // HACK: More than one query which indicates union was used, we need to wrap in a select statement to be adherent to SQL standard on Firebird and PSQL
                if (queries.Count() > 1)
                {
                    var query = this.AppendOrderBy(context.CreateSqlStatement("SELECT * FROM (").Append(retVal.ToSqlStatement()).Append(") AS domain_query "), orderBy);
                    retVal = this.DomainQueryInternal <Guid>(context, query);
                }
                else
                {
                    this.AppendOrderBy(retVal.Statement, orderBy);
                }

                // Only perform count
                if (count == 0)
                {
                    totalResults = retVal.Count();
                    return(new List <CompositeResult <TDomain, TDomainKey> >());
                }
                else
                {
                    if (context.Data.TryGetValue("principal", out object pRaw))
                    {
                        var currentPrincipal = pRaw as IPrincipal;
                        countResults = countResults && currentPrincipal != AuthenticationContext.SystemPrincipal;
                        overrideFuzzyTotalSetting = currentPrincipal == AuthenticationContext.SystemPrincipal;
                    }

                    if (queryId != Guid.Empty && ApplicationServiceContext.Current.GetService <IQueryPersistenceService>() != null)
                    {
                        var keys = retVal.Keys <Guid>().Take(count.Value * 20).OfType <Guid>().ToArray();
                        totalResults = keys.Length;
                        this.m_queryPersistence?.RegisterQuerySet(queryId, keys, queries, totalResults);
                        if (totalResults == count.Value * 20) // result set is larger than 10,000 load in background
                        {
                            ApplicationServiceContext.Current.GetService <IThreadPoolService>().QueueUserWorkItem(o =>
                            {
                                var dynParm    = o as dynamic;
                                var subContext = dynParm.Context as DataContext;
                                var statement  = dynParm.Statement as SqlStatement;
                                var type       = dynParm.Type as Type;
                                var qid        = (Guid)dynParm.QueryId;
                                try
                                {
                                    // Get the rest of the keys
                                    Guid[] sk = null;
                                    if (type == typeof(OrmResultSet <Guid>))
                                    {
                                        sk = subContext.Query <Guid>(statement).ToArray();
                                    }
                                    else
                                    {
                                        sk = subContext.Query <CompositeResult <TDomain, TDomainKey> >(statement).Keys <Guid>(false).ToArray();
                                    }
                                    this.m_queryPersistence?.RegisterQuerySet(queryId, sk, statement, sk.Length);
                                }
                                finally
                                {
                                    subContext.Dispose();
                                }
                            }, new { Context = context.OpenClonedContext(), Statement = retVal.Statement.Build(), QueryId = queryId, Type = retVal.GetType() });
                        }
                        return(keys.Skip(offset).Take(count.Value).OfType <Object>());
                    }
                    else if (count.HasValue && countResults && !overrideFuzzyTotalSetting && !this.m_settingsProvider.GetConfiguration().UseFuzzyTotals)
                    {
                        totalResults = retVal.Count();
                    }
                    else
                    {
                        totalResults = 0;
                    }

                    // Fuzzy totals - This will only fetch COUNT + 1 as the total results
                    if (count.HasValue)
                    {
                        if ((overrideFuzzyTotalSetting || this.m_settingsProvider.GetConfiguration().UseFuzzyTotals) && totalResults == 0)
                        {
                            var fuzzResults = retVal.Skip(offset).Take(count.Value + 1).OfType <Object>().ToList();
                            totalResults = fuzzResults.Count() + offset;
                            return(fuzzResults.Take(count.Value));
                        }
                        else // We already counted as part of the queryId so no need to take + 1
                        {
                            return(retVal.Skip(offset).Take(count.Value).OfType <Object>());
                        }
                    }
                    else
                    {
                        return(retVal.Skip(offset).OfType <Object>());
                    }
                }
            }
            catch (Exception ex)
            {
                if (retVal != null)
                {
                    this.m_tracer.TraceEvent(EventLevel.Error, context.GetQueryLiteral(retVal.ToSqlStatement()));
                }
                throw new DataPersistenceException("Error executing query", ex);
            }
            finally
            {
#if DEBUG
                sw.Stop();
                //  this.m_tracer.TraceVerbose("Query {0} in {1} ms", context.GetQueryLiteral(retVal.ToSqlStatement()), sw.ElapsedMilliseconds);
#endif
            }
        }
        public void TestCreate()
        {
            var table = TableMapping.Get <TestObjectWithAutoIncrementPrimaryKeyAndDefaultTableName>();

            Assert.Equal(table.TableName, "TestObjectWithAutoIncrementPrimaryKeyAndDefaultTableName");

            var expectedColumns = new string[] { "Id", "Uri", "B", "NotNull", "Collated", "Value", "AFloat", "NullableInt" };

            Assert.Equal(expectedColumns, table.Columns.Keys);

            var expectedIndexes = new Dictionary <string, IndexInfo>
            {
                { "TestObjectWithAutoIncrementPrimaryKeyAndDefaultTableName_Uri", new IndexInfo(false, new string[] { "Uri" }) },
                { "TestObjectWithAutoIncrementPrimaryKeyAndDefaultTableName_B", new IndexInfo(true, new string[] { "B" }) },
                { "TestObjectWithAutoIncrementPrimaryKeyAndDefaultTableName_NotNull_Collated", new IndexInfo(false, new string[] { "NotNull", "Collated" }) },
                { "named", new IndexInfo(true, new string[] { "Uri", "B" }) }
            };

            var indexes = table.Indexes;

            Assert.Equal(indexes, expectedIndexes);

            var idMapping = table.Columns["Id"];

            // Subtle touch, but nullables are ignored in the CLR type.
            Assert.Equal(idMapping.ClrType, typeof(Nullable <long>));
            // No way to test the PropertyInfo directly
            Assert.Equal(idMapping.Metadata.CollationSequence, "BINARY");
            Assert.Equal(idMapping.Metadata.DeclaredType, "INTEGER");
            Assert.True(idMapping.Metadata.HasNotNullConstraint);
            Assert.True(idMapping.Metadata.IsAutoIncrement);
            Assert.True(idMapping.Metadata.IsPrimaryKeyPart);

            var uriMapping = table.Columns["Uri"];

            Assert.Equal(uriMapping.ClrType, typeof(Uri));
            // No way to test the PropertyInfo directly
            Assert.Equal(uriMapping.Metadata.CollationSequence, "BINARY");
            Assert.Equal(uriMapping.Metadata.DeclaredType, "TEXT");
            Assert.False(uriMapping.Metadata.HasNotNullConstraint);
            Assert.False(uriMapping.Metadata.IsAutoIncrement);
            Assert.False(uriMapping.Metadata.IsPrimaryKeyPart);

            var bMapping = table.Columns["B"];

            Assert.Equal(bMapping.ClrType, typeof(string));
            // No way to test the PropertyInfo directly
            Assert.Equal(bMapping.Metadata.CollationSequence, "BINARY");
            Assert.Equal(bMapping.Metadata.DeclaredType, "TEXT");
            Assert.False(bMapping.Metadata.HasNotNullConstraint);
            Assert.False(bMapping.Metadata.IsAutoIncrement);
            Assert.False(bMapping.Metadata.IsPrimaryKeyPart);

            Assert.False(table.Columns.ContainsKey("Ignored"));

            var notNullMapping = table.Columns["NotNull"];

            Assert.Equal(notNullMapping.ClrType, typeof(byte[]));
            // No way to test the PropertyInfo directly
            Assert.Equal(notNullMapping.Metadata.CollationSequence, "BINARY");
            Assert.Equal(notNullMapping.Metadata.DeclaredType, "BLOB");
            Assert.True(notNullMapping.Metadata.HasNotNullConstraint);
            Assert.False(notNullMapping.Metadata.IsAutoIncrement);
            Assert.False(notNullMapping.Metadata.IsPrimaryKeyPart);

            var collatedMapping = table.Columns["Collated"];

            Assert.Equal(collatedMapping.ClrType, typeof(string));
            // No way to test the PropertyInfo directly
            Assert.Equal(collatedMapping.Metadata.CollationSequence, "Fancy Collation");
            Assert.Equal(collatedMapping.Metadata.DeclaredType, "TEXT");
            Assert.False(collatedMapping.Metadata.HasNotNullConstraint);
            Assert.False(collatedMapping.Metadata.IsAutoIncrement);
            Assert.False(collatedMapping.Metadata.IsPrimaryKeyPart);

            var valueMapping = table.Columns["Value"];

            Assert.Equal(valueMapping.ClrType, typeof(DateTime));
            // No way to test the PropertyInfo directly
            Assert.Equal(valueMapping.Metadata.CollationSequence, "BINARY");
            Assert.Equal(valueMapping.Metadata.DeclaredType, "INTEGER");
            Assert.True(valueMapping.Metadata.HasNotNullConstraint);
            Assert.False(valueMapping.Metadata.IsAutoIncrement);
            Assert.False(valueMapping.Metadata.IsPrimaryKeyPart);

            var aFloatMapping = table.Columns["AFloat"];

            Assert.Equal(aFloatMapping.ClrType, typeof(float));
            // No way to test the PropertyInfo directly
            Assert.Equal(aFloatMapping.Metadata.CollationSequence, "BINARY");
            Assert.Equal(aFloatMapping.Metadata.DeclaredType, "REAL");
            Assert.True(aFloatMapping.Metadata.HasNotNullConstraint);
            Assert.False(aFloatMapping.Metadata.IsAutoIncrement);
            Assert.False(aFloatMapping.Metadata.IsPrimaryKeyPart);

            var nullable = table.Columns["NullableInt"];

            Assert.Equal(nullable.ClrType, typeof(Nullable <int>));
            // No way to test the PropertyInfo directly
            Assert.Equal(nullable.Metadata.CollationSequence, "BINARY");
            Assert.Equal(nullable.Metadata.DeclaredType, "INTEGER");
            Assert.False(nullable.Metadata.HasNotNullConstraint);
            Assert.False(nullable.Metadata.IsAutoIncrement);
            Assert.False(nullable.Metadata.IsPrimaryKeyPart);
        }
        public void TestCreateWithExplicitTableName()
        {
            var tableWithExplicitName = TableMapping.Get <TestObjectWithExplicitTableName>();

            Assert.Equal(tableWithExplicitName.TableName, "ExplicitTableName");
        }
        /// <summary>
        /// Execute the current operation
        /// </summary>
        public IEnumerable <object> Execute(SubscriptionDefinition subscription, NameValueCollection parameters, int offset, int?count, out int totalResults, Guid queryId)
        {
            if (subscription == null || subscription.ServerDefinitions.Count == 0)
            {
                throw new InvalidOperationException("Subscription does not have server definition");
            }

            try
            {
                var preArgs = new QueryRequestEventArgs <IdentifiedData>(o => o.Key == subscription.Key, offset, count, queryId, AuthenticationContext.Current.Principal, new ModelSort <IdentifiedData> [0], parameters);
                this.Executing?.Invoke(this, preArgs);
                if (preArgs.Cancel)
                {
                    this.m_tracer.TraceWarning("Pre-Event for executor failed");
                    totalResults = preArgs.TotalResults;
                    return(preArgs.Results);
                }

                var persistenceType     = typeof(IDataPersistenceService <>).MakeGenericType(subscription.ResourceType);
                var persistenceInstance = ApplicationServiceContext.Current.GetService(persistenceType) as IAdoPersistenceService;
                var queryService        = ApplicationServiceContext.Current.GetService <IQueryPersistenceService>();
                var cacheService        = ApplicationServiceContext.Current.GetService <IDataCachingService>();

                // Get the definition
                var definition = subscription.ServerDefinitions.FirstOrDefault(o => o.InvariantName == m_configuration.Provider.Invariant);
                if (definition == null)
                {
                    throw new InvalidOperationException($"Subscription does not provide definition for provider {m_configuration.Provider.Invariant}");
                }

                // No obsoletion time?
                if (typeof(IBaseEntityData).IsAssignableFrom(subscription.ResourceType) && !parameters.ContainsKey("obsoletionTime"))
                {
                    parameters.Add("obsoletionTime", "null");
                }

                // Query expression
                var queryExpression = typeof(QueryExpressionParser).GetGenericMethod(
                    nameof(QueryExpressionParser.BuildLinqExpression),
                    new Type[] { subscription.ResourceType },
                    new Type[] { typeof(NameValueCollection) }
                    ).Invoke(null, new object[] { parameters });

                // Query has been registered?
                IEnumerable <IdentifiedData> result = null;
                if (queryId != Guid.Empty && queryService?.IsRegistered(queryId) == true)
                {
                    totalResults = (int)queryService.QueryResultTotalQuantity(queryId);
                    result       = queryService.GetQueryResults(queryId, offset, count ?? 100)
                                   .Select(o =>
                    {
                        try
                        {
                            var retVal = cacheService.GetCacheItem(o);
                            if (retVal == null)
                            {
                                using (var ctx = m_configuration.Provider.GetReadonlyConnection())
                                {
                                    ctx.Open();
                                    ctx.LoadState = LoadState.FullLoad;
                                    retVal        = persistenceInstance.Get(ctx, o) as IdentifiedData;
                                    cacheService?.Add(retVal);
                                }
                            }
                            return(retVal);
                        }
                        catch (Exception e)
                        {
                            this.m_tracer.TraceError("Error fetching query results for {0}: {1}", queryId, e);
                            throw new DataPersistenceException("Error fetching query results", e);
                        }
                    }).OfType <IdentifiedData>().ToList();
                }
                else
                {
                    // Now grab the context and query!!!
                    using (var connection = m_configuration.Provider.GetReadonlyConnection())
                    {
                        try
                        {
                            connection.Open();
                            connection.LoadState = LoadState.FullLoad;

                            // First, build the query using the query build
                            TableMapping tableMapping = null;
                            if (typeof(Entity).IsAssignableFrom(subscription.ResourceType))
                            {
                                tableMapping = TableMapping.Get(typeof(DbEntityVersion));
                            }
                            else if (typeof(Act).IsAssignableFrom(subscription.ResourceType))
                            {
                                tableMapping = TableMapping.Get(typeof(DbActVersion));
                            }
                            else if (typeof(Concept).IsAssignableFrom(subscription.ResourceType))
                            {
                                tableMapping = TableMapping.Get(typeof(DbConceptVersion));
                            }
                            else
                            {
                                throw new InvalidOperationException("ADO Subscriptions only support Entities and Acts (or sub-types)");
                            }

                            var query = (typeof(QueryBuilder).GetGenericMethod(
                                             nameof(QueryBuilder.CreateQuery),
                                             new Type[] { subscription.ResourceType },
                                             new Type[] { queryExpression.GetType(), typeof(ColumnMapping).MakeArrayType() }
                                             ).Invoke(this.m_queryBuilder, new object[] { queryExpression, tableMapping.Columns.ToArray() }) as SqlStatement).Build();

                            // Now we want to remove the portions of the built query statement after FROM and before WHERE as the definition will be the source of our selection
                            SqlStatement domainQuery = new SqlStatement(m_configuration.Provider, query.SQL.Substring(0, query.SQL.IndexOf(" FROM ")));

                            // Append our query
                            var           definitionQuery = definition.Definition;
                            List <Object> values          = new List <object>();
                            definitionQuery = this.m_parmRegex.Replace(definitionQuery, (o) =>
                            {
                                if (parameters.TryGetValue("_" + o.Groups[2].Value.Substring(1, o.Groups[2].Value.Length - 2), out List <String> qValue))
                                {
                                    Guid uuid = Guid.Empty;
                                    if (Guid.TryParse(qValue.First(), out uuid))
                                    {
                                        values.AddRange(qValue.Select(v => Guid.Parse(v)).OfType <Object>());
                                    }
                                    else
                                    {
                                        values.AddRange(qValue);
                                    }
                                    return(o.Groups[1].Value + String.Join(",", qValue.Select(v => "?")));
                                }
                                return("NULL");
                            });

                            // Now we want to append
                            domainQuery.Append(" FROM (").Append(definitionQuery, values.ToArray()).Append($") AS {tableMapping.TableName} ");
                            domainQuery.Append(query.SQL.Substring(query.SQL.IndexOf("WHERE ")), query.Arguments.ToArray());

                            // Now we want to create the result type
                            var resultType = tableMapping.OrmType;
                            if (typeof(IDbVersionedData).IsAssignableFrom(resultType)) // type is versioned so we have to join
                            {
                                var fkType = tableMapping.GetColumn("Key").ForeignKey.Table;
                                resultType = typeof(CompositeResult <,>).MakeGenericType(resultType, fkType);
                            }

                            // Now we want to select out our results
                            if (count == 0)
                            {
                                totalResults = connection.Count(domainQuery);
                                return(null);
                            }
                            else
                            {
                                // Fetch
                                var domainResults = typeof(DataContext).GetGenericMethod(
                                    nameof(DataContext.Query),
                                    new Type[] { resultType },
                                    new Type[] { typeof(SqlStatement) }).Invoke(connection, new object[] { domainQuery }) as IOrmResultSet;

                                IEnumerable <object> resultObjects = null;

                                // Register query if query id specified
                                if (queryId != Guid.Empty)
                                {
                                    var results = domainResults.Keys <Guid>().OfType <Guid>().ToArray();
                                    this.m_tracer.TraceVerbose("Query for Keys: {0}", connection.GetQueryLiteral(domainResults.Keys <Guid>().ToSqlStatement()));
                                    totalResults = results.Count();
                                    ApplicationServiceContext.Current.GetService <IQueryPersistenceService>()?.RegisterQuerySet(queryId, results, null, totalResults);
                                    resultObjects = results.Skip(offset).Take(count ?? 100).OfType <Object>();
                                }
                                else if (m_configuration.UseFuzzyTotals || preArgs.UseFuzzyTotals)
                                {
                                    this.m_tracer.TraceVerbose("Query for Objects: {0}", connection.GetQueryLiteral(domainResults.ToSqlStatement()));
                                    resultObjects = domainResults.Skip(offset).Take((count ?? 100) + 1).OfType <Object>();
                                    totalResults  = domainResults.Count();
                                }
                                else
                                {
                                    this.m_tracer.TraceVerbose("Query for Objects: {0}", connection.GetQueryLiteral(domainResults.ToSqlStatement()));

                                    totalResults  = domainResults.Count();
                                    resultObjects = domainResults.Skip(offset).Take(count ?? 100).OfType <Object>();
                                }
                                this.m_tracer.TraceVerbose("If i show up in the log, the log is ???????? WHY?????");
                                // Return
                                result = resultObjects
                                         .Take(count ?? 100)
                                         .OfType <Object>()
                                         .Select(o =>
                                {
                                    try
                                    {
                                        if (o is Guid)
                                        {
                                            var retVal = cacheService.GetCacheItem((Guid)o);
                                            if (retVal == null)
                                            {
                                                using (var subConn = connection.OpenClonedContext())
                                                {
                                                    retVal = persistenceInstance.Get(subConn, (Guid)o) as IdentifiedData;
                                                    cacheService?.Add(retVal);
                                                }
                                            }
                                            return(retVal);
                                        }
                                        else
                                        {
                                            var idData = (o as CompositeResult)?.Values.OfType <IDbIdentified>().FirstOrDefault() ?? o as IDbIdentified;
                                            var retVal = cacheService.GetCacheItem(idData.Key);

                                            if (retVal == null)
                                            {
                                                using (var subConn = connection.OpenClonedContext())
                                                {
                                                    retVal = persistenceInstance.ToModelInstance(o, subConn) as IdentifiedData;
                                                    cacheService?.Add(retVal);
                                                }
                                            }
                                            return(retVal);
                                        }
                                    }
                                    catch (Exception e)
                                    {
                                        this.m_tracer.TraceError("Error converting result: {0}", e);
                                        throw;
                                    }
                                }).OfType <IdentifiedData>().ToList();
                            }
                        }
                        catch (Exception e)
                        {
#if DEBUG
                            this.m_tracer.TraceError("Error executing subscription: {0}", e);
#else
                            this.m_tracer.TraceError("Error executing subscription: {0}", e.Message);
#endif

                            throw new DataPersistenceException($"Error executing subscription: {e.Message}", e);
                        }
                    } // using conn
                }     // if

                var postEvt = new QueryResultEventArgs <IdentifiedData>(o => o.Key == subscription.Key, result, offset, count, totalResults, queryId, AuthenticationContext.Current.Principal);
                this.Executed?.Invoke(this, postEvt);

                // Now set the overridden data
                return(postEvt.Results);
            }
            catch (Exception e)
            {
                this.m_tracer.TraceError("Error executing core ADO Subscription logic for {0}: {1}", subscription.Key, e);
                throw new Exception($"Error executing core ADO subscription logic for {subscription.Key}", e);
            }
        }
        /// <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
        }
Exemple #17
0
        /// <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>());
        }
 internal static string CompileFromClause(params Type[] types) =>
 "FROM " + string.Join(", ", types.Select(x => "\"" + TableMapping.Get(x).TableName + "\""));
        internal static string CompileJoinClause(bool left, Type table, Expression expr)
        {
            var tableName = TableMapping.Get(table).TableName;

            return((left ? "LEFT JOIN " : "INNER JOIN ") + "\"" + tableName + "\" ON " + expr.CompileExpr());
        }