示例#1
0
        /// <summary>
        /// Creates the SQL query based on conditions using the current dialect.
        /// Generally, you can call this method for debugging reasons.
        /// </summary>
        /// <param name="searchOptions">The search definitions.</param>
        /// <param name="connection">The Connection.</param>
        /// <param name="justCount">Indicates that this is a COUNT query.</param>
        /// <param name="skip">Number of rows to skip when paging</param>
        /// <param name="take">Number of rows to take when paging</param>
        /// <param name="parameters">Outputs the generated parameters.</param>
        /// <returns>A SQL query.</returns>
        public static string GetSearchSql(SearchOptions searchOptions, bool justCount, int?skip, int?take, ConnectionStringSettings connection, out TenorParameter[] parameters)
        {
            GeneralDialect dialect = DialectFactory.CreateDialect(connection);

            if (searchOptions == null)
            {
                throw (new ArgumentNullException("searchOptions", "You must specify a SearchOptions instance."));
            }

            TableInfo table = TableInfo.CreateTableInfo(searchOptions.baseType);

            if (connection == null)
            {
                connection = table.GetConnection();
            }

            //Read Projections
            List <Projection> projections = new List <Projection>();

            foreach (Projection p in searchOptions.Projections)
            {
                projections.Add(p);
            }

            //Read Joins

            List <Join> joins = new List <Join>();

            joins.AddRange(GetPlainJoins(searchOptions, dialect));



            //Get necessary fields to create the select statement.
            StringBuilder           sqlFields  = new StringBuilder();
            List <FieldInfo>        fieldInfos = new List <FieldInfo>();
            List <SpecialFieldInfo> spFields   = new List <SpecialFieldInfo>();
            List <FieldInfo>        lenFields  = new List <FieldInfo>();

            FieldInfo[] allFields;
            if (justCount)
            {
                allFields = EntityBase.GetFields(searchOptions.baseType, true); //lets count using distinct subquery
            }
            else if (searchOptions.Projections.Count > 0)
            {
                allFields = ReadProjections <FieldInfo>(projections, null, EntityBase.GetFields(searchOptions.baseType));
            }
            else
            {
                allFields = EntityBase.GetFields(searchOptions.baseType); //lets get all fields
            }
            foreach (FieldInfo f in allFields)
            {
                if (f.PrimaryKey || (!f.LazyLoading && !justCount)) //primary keys and eager fields must be loaded
                {
                    fieldInfos.Add(f);
                }
                else if (!justCount && f.LazyLoading && f.FieldType.IsAssignableFrom(typeof(BinaryStream)))
                {
                    lenFields.Add(f);
                }

                // when paging, at least one sorting criterion is needed
                if (skip.HasValue && take.HasValue && searchOptions.Sorting.Count == 0 && f.PrimaryKey)
                {
                    searchOptions.Sorting.Add(f.RelatedProperty.Name);
                }
            }

            if (!justCount) //we don't need it on counting
            {
                SpecialFieldInfo[] fields = EntityBase.GetSpecialFields(searchOptions.baseType);
                if (searchOptions.Projections.Count > 0)
                {
                    fields = ReadProjections <SpecialFieldInfo>(projections, null, fields);
                }

                spFields.AddRange(fields);
            }

            sqlFields.Append(dialect.CreateSelectSql(table.RelatedTable, null, fieldInfos.ToArray(), spFields.ToArray(), lenFields.ToArray()));


            //adding values from eager loading types
            foreach (ForeignKeyInfo fkInfo in searchOptions.eagerLoading.Keys)
            {
                fieldInfos = new List <FieldInfo>();
                spFields   = new List <SpecialFieldInfo>();
                lenFields  = new List <FieldInfo>();

                //select all fields, or only the projection.
                FieldInfo[] allEagerFields = EntityBase.GetFields(fkInfo.ElementType);
                if (searchOptions.Projections.Count > 0)
                {
                    allEagerFields = ReadProjections <FieldInfo>(projections, fkInfo.RelatedProperty.Name, allEagerFields);
                }

                foreach (FieldInfo f in allEagerFields)
                {
                    if (f.PrimaryKey || !f.LazyLoading)
                    {
                        fieldInfos.Add(f);
                    }
                    else if (f.LazyLoading && f.FieldType.IsAssignableFrom(typeof(BinaryStream)))
                    {
                        lenFields.Add(f);
                    }
                }
                //spfields
                SpecialFieldInfo[] allSpFields = EntityBase.GetSpecialFields(fkInfo.ElementType);
                if (searchOptions.Projections.Count > 0)
                {
                    allSpFields = ReadProjections <SpecialFieldInfo>(projections, fkInfo.RelatedProperty.Name, allSpFields);
                }

                spFields.AddRange(allSpFields);
                //joins: joins was made on GetPlainJoins.

                sqlFields.Append(", ");
                sqlFields.Append(dialect.CreateSelectSql(fkInfo.ElementType, searchOptions.eagerLoading[fkInfo], fieldInfos.ToArray(), spFields.ToArray(), lenFields.ToArray()));
            }


            //Sorting (not necessary for count queries)
            string sqlSort = string.Empty;

            if (!justCount)
            {
                string appendToSelect = null;

                sqlSort = dialect.CreateSortSql(searchOptions.Sorting, table.RelatedTable, joins.ToArray(), searchOptions.Distinct, skip.HasValue && take.HasValue, out appendToSelect);

                if (!string.IsNullOrEmpty(appendToSelect))
                {
                    sqlFields.Append(appendToSelect);
                }
            }

            //Check if we found all projections:
            if (projections.Count > 0)
            {
                throw new InvalidProjectionException(projections[0]);
            }


            //Creates the where part
            string sqlWhere = dialect.CreateWhereSql(searchOptions.Conditions, searchOptions.baseType, joins.ToArray(), out parameters);

            // Creates the join parts
            string sqlJoins = dialect.CreateJoinsSql(joins.ToArray());


            // Creates the entire sql string
            string sql = dialect.CreateFullSql(searchOptions.baseType, searchOptions.Distinct, justCount, searchOptions.Top, skip, take, sqlFields.ToString(), sqlJoins, sqlSort, sqlWhere);


            Tenor.Diagnostics.Debug.DebugSQL("GetSearchSql()", sql, parameters, connection);
#if DEBUG
            LastSearches.Push(sql);
#endif

            return(sql);
        }
示例#2
0
        /// <summary>
        /// Gets the value of a lazy tagged property.
        /// This call can do a database access.
        /// </summary>
        internal virtual object GetPropertyValue(string propertyName, bool forceGetBinary)
        {
            //only loads if not loaded yet.
            //TODO: provide a way to reload from database.
            lock (propertyData)
            {
                if (forceGetBinary || !propertyData.ContainsKey(propertyName))
                {
                    //Getting class metadata.

                    TableInfo table = TableInfo.CreateTableInfo(this.GetType());

                    System.Reflection.PropertyInfo fieldP = this.GetType().GetProperty(propertyName);
                    if (fieldP == null)
                    {
                        throw new Tenor.Data.MissingFieldException(this.GetType(), propertyName);
                    }

                    ForeignKeyInfo fkInfo = null;

                    fkInfo = ForeignKeyInfo.Create(fieldP);

                    if (fkInfo != null)
                    {
                        // this is an FK, so, route to fk loading
                        return(LoadForeign(fieldP, null));
                    }
                    else
                    {
                        //Continue to the lazy property (lazy fields like byte[]) loading
                        FieldInfo field = FieldInfo.Create(fieldP);
                        if (field == null)
                        {
                            throw new Tenor.Data.MissingFieldException(this.GetType(), fieldP.Name);
                        }

                        if (!forceGetBinary && (field.FieldType == typeof(BinaryStream) || field.FieldType == typeof(BinaryStream).BaseType))
                        {
                            propertyData[propertyName] = new BinaryStream(this, propertyName);
                        }
                        else
                        {
                            GeneralDialect dialect = DialectFactory.CreateDialect(table.GetConnection());


                            ConditionCollection conditions = new ConditionCollection();

                            foreach (FieldInfo f in GetFields(this.GetType(), true))
                            {
                                conditions.Add(f.RelatedProperty.Name, f.PropertyValue(this));
                            }
                            if (conditions.Count == 0)
                            {
                                throw (new Tenor.Data.MissingPrimaryKeyException(this.GetType()));
                            }

                            TenorParameter[] parameters = null;
                            string           fieldsPart = dialect.CreateSelectSql(table.RelatedTable, null, new FieldInfo[] { field }, null, null);
                            string           wherePart  = dialect.CreateWhereSql(conditions, table.RelatedTable, null, out parameters);
                            string           sql        = dialect.CreateFullSql(table.RelatedTable,
                                                                                false, false,
                                                                                0, fieldsPart, null, null, wherePart);

                            Tenor.Diagnostics.Debug.DebugSQL("GetPropertyValue()", sql, parameters, table.GetConnection());
#if DEBUG
                            LastSearches.Push(sql);
#endif
                            Tenor.Data.DataTable rs = new Tenor.Data.DataTable(sql, parameters, table.GetConnection());
                            rs.Bind();

                            if (rs.Rows.Count == 0)
                            {
                                throw (new RecordNotFoundException());
                            }
                            else if (rs.Rows.Count > 1)
                            {
                                throw new ManyRecordsFoundException();
                            }
                            else
                            {
                                var obj = rs.Rows[0][field.DataFieldName];
                                if (obj == DBNull.Value)
                                {
                                    obj = null;
                                }

                                if (forceGetBinary)
                                {
                                    if (obj == null)
                                    {
                                        return new byte[] { }
                                    }
                                    ;
                                    else
                                    {
                                        return(obj);
                                    }
                                }
                                else
                                {
                                    propertyData[propertyName] = obj;
                                }
                            }
                        }
                    }
                }
                return(propertyData[propertyName]);
            }
        }