예제 #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="BinaryCriteria"/> class.
        /// </summary>
        /// <param name="left">The left operand.</param>
        /// <param name="op">The operator.</param>
        /// <param name="right">The right operand.</param>
        /// <exception cref="ArgumentNullException">
        /// Left or right operand is null.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">Operator is not a binary one.</exception>
        public BinaryCriteria(BaseCriteria left, CriteriaOperator op, BaseCriteria right)
        {
            if (ReferenceEquals(left, null))
            {
                throw new ArgumentNullException("left");
            }

            if (ReferenceEquals(right, null))
            {
                throw new ArgumentNullException("right");
            }

            if (op < CriteriaOperator.AND || op > CriteriaOperator.NotLike)
            {
                throw new ArgumentOutOfRangeException("op");
            }

            this.left  = left;
            this.right = right;
            this.op    = op;
        }
예제 #2
0
        private static BaseCriteria JoinIf(BaseCriteria criteria1, BaseCriteria criteria2, CriteriaOperator op)
        {
            if (ReferenceEquals(null, criteria1))
            {
                throw new ArgumentNullException("criteria1");
            }

            if (ReferenceEquals(null, criteria2))
            {
                throw new ArgumentNullException("criteria2");
            }

            if (criteria1.IsEmpty)
            {
                return(criteria2);
            }
            if (criteria2.IsEmpty)
            {
                return(criteria1);
            }
            return(new BinaryCriteria(criteria1, op, criteria2));
        }
예제 #3
0
 public BaseCriteria InStatement(BaseCriteria statement)
 {
     return(In(statement));
 }
예제 #4
0
 public BaseCriteria NotIn(BaseCriteria statement)
 {
     return(null);
 }
예제 #5
0
 public CaseBuilder WhenThen(BaseCriteria when, object then)
 {
     this.when.Add(when);
     this.then.Add(then);
     return(this);
 }
예제 #6
0
 public CaseBuilder When(BaseCriteria when)
 {
     this.when.Add(when);
     return(this);
 }
예제 #7
0
 public InnerJoin(string toTable, string alias, BaseCriteria onCriteria)
     : base(null, toTable, alias, onCriteria)
 {
 }
예제 #8
0
 /// <summary>
 /// Validates the specified criteria.
 /// </summary>
 /// <param name="criteria">The criteria.</param>
 public void Validate(BaseCriteria criteria)
 {
     Visit(criteria);
 }
예제 #9
0
 public UnaryCriteria(string op, BaseCriteria operand)
 {
 }
예제 #10
0
 public InnerJoin(IDictionary <string, Join> joins, string toTable, string alias, BaseCriteria onCriteria)
     : base(joins, toTable, alias, onCriteria)
 {
 }
예제 #11
0
 public BaseCriteria Process(BaseCriteria criteria)
 {
     return(Visit(criteria));
 }
예제 #12
0
파일: Join.cs 프로젝트: mhsabur/Serenity
        protected Join(IDictionary <string, Join> joins, string toTable, string alias, BaseCriteria onCriteria)
            : base(toTable, alias)
        {
            this.joins      = joins;
            this.onCriteria = onCriteria;

            if (!ReferenceEquals(this.onCriteria, null))
            {
                var aliases = JoinAliasLocator.Locate(this.onCriteria.ToStringIgnoreParams());
                if (aliases != null && aliases.Count > 0)
                {
                    referencedAliases = aliases;
                }
            }

            var toTableAliases = JoinAliasLocator.Locate(this.Table);

            if (toTableAliases != null && toTableAliases.Count > 0)
            {
                if (referencedAliases == null)
                {
                    referencedAliases = toTableAliases;
                }
                else
                {
                    foreach (var x in toTableAliases)
                    {
                        referencedAliases.Add(x);
                    }
                }
            }

            if (joins != null)
            {
                if (joins.ContainsKey(this.Name))
                {
                    throw new ArgumentException(String.Format(
                                                    "There is already a join with alias '{0}'", this.Name));
                }

                joins.Add(this.Name, this);
            }
        }
예제 #13
0
 public BinaryCriteria(BaseCriteria left, string op, BaseCriteria right)
 {
 }
예제 #14
0
        private void ToJson(JsonWriter writer, BaseCriteria criteria, JsonSerializer serializer)
        {
            if (criteria is null ||
                criteria.IsEmpty)
            {
                writer.WriteNull();
                return;
            }

            if (criteria is ValueCriteria valueCriteria)
            {
                var value = valueCriteria.Value;
                if (value != null && value is IEnumerable && !(value is string))
                {
                    // make sure that first value in array won't be recognized as a operator
                    // while deserializing (e.g. if values are [">", "a", "b"], serialize them
                    // as [[">", "a", "b"]] so that the first > won't be recognized as GE operator.
                    writer.WriteStartArray();
                    serializer.Serialize(writer, value);
                    writer.WriteEndArray();
                    return;
                }

                serializer.Serialize(writer, value);
                return;
            }

            if (criteria is ParamCriteria prm)
            {
                writer.WriteStartArray();
                serializer.Serialize(writer, prm.Name);
                writer.WriteEndArray();
                return;
            }

            if (criteria is Criteria crit)
            {
                writer.WriteStartArray();
                serializer.Serialize(writer, crit.Expression);
                writer.WriteEndArray();
                return;
            }

            if (criteria is UnaryCriteria unary)
            {
                writer.WriteStartArray();
                writer.WriteValue(OperatorToKey[(int)unary.Operator]);
                ToJson(writer, unary.Operand, serializer);
                writer.WriteEndArray();
                return;
            }

            if (criteria is BinaryCriteria binary)
            {
                writer.WriteStartArray();
                ToJson(writer, binary.LeftOperand, serializer);
                writer.WriteValue(OperatorToKey[(int)binary.Operator]);
                ToJson(writer, binary.RightOperand, serializer);
                writer.WriteEndArray();
                return;
            }

            throw new JsonSerializationException(string.Format("Can't serialize criteria of type {0}", criteria.GetType().FullName));
        }
예제 #15
0
 /// <summary>
 ///   Gets the next display order value for a table or a group of records.</summary>
 /// <param name="connection">
 ///   Connection (required).</param>
 /// <param name="row">
 ///   Row with a display order field (required).</param>
 /// <param name="filter">
 ///   Filter for records (can be null).</param>
 /// <returns>
 ///   One more of maximum display order values of records in the group.
 ///   If none, 1.</returns>
 public static int GetNextValue(IDbConnection connection, IDisplayOrderRow row, BaseCriteria filter = null)
 {
     return(GetNextValue(connection, ((Row)row).Table, row.DisplayOrderField, filter));
 }
예제 #16
0
 /// <summary>
 ///   Sets a records display order to to requested value, and also renumbers other records
 ///   in the group as required.</summary>
 /// <param name="connection">
 ///   Connection (required).</param>
 /// <param name="row">
 ///   Row with a display order and ID field (should implement IDbIdRow interface).</param>
 /// <param name="filter">
 ///   Filter that will determine the record group (can be null).</param>
 /// <param name="recordID">
 ///   ID value of the record.</param>
 /// <param name="newDisplayOrder">
 ///   New display order of the record.</param>
 /// <param name="descendingKeyOrder">
 ///   Will records with same display order values be sorted in ascending or descending ID order?
 ///   For example, if records with ID's 1, 2, 3 has display order value of "0", their actual display
 ///   orders are 1, 2 and 3. If this parameter is set to true (descending), their display orders will
 ///   become 3, 2, 1. This parameter controls if records that are added recently and has no display
 ///   order value assigned (or 0) be shown at start or at the end.</param>
 /// <returns>
 ///   If any of the display order values is changed true.</returns>
 public static bool ReorderValues(IDbConnection connection, IDisplayOrderRow row, BaseCriteria filter = null,
                                  Int64?recordID = null, int newDisplayOrder = 1, bool descendingKeyOrder = false, bool hasUniqueConstraint = false)
 {
     return(ReorderValues(connection, ((Row)row).Table, (Field)((IIdRow)row).IdField, row.DisplayOrderField, filter, recordID,
                          newDisplayOrder, descendingKeyOrder, hasUniqueConstraint));
 }
예제 #17
0
        /// <summary>
        ///   Sets a records display order to to requested value, and also renumbers other records
        ///   in the group as required.</summary>
        /// <param name="connection">
        ///   Connection (required).</param>
        /// <param name="tableName">
        ///   Tablename (required).</param>
        /// <param name="keyField">
        ///   ID field meta that will be used to locate the record (required).</param>
        /// <param name="orderField">
        ///   Display order field meta.</param>
        /// <param name="filter">
        ///   Filter that will determine the record group (can be null).</param>
        /// <param name="recordID">
        ///   ID value of the record.</param>
        /// <param name="newDisplayOrder">
        ///   New display order of the record.</param>
        /// <param name="descendingKeyOrder">
        ///   Will records with same display order values be sorted in ascending or descending ID order?
        ///   For example, if records with ID's 1, 2, 3 has display order value of "0", their actual display
        ///   orders are 1, 2 and 3. If this parameter is set to true (descending), their display orders will
        ///   become 3, 2, 1. This parameter controls if records that are added recently and has no display
        ///   order value assigned (or 0) be shown at start or at the end.</param>
        /// <returns>
        ///   If any of the display order values is changed true.</returns>
        public static bool ReorderValues(IDbConnection connection, string tableName, Field keyField, Field orderField,
                                         BaseCriteria filter     = null, Int64?recordID = null, int newDisplayOrder = 1,
                                         bool descendingKeyOrder = false, bool hasUniqueConstraint = false)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }
            if (tableName == null || tableName.Length == 0)
            {
                throw new ArgumentNullException("tableName");
            }
            if (keyField == null)
            {
                throw new ArgumentNullException("keyField");
            }
            if (orderField == null)
            {
                throw new ArgumentNullException("orderField");
            }

            // last assigned display order value
            int order = 0;

            // a list that will contain an element for each record, and hold old and new display
            // order values of records
            List <OrderRecord> orderRecords = new List <OrderRecord>();

            // link to the order entry for record whose display order value is asked to be changed
            OrderRecord changing = null;

            // query to fetch id and display order values of the records in the group
            SqlQuery query = new SqlQuery()
                             .Select(
                keyField,
                orderField)
                             .From(
                tableName, Alias.T0)
                             .Where(
                filter)
                             .OrderBy(
                orderField);

            // determine display order for records with same display order values
            // based on ID ordering set
            query.OrderBy(keyField.Name, desc: descendingKeyOrder);

            // read all existing records
            using (IDataReader reader = SqlHelper.ExecuteReader(connection, query))
            {
                while (reader.Read())
                {
                    // each records actual display order value is one more than previous one
                    order++;
                    // create an entry to hold current and new display order value of the record
                    OrderRecord r = new OrderRecord();
                    // record ID
                    r.recordID = Convert.ToInt64(reader.GetValue(0));
                    // old display order field value (not the actual display order!)
                    r.oldOrder = Convert.ToInt32(reader.GetValue(1));
                    // new display order value (actual one to be set)
                    r.newOrder = order;

                    orderRecords.Add(r);

                    // if this is the one that is requested to be changed, hold a link to its entry
                    if (recordID == r.recordID)
                    {
                        changing = r;
                    }
                }
            }

            // ensure that the new display order is within limits
            // if its lower than 1 or bigger than record count, fix it
            if (newDisplayOrder <= 0)
            {
                newDisplayOrder = 1;
            }
            else if (newDisplayOrder > order)
            {
                newDisplayOrder = order;
            }

            // if the record whose display order is to be changed can be found, and its display order value is different
            // than the one in database
            if (changing != null && changing.newOrder != newDisplayOrder)
            {
                // let's say record had a display order value of 6and now it will become 10, the records with actual
                // display orders of 7, 8, 9, 10 will become 6, 7, 8, 9 orders.
                //
                // WARNING: notice that array is 0 based, so record with actual display order of 7 is in the
                // 6th index in the array)
                for (int i = changing.newOrder; i < newDisplayOrder; i++)
                {
                    orderRecords[i].newOrder = i;
                }

                // if the records display order is to be changed from 9 to 5, the records with actual orders of 5, 6, 7, 8
                // is going to be 6, 7, 8, 9 ordered.
                for (int i = newDisplayOrder - 1; i < changing.newOrder - 1; i++)
                {
                    orderRecords[i].newOrder = i + 2;
                }

                // as the records that will be changing are assigned new orders, we may assign new display order
                // directly.
                changing.newOrder = newDisplayOrder;
            }

            // from now on, apply the new display order values by preparing queries

            // StringBuilder that will contain query(s)
            StringBuilder queries = new StringBuilder();

            if (SqlSettings.CurrentDialect.NeedsExecuteBlockStatement())
            {
                queries.AppendLine("EXECUTE BLOCK AS");
                queries.AppendLine("BEGIN");
            }

            int updateCount = 0;

            Action <long, long> appendSingleUpdate = delegate(long id, long newOrder)
            {
                queries.AppendLine(String.Format(
                                       "UPDATE {0} SET {1} = {2} WHERE {3} = {4};", tableName,
                                       orderField.Name, newOrder, keyField.Name, id));
                updateCount++;
            };

            if (hasUniqueConstraint)
            {
                var byCurrentOrder = new Dictionary <Int64, OrderRecord>();
                foreach (var rec in orderRecords)
                {
                    byCurrentOrder[rec.oldOrder] = rec;
                }

                var list = new List <OrderRecord>();
                list.AddRange(orderRecords);
                list.Sort((x, y) => (x.newOrder - y.newOrder));

                foreach (var rec in list)
                {
                    if (rec.oldOrder != rec.newOrder)
                    {
                        byCurrentOrder.Remove(rec.oldOrder);

                        OrderRecord congestion;
                        if (byCurrentOrder.TryGetValue(rec.newOrder, out congestion))
                        {
                            var empty = list.Count * 2;
                            while (byCurrentOrder.ContainsKey(empty))
                            {
                                empty++;
                            }

                            congestion.oldOrder = empty;
                            appendSingleUpdate(congestion.recordID, empty);
                            byCurrentOrder[empty] = congestion;
                        }

                        appendSingleUpdate(rec.recordID, rec.newOrder);
                        byCurrentOrder[rec.newOrder] = rec;
                    }
                }
            }
            else
            {
                // StringBuilder that will contain IN(...) part of the latest query
                StringBuilder sb = new StringBuilder();

                // scan all display order changing records
                int start = 0;
                while (start < orderRecords.Count)
                {
                    OrderRecord rs = orderRecords[start];

                    // if this records display order is not changed, skip it
                    if (rs.oldOrder == rs.newOrder)
                    {
                        start++;
                        continue;
                    }

                    // find the difference between old and new display orders
                    int difference = rs.oldOrder - rs.newOrder;

                    // clear the IN(...) list
                    sb.Length = 0;

                    // add this records ID to the IN (...) part
                    sb.Append(rs.recordID);

                    // now we'll find all following records whose display orders are changed same amount
                    // (difference between old and new is same), so we will update them with just one query
                    // like UPDATE ORDER = ORDER + 1 WHERE ID IN (X, Y, Z....).
                    int finish = start;

                    while (finish + 1 < orderRecords.Count)
                    {
                        // if we found more than 100 records whose display orders changed same amount, to
                        // limit IN(...) part to overgrow, break searching and run the query. Collect the
                        // rest in another query. If query is too complex, might result in performance
                        // degration in SQL server
                        if (finish - start >= 100)
                        {
                            break;
                        }

                        OrderRecord rf = orderRecords[finish + 1];

                        // is this records display order value changed same amount
                        if (rf.oldOrder - rf.newOrder != difference)
                        {
                            break;
                        }

                        sb.Append(',');
                        sb.Append(rf.recordID);

                        finish++;
                    }

                    // if only one record in batch, no need to use IN clause
                    if (start == finish)
                    {
                        queries.AppendLine(String.Format(
                                               "UPDATE {0} SET {1} = {2} WHERE {3} = {4};", tableName,
                                               orderField.Name, rs.newOrder, keyField.Name, rs.recordID));
                        updateCount++;
                    }
                    else
                    {
                        // batch update, use IN (...)
                        OrderRecord rf = orderRecords[finish];

                        queries.AppendLine(String.Format(
                                               "UPDATE {0} SET {1} = {1} - ({2}) WHERE ({3} IN ({4}));",
                                               tableName,
                                               orderField.Name,
                                               rs.oldOrder - rs.newOrder,
                                               keyField.Name,
                                               sb.ToString()));
                        updateCount++;
                    }

                    start = finish + 1;
                }
            }

            if (queries.Length > 0 && updateCount > 0)
            {
                if (SqlSettings.CurrentDialect.NeedsExecuteBlockStatement())
                {
                    queries.AppendLine("END;");
                }

                SqlHelper.ExecuteNonQuery(connection, queries.ToString());
                // one ore more records has changed display order values

                return(true);
            }
            else
            {
                // nothing changed, all display orders are same
                return(false);
            }
        }