/// <summary>
        /// Implementation for building the overall T-SQL query.
        /// </summary>
        private void BuildSql( )
        {
            _result = new BulkSqlQuery
            {
                Request = _request
            };

            // Walk the request object graph to get individual nodes
            var allRequestNodes = Delegates.WalkGraph(_request, rq => rq.Relationships.Select(r => r.RequestedMembers));

            // Build info for each node
            int nextTag = 0;

            foreach (EntityMemberRequest node in allRequestNodes)
            {
                var nodeInfo = new RequestNodeInfo
                {
                    Request = node,
                    Tag     = nextTag++
                };
                _requestNodeMap.Add(node, nodeInfo);
                _result.RequestNodes.Add(nodeInfo.Tag, nodeInfo);
            }

            ProcessRelationships( );
            ProcessFields( );
        }
Example #2
0
 /// <summary>
 /// Execute the query held in the BulkSqlQuery object for the specified entity, and capture the results in a fairly raw format.
 /// </summary>
 public static BulkRequestResult RunQuery(BulkSqlQuery query, EntityRef entity)
 {
     if (entity == null)
     {
         throw new ArgumentNullException("entity");
     }
     return(RunQuery(query, entity.Id.ToEnumerable()));
 }
Example #3
0
        /// <summary>
        /// Generates the query.
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private BulkRequestResult CreateResult(EntityRequest request)
        {
            // Get/create a query object
            BulkSqlQuery query = BulkSqlQueryCache.GetBulkSqlQuery(request);

            // Run query on SQL server
            BulkRequestResult unsecuredResult = BulkRequestSqlRunner.RunQuery(query, request.EntityIDsCanonical);

            return(unsecuredResult);
        }
        /// <summary>
        /// Build, or retrieve from cache, a prepared SQL query.
        /// </summary>
        /// <param name="request">The query to load.</param>
        /// <returns>An object containing the sql query and other lookup data.</returns>
        public static BulkSqlQuery GetBulkSqlQuery(EntityRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (request.Request == null && request.RequestString == null)
            {
                throw new ArgumentException("Either Request or RequestString must be specified", "request");
            }

            // Check the cache
            string       key   = GetCacheKey(request);
            BulkSqlQuery query = _requestCache.GetOrAdd(key, k => CreateQuery(request));

            return(query);
        }
Example #5
0
        /// <summary>
        /// Read field values from the database result
        /// </summary>
        private static void ReadFieldValues(IDataReader reader, BulkSqlQuery query, BulkRequestResult result)
        {
            // select d.EntityId, d.FieldId, d.Data, [d.Namespace]
            while (reader.Read())
            {
                // Caution: We're in a database-read context, so don't touch the entity model or things will crash.

                // Load row
                long   entityId = reader.GetInt64(0);
                long   fieldId  = reader.GetInt64(1);
                object data     = reader.GetValue(2);

                // Get alias namespace
                if (data != null && reader.FieldCount == 4)
                {
                    string aliasNamespace = reader.GetString(3);
                    data = aliasNamespace + ":" + data;
                }

                // Get/convert the type info for the field
                FieldInfo fieldInfo;
                if (!query.FieldTypes.TryGetValue(fieldId, out fieldInfo))
                {
                    throw new InvalidOperationException("Assert false: encountered a field type in the result that was not part of the request.");
                }

                if (fieldInfo.IsWriteOnly)
                {
                    data = null;
                }

                // Prepare field value
                var typedValue = new TypedValue(DateTimeKind.Utc);
                typedValue.Type  = fieldInfo.DatabaseType;
                typedValue.Value = data;
                var fieldValue = new FieldValue(data, typedValue);

                // Add to dictionary
                var key = new FieldKey(entityId, fieldId);
                result.FieldValues [key] = fieldValue;
            }
        }
Example #6
0
        /// <summary>
        /// Execute the query held in the BulkSqlQuery object for the specified entities, and capture the results in a fairly raw format.
        /// </summary>
        /// <param name="query">The query object.</param>
        /// <param name="entities">IDs of root-level entities to load. Must not contain duplicates.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentNullException">
        /// query
        /// or
        /// entities
        /// </exception>
        /// <exception cref="System.ArgumentException">No entities were loaded;entities</exception>
        public static BulkRequestResult RunQuery(BulkSqlQuery query, IEnumerable <long> entities)
        {
            if (query == null)
            {
                throw new ArgumentNullException("query");
            }
            if (entities == null)
            {
                throw new ArgumentNullException("entities");
            }

            var entitiesList = entities.ToList( );

            if (entitiesList.Count <= 0)
            {
                throw new ArgumentException("No entities were loaded", "entities");
            }

            var result = new BulkRequestResult();

            result.BulkSqlQuery = query;

            /////
            // HACK:TODO: 'LastLogin' is handled differently to all other fields on an entity. See UserAccountValidator
            /////
            long lastLogonId = WellKnownAliases.CurrentTenant.LastLogon;

            if (query.FieldTypes.ContainsKey(lastLogonId))
            {
                using (CacheContext cacheContext = new CacheContext( ))
                {
                    cacheContext.Entities.Add(lastLogonId);
                }
            }

            using (DatabaseContext ctx = DatabaseContext.GetContext())
                using (IDbCommand command = ctx.CreateCommand())
                {
                    // If single entity, then pass via parameter (to allow SQL to cache execution plan)
                    if (entitiesList.Count == 1)
                    {
                        ctx.AddParameter(command, "@entityId", DbType.Int64, entitiesList[0]);
                    }
                    else
                    {
                        command.AddIdListParameter("@entityIds", entitiesList);
                    }

                    ctx.AddParameter(command, "@tenantId", DbType.Int64, RequestContext.TenantId);

                    foreach (KeyValuePair <string, DataTable> tvp in query.TableValuedParameters)
                    {
                        command.AddTableValuedParameter(tvp.Key, tvp.Value);
                    }

                    command.CommandText = "dbo.spExecBulkRequest";
                    command.CommandType = CommandType.StoredProcedure;

                    using (IDataReader reader = command.ExecuteReader())
                    {
                        if (reader != null)
                        {
                            ReadRelationships(reader, query, result);
                            while (reader.NextResult())
                            {
                                ReadFieldValues(reader, query, result);
                            }
                        }
                    }
                }

            return(result);
        }
Example #7
0
        /// <summary>
        /// Read relationships, and top level entities, from the database result.
        /// </summary>
        private static void ReadRelationships(IDataReader reader, BulkSqlQuery query, BulkRequestResult result)
        {
            // select distinct EntityId, RelSrcId, RelTypeId from #process
            while (reader.Read())
            {
                // Caution: We're in a database-read context, so don't touch the entity model or things will crash.

                long toId          = reader.GetInt64(0);
                int  nodeTag       = reader.GetInt32(1);    // tag of the request node that returned this entity
                long fromId        = reader.GetInt64(2);    // zero for root-level entities
                long typeIdWithNeg = reader.GetInt64(3);    // relationship type-id, with reverse being indicated with negative values

                // Root result entity
                if (fromId == 0)
                {
                    result.RootEntities.Add(toId);
                }
                else
                {
                    // Add to dictionary
                    var key   = new RelationshipKey(fromId, typeIdWithNeg);
                    var value = toId;

                    List <long> list;
                    if (!result.Relationships.TryGetValue(key, out list))
                    {
                        list = new List <long>();
                        result.Relationships[key] = list;
                    }
                    list.Add(value);
                }

                // Implicit relationship security
                bool implicitlySecured = false;
                if (fromId != 0)
                {
                    var relInfo = query.Relationships[typeIdWithNeg];
                    implicitlySecured = relInfo.ImpliesSecurity;
                }

                // Store entity
                EntityValue ev;
                if (!result.AllEntities.TryGetValue(toId, out ev))
                {
                    ev = new EntityValue {
                        ImplicitlySecured = implicitlySecured
                    };
                    result.AllEntities[toId] = ev;
                }
                else
                {
                    ev.ImplicitlySecured = ev.ImplicitlySecured && implicitlySecured;
                }

                // Store the request node that specified members to load for this entity
                RequestNodeInfo requestNode = query.RequestNodes [nodeTag];
                ev.Nodes.Add(requestNode);
            }

#if DEBUG
            if (result.RootEntitiesList.Count != 0)
            {
                throw new InvalidOperationException("Assert false .. expected RootEntityList to be empty.");
            }
#endif
            result.RootEntitiesList.AddRange(result.RootEntities);

            RemoveDuplicateRelationshipEntries(result);
        }