Пример #1
0
        /// <summary>
        ///     An IQueryable&lt;T&gt; extension method that updates all rows from the query using an
        ///     expression without retrieving entities.
        /// </summary>
        /// <typeparam name="T">The type of elements of the query.</typeparam>
        /// <param name="query">The query to update rows from without retrieving entities.</param>
        /// <param name="updateFactory">The update expression.</param>
        /// <param name="batchUpdateBuilder">The batch builder action to change default configuration.</param>
        /// <returns>The number of rows affected.</returns>
        public static int Update <T>(this IQueryable <T> query, Expression <Func <T, T> > updateFactory, Action <BatchUpdate> batchUpdateBuilder) where T : class
        {
            var batchUpdate = new BatchUpdate();

            if (BatchUpdateManager.BatchUpdateBuilder != null)
            {
                BatchUpdateManager.BatchUpdateBuilder(batchUpdate);
            }

            if (batchUpdateBuilder != null)
            {
                batchUpdateBuilder(batchUpdate);
            }

            return(batchUpdate.Execute(query, updateFactory));
        }
        /// <summary>Executes the batch delete operation.</summary>
        /// <typeparam name="T">The type of elements of the query.</typeparam>
        /// <param name="query">The query used to execute the batch operation.</param>
        /// <param name="updateFactory">The update factory.</param>
        /// <returns>The number of rows affected.</returns>
        public int Execute <T>(IQueryable <T> query, Expression <Func <T, T> > updateFactory) where T : class
        {
            // FIX query with visitor
            {
                var visitor = new BatchUpdateVisitor();
                visitor.Visit(query.Expression);

                if (visitor.HasOrderBy)
                {
                    query = query.Take(int.MaxValue);
                }
            }

            string expression = query.Expression.ToString();

            if (Regex.IsMatch(expression, @"\.Where\(\w+ => False\)"))
            {
                return(0);
            }

#if EF5 || EF6
            var objectQuery = query.GetObjectQuery();

            // GET model and info
            var model  = query.GetDbContext().GetModel();
            var entity = model.Entity <T>();

            // TODO: Select only key + lambda columns
            // var keys = entity.Info.Key.PropertyRefs;
            //var queryKeys = query.SelectByName(keys.Select(x => x.Name).ToList());
            //var innerObjectQuery = queryKeys.GetObjectQuery();
            var innerObjectQuery = objectQuery;

            // GET UpdateSetValues
            var values = GetInnerValues(query, updateFactory, entity);

            // CREATE command
            var command = CreateCommand(innerObjectQuery, entity, values);

            // WHERE 1 = 0
            if (command == null)
            {
                return(0);
            }

            // EXECUTE
            var ownConnection = false;

            try
            {
                if (innerObjectQuery.Context.Connection.State != ConnectionState.Open)
                {
                    ownConnection = true;
                    innerObjectQuery.Context.Connection.Open();
                }

                if (Executing != null)
                {
                    Executing(command);
                }

                var rowAffecteds = command.ExecuteNonQuery();
                return(rowAffecteds);
            }
            finally
            {
                if (ownConnection && innerObjectQuery.Context.Connection.State != ConnectionState.Closed)
                {
                    innerObjectQuery.Context.Connection.Close();
                }
            }
#elif EFCORE
            if (BatchUpdateManager.InMemoryDbContextFactory != null && query.IsInMemoryQueryContext())
            {
                var context = BatchUpdateManager.InMemoryDbContextFactory();

                var list           = query.ToList();
                var compiled       = updateFactory.Compile();
                var memberBindings = ((MemberInitExpression)updateFactory.Body).Bindings;
                var accessors      = memberBindings
                                     .Select(x => x.Member.Name)
                                     .Select(x => new PropertyOrFieldAccessor(typeof(T).GetProperty(x, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)))
                                     .ToList();

                foreach (var item in list)
                {
                    var newItem = compiled(item);

                    foreach (var accessor in accessors)
                    {
                        var value = accessor.GetValue(newItem);
                        accessor.SetValue(item, value);
                    }
                }

                context.SaveChanges();
                return(list.Count);
            }

            var dbContext = query.GetDbContext();
            var entity    = dbContext.Model.FindEntityType(typeof(T));

            // TODO: Select only key + lambda columns
            //  var keys = entity.GetKeys().ToList()[0].Properties;
            //var queryKeys = query.SelectByName(keys.Select(x => x.Name).ToList());
            //var innerObjectQuery = queryKeys.GetObjectQuery();
            var queryKeys = query;

            // GET UpdateSetValues
            var values = GetInnerValues(query, updateFactory, entity);

            // CREATE command
            var command = CreateCommand(queryKeys, entity, values);

            // EXECUTE
            var ownConnection = false;

            try
            {
                if (dbContext.Database.GetDbConnection().State != ConnectionState.Open)
                {
                    ownConnection = true;
                    dbContext.Database.OpenConnection();
                }

                if (Executing != null)
                {
                    Executing(command);
                }

                var rowAffecteds = command.ExecuteNonQuery();
                return(rowAffecteds);
            }
            finally
            {
                if (ownConnection && dbContext.Database.GetDbConnection().State != ConnectionState.Closed)
                {
                    dbContext.Database.CloseConnection();
                }
            }
#endif
        }