コード例 #1
0
ファイル: ShopSale.cs プロジェクト: ktakakis/SomeCafe
        //----------------------------------------------
        //create methods

        /// <summary>
        /// This creates a Sale entry, and also update the ShopStock number in stock
        /// </summary>
        /// <param name="numBought"></param>
        /// <param name="shopStockId"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public static IStatusGeneric <ShopSale> CreateSellAndUpdateStock(int numBought, int shopStockId,
                                                                         DbContext context)
        {
            if (numBought < 0)
            {
                throw new ArgumentException("must be positive", nameof(numBought));
            }
            var status = new StatusGenericHandler <ShopSale>();

            var stock = context.Find <ShopStock>(shopStockId);

            if (stock == null)
            {
                status.AddError("Could not find the stock item you requested.");
                return(status);
            }
            stock.NumInStock = stock.NumInStock - numBought;
            if (stock.NumInStock < 0)
            {
                status.AddError("There are not enough items of that product to sell.");
                return(status);
            }
            var sale = new ShopSale(numBought, null, shopStockId);

            return(status.SetResult(sale));
        }
コード例 #2
0
        public IStatusGeneric DeleteRole(string roleName, bool removeFromUsers,
                                         ExtraAuthorizeDbContext context)
        {
            var status = new StatusGenericHandler {
                Message = "Deleted role successfully."
            };
            var roleToUpdate = context.Find <RoleToPermissions>(roleName);

            if (roleToUpdate == null)
            {
                return(status.AddError("That role doesn't exists"));
            }

            var usersWithRoles = context.UserToRoles.Where(x => x.RoleName == roleName).ToList();

            if (usersWithRoles.Any())
            {
                if (!removeFromUsers)
                {
                    return(status.AddError($"That role is used by {usersWithRoles.Count} and you didn't ask for them to be updated."));
                }

                context.RemoveRange(usersWithRoles);
                status.Message = $"Removed role from {usersWithRoles.Count} user and then deleted role successfully.";
            }

            context.Remove(roleToUpdate);
            return(status);
        }
コード例 #3
0
        public IStatusGeneric UpdateApprove(string checkBy, string approveBy, DateTime?checkDate)
        {
            var status = new StatusGenericHandler();

            if (string.IsNullOrWhiteSpace(checkBy))
            {
                status.AddError("check by value is null!!", "punch");
            }
            if (string.IsNullOrWhiteSpace(approveBy))
            {
                status.AddError("approve by value is null!!", "punch");
            }
            if (!checkDate.HasValue)
            {
                status.AddError("check Date is invalied", "punch");
            }

            if (!status.HasErrors)
            {
                this.CheckBy   = checkBy;
                this.ApproveBy = approveBy;
                this.CheckDate = checkDate;
            }

            return(status);
        }
コード例 #4
0
ファイル: Person.cs プロジェクト: Aminsh1221056SaSa/PSSR
        public IStatusGeneric UpdatePerson(string firstName, string lastName
                                           , string nationalId, string mobileNumber)
        {
            var status = new StatusGenericHandler();

            if (string.IsNullOrWhiteSpace(firstName))
            {
                status.AddError("I'm sorry, but firstName is empty.");
                return(status);
            }

            if (string.IsNullOrWhiteSpace(lastName))
            {
                status.AddError("I'm sorry, but lastName is empty.");
                return(status);
            }

            if (string.IsNullOrWhiteSpace(nationalId))
            {
                status.AddError("I'm sorry, but nationalId is empty.");
                return(status);
            }

            //All Ok
            this.FirstName    = firstName;
            this.LastName     = lastName;
            this.NationalId   = nationalId;
            this.MobileNumber = mobileNumber;

            return(status);
        }
コード例 #5
0
        public async Task <IStatusGeneric <Order> >          //#A
        CreateOrderAndSaveAsync(PlaceOrderInDto dto)         //#B
        {
            var status = new StatusGenericHandler <Order>(); //#C

            if (!dto.AcceptTAndCs)                           //#D
            {
                return(status.AddError("You must accept the T&Cs to place an order."));
            }
            if (!dto.LineItems.Any())                 //#D
            {
                return(status.AddError("No items in your basket."));
            }

            var booksDict = await _dbAccess                            //#E
                            .FindBooksByIdsAsync                       //#E
                                (dto.LineItems.Select(x => x.BookId)); //#E

            var linesStatus = FormLineItemsWithErrorChecking           //#F
                                  (dto.LineItems, booksDict);          //#F

            if (status.CombineStatuses(linesStatus).HasErrors)         //#G
            {
                return(status);                                        //#G
            }
            var orderStatus = Order.CreateOrder(                       //#H
                dto.UserId, linesStatus.Result);                       //#H

            if (status.CombineStatuses(orderStatus).HasErrors)         //#I
            {
                return(status);                                        //#I
            }
            await _dbAccess.AddAndSave(orderStatus.Result);            //#J

            return(status.SetResult(orderStatus.Result));              //#K
        }
        //----------------------------------------------------
        //private

        private static IStatusGeneric CompareRouteValues(RouteValueDictionary foundValueRouteValues, object expectedRouteValues)
        {
            var expectedRouteValueDict = expectedRouteValues.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                         .Select(x => new { key = x.Name, value = x.GetValue(expectedRouteValues) })
                                         .ToDictionary(x => x.key, y => y.value);

            var status = new StatusGenericHandler();

            if (string.Join(", ", expectedRouteValueDict.Keys) != string.Join(", ", foundValueRouteValues.Keys))
            {
                return(status.AddError(
                           $"RouteValues: Different named properties: expected = {string.Join(",", expectedRouteValueDict.Keys)}, found = {string.Join(", ", foundValueRouteValues.Keys)}"));
            }
            foreach (var propName in expectedRouteValueDict.Keys)
            {
                var expectedValue = expectedRouteValueDict[propName];
                var foundValue    = foundValueRouteValues[propName];
                if (expectedValue.GetType() != foundValue.GetType())
                {
                    status.AddError(
                        $"RouteValues->{propName}, different type: expected = {expectedValue.GetType().Name}, found = {foundValue.GetType().Name}");
                }
                else if (!Equals(expectedValue, foundValue))
                {
                    status.AddError(
                        $"RouteValues->{propName}, different values: expected = {expectedValue}, found = {foundValue}");
                }
            }

            return(status);
        }
コード例 #7
0
        public IStatusGeneric ChangeDeliveryDate(string userId, DateTime newDeliveryDate)
        {
            var status = new StatusGenericHandler();

            if (CustomerName != userId)
            {
                status.AddError("I'm sorry, but that order does not belong to you");
                //Log a security issue
                return(status);
            }

            if (HasBeenDelivered)
            {
                status.AddError("I'm sorry, but that order has been delivered.");
                return(status);
            }

            if (newDeliveryDate < DateTime.Today.AddDays(1))
            {
                status.AddError("I'm sorry, we cannot get the order to you that quickly. Please choose a new date.", "NewDeliveryDate");
                return(status);
            }

            if (newDeliveryDate.DayOfWeek == DayOfWeek.Sunday)
            {
                status.AddError("I'm sorry, we don't deliver on Sunday. Please choose a new date.", "NewDeliveryDate");
                return(status);
            }

            //All Ok
            ExpectedDeliveryDate = newDeliveryDate;
            return(status);
        }
        /// <summary>
        /// This will result the cascade soft delete flag on this entity and any dependent entities with the correct delete behaviour and cascade level
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="resetSoftDeleteThisEntity">entity class with cascade soft delete interface. Mustn't be null</param>
        /// <param name="callSaveChanges">Defaults to calling SaveChanges. If set to false, then you must call SaveChanges</param>
        /// <returns>Returns a status. If no errors then Result contains the number of entities that had been reset, plus summary string in Message part</returns>
        public async Task <IStatusGeneric <int> > ResetCascadeSoftDeleteAsync <TEntity>(TEntity resetSoftDeleteThisEntity, bool callSaveChanges = true)
            where TEntity : class, TInterface
        {
            if (resetSoftDeleteThisEntity == null)
            {
                throw new ArgumentNullException(nameof(resetSoftDeleteThisEntity));
            }

            var status             = new StatusGenericHandler <int>();
            var currentDeleteLevel = _config.GetSoftDeleteValue.Compile().Invoke(resetSoftDeleteThisEntity);

            if (currentDeleteLevel == 0)
            {
                return(status.AddError($"This entry isn't {_config.TextSoftDeletedPastTense}."));
            }

            if (currentDeleteLevel > 1)
            {
                return(status.AddError($"This entry was soft deleted {currentDeleteLevel - 1} " +
                                       $"level{(currentDeleteLevel > 2  ? "s" : "")} above here"));
            }

            //For reset you need to read every time because some of the collection might be soft deleted already
            var walker = new CascadeWalker <TInterface>(_context, _config, true,
                                                        CascadeSoftDelWhatDoing.ResetSoftDelete, true);
            await walker.WalkEntitiesSoftDelete(resetSoftDeleteThisEntity, 1);

            if (callSaveChanges)
            {
                await _context.SaveChangesAsync();
            }

            return(ReturnSuccessFullResult(CascadeSoftDelWhatDoing.ResetSoftDelete, walker.NumFound));
        }
コード例 #9
0
ファイル: Survey.cs プロジェクト: mikeathers/Welsby.Surveys
        private StatusGenericHandler AddQuestionGroup(string name, IEnumerable <Question> questions, SurveyDbContext context = null)
        {
            var status = new StatusGenericHandler();

            if (string.IsNullOrWhiteSpace(name))
            {
                status.AddError("A name is needed when creating a new question group.", nameof(name));
                return(status);
            }

            if (_questionGroups != null)
            {
                var questionGroup = new QuestionGroup(name, questions, this);
                _questionGroups.Add(questionGroup);
            }
            else if (context == null)
            {
                status.AddError("You must provide a context if the QuestionGroups collection isn't valid.", nameof(context));
                return(status);
            }
            else if (context.Entry(this).IsKeySet)
            {
                context.Add(new QuestionGroup(name, questions, this));
            }
            else
            {
                status.AddError("Could not add a new QuestionGroup.");
                return(status);
            }

            return(status);
        }
コード例 #10
0
ファイル: Survey.cs プロジェクト: mikeathers/Welsby.Surveys
        private StatusGenericHandler AddQuestion(string text, QuestionType questionType, QuestionGroup questionGroup, SurveyDbContext context = null)
        {
            var status = new StatusGenericHandler();


            if (string.IsNullOrWhiteSpace(text))
            {
                status.AddError("Question text is needed when creating a new question.", nameof(text));
                return(status);
            }

            if (questionType == null)
            {
                status.AddError("A QuestionType has not been specified.", nameof(questionType));
                return(status);
            }
            if (questionGroup == null)
            {
                status.AddError("A QuestionGroup which to add this question to has not been specified.", nameof(questionGroup));
                return(status);
            }
            if (context != null)
            {
                status = questionGroup.AddQuestion(text, questionType, context);
            }
            else
            {
                status.AddError("Could not add a new Question.");
                return(status);
            }

            return(status);
        }
コード例 #11
0
ファイル: Survey.cs プロジェクト: mikeathers/Welsby.Surveys
        public StatusGenericHandler RenameSurvey(string newName, SurveyDbContext context = null)
        {
            var status = new StatusGenericHandler();

            if (string.IsNullOrWhiteSpace(newName))
            {
                status.AddError("A new name has not been provided");
                return(status);
            }

            if (context == null)
            {
                status.AddError("You must provide a context if you want to remove this Survey.", nameof(context));
                return(status);
            }

            var nameAlreadyTaken = context.Surveys.Any(m => m.Name == newName);

            if (nameAlreadyTaken)
            {
                status.AddError("A survey with the name you have provided already exists.", nameof(context));
                return(status);
            }

            Name = newName;
            return(status);
        }
コード例 #12
0
        /*********************************************************
         #A This method forms a Review to be filled in by the user
         #B I read the book title to show to the user when they are filling in their review
         #C This simply creates a Review with the BookId foreign key filled in
         #D Ths method updates the book with the new review
         #E This loads the correct book using the value in the review's foreign key, and includes any existing reviews (or empty collection if no reviews yet)
         #F I now add the new review to the Reviews collection
         #G The SaveChanges uses its DetectChanges method, which sees that the Book Review property has changed. It then creates a new row in the Review table
         #H The method returns the updated book
         * ******************************************************/

        public IStatusGeneric AddReviewWithChecks(Review review)              //#A
        {
            var status = new StatusGenericHandler();                          //#B

            if (review.NumStars < 0 || review.NumStars > 5)                   //#C
            {
                status.AddError("This must be between 0 and 5.",              //#C
                                nameof(Review.NumStars));                     //#C
            }
            if (string.IsNullOrWhiteSpace(review.Comment))                    //#D
            {
                status.AddError("Please provide a comment with your review.", //#D
                                nameof(Review.Comment));                      //#D
            }
            if (!status.IsValid)                                              //#E
            {
                return(status);                                               //#E
            }
            var book = _context.Books                                         //#F
                       .Include(r => r.Reviews)                               //#F
                       .Single(k => k.BookId                                  //#F
                               == review.BookId);                             //#F

            book.Reviews.Add(review);                                         //#F
            _context.SaveChanges();                                           //#F
            return(status);                                                   //#G
        }
コード例 #13
0
        public StatusGenericHandler AddQuestion(CompletedQuestion question, SurveyDbContext context = null)
        {
            var status = new StatusGenericHandler();

            if (string.IsNullOrWhiteSpace(question.Answer))
            {
                status.AddError("An answer is needed when submitting a question.", nameof(question.Answer));
                return(status);
            }

            if (_completedQuestions != null)
            {
                var completedQuestion = new CompletedQuestion(question.Question, question.Answer, this);
                _completedQuestions.Add(completedQuestion);
            }
            else if (context == null)
            {
                status.AddError("You must provide a context if the CompletedQuestions collection isn't valid.", nameof(context));
                return(status);
            }
            else if (context.Entry(this).IsKeySet)
            {
                context.Add(new CompletedQuestion(question.Question, question.Answer, this));
            }
            else
            {
                status.AddError("Could not add a new CompletedQuestion.");
                return(status);
            }

            return(status);
        }
コード例 #14
0
        public static IStatusGeneric <UserToRole> AddRoleToUser(string userId, string roleName, ExtraAuthorizeDbContext context)
        {
            if (userId == null)
            {
                throw new ArgumentNullException(nameof(userId));
            }
            if (roleName == null)
            {
                throw new ArgumentNullException(nameof(roleName));
            }

            var status = new StatusGenericHandler <UserToRole>();

            if (context.Find <UserToRole>(userId, roleName) != null)
            {
                status.AddError($"The user already has the Role '{roleName}'.");
                return(status);
            }
            var roleToAdd = context.Find <RoleToPermissions>(roleName);

            if (roleToAdd == null)
            {
                status.AddError($"I could not find the Role '{roleName}'.");
                return(status);
            }

            return(status.SetResult(new UserToRole(userId, roleToAdd)));
        }
コード例 #15
0
        public StatusGenericHandler AddQuestion(string text, QuestionType type, SurveyDbContext context = null)
        {
            var status   = new StatusGenericHandler();
            var question = new Question(text, type, this);

            if (_questions != null)
            {
                _questions.Add(question);
            }
            else if (context == null)
            {
                status.AddError("You must provide a context if you want to remove this Survey.", nameof(context));
                return(status);
            }
            else if (context.Entry(this).IsKeySet)
            {
                context.Add(new Question(text, type, this));
            }
            else
            {
                status.AddError("Could not add a new survey.", nameof(context));
                return(status);
            }

            return(status);
        }
コード例 #16
0
        }                    //Needed by EF Core

        public static IStatusGeneric <Book> CreateBook(
            string title, DateTime publishedOn,
            bool estimatedDate,
            string publisher, decimal price, string imageUrl,
            ICollection <Author> authors,
            ICollection <Tag> tags = null)
        {
            var status = new StatusGenericHandler <Book>();

            if (string.IsNullOrWhiteSpace(title))
            {
                status.AddError(
                    "The book title cannot be empty.");
            }

            var book = new Book
            {
                Title         = title,
                PublishedOn   = publishedOn,
                EstimatedDate = estimatedDate,
                Publisher     = publisher,
                OrgPrice      = price,
                ActualPrice   = price,
                ImageUrl      = imageUrl,
                //We need to initialise the AuthorsOrdered string when the entry is created
                //NOTE: We must NOT initialise the ReviewsCount and the ReviewsAverageVotes as they default to zero
                AuthorsOrdered = string.Join(", ", authors.Select(x => x.Name)),

                _tags = tags != null
                    ? new HashSet <Tag>(tags)
                    : new HashSet <Tag>(),
                _reviews = new HashSet <Review>()       //We add an empty list on create. I allows reviews to be added when building test data
            };

            if (authors == null)
            {
                throw new ArgumentNullException(nameof(authors));
            }

            byte order = 0;

            book._authorsLink = new HashSet <BookAuthor>(
                authors.Select(a =>
                               new BookAuthor(book, a, order++)));
            if (!book._authorsLink.Any())
            {
                status.AddError(
                    "You must have at least one Author for a book.");
            }

            if (status.IsValid)
            {
                book.AddEvent(new BookChangedEvent(BookChangeTypes.Added), EventToSend.DuringSave);
            }

            return(status.SetResult(book));
        }
コード例 #17
0
        public static async Task <IStatusGeneric> CheckSingleBookAsync(
            this BookDbContext context, int bookId, bool fixBadCacheValues, CancellationToken cancellationToken)
        {
            var status = new StatusGenericHandler();

            var dto = await context.Books
                      .IgnoreQueryFilters()
                      .MapBookToDto()
                      .SingleOrDefaultAsync(x => x.BookId == bookId, cancellationToken);

            if (dto == null)
            {
                status.AddError("SQL: No book found.");
            }

            Book loadedBook = null;
            var  fixedThem  = fixBadCacheValues ? "and fixed it" : "(not fixed)";

            if (dto.RecalcReviewsCount != dto.ReviewsCount ||
                Math.Abs((dto.RecalcReviewsAverageVotes ?? 0) - dto.ReviewsAverageVotes) > 0.0001)
            {
                status.AddError($"SQL: Review cached values incorrect {fixedThem}. " +
                                $"Actual Reviews.Count = {dto.RecalcReviewsCount}, Cached ReviewsCount = {dto.ReviewsCount}. " +
                                $"Actual Reviews average = {dto.RecalcReviewsAverageVotes:F5}, Cached ReviewsAverageVotes = {dto.ReviewsAverageVotes:F5}. " +
                                $"Last updated {dto.LastUpdatedUtc:G}");
                if (fixBadCacheValues)
                {
                    loadedBook = await context.Books.
                                 SingleOrDefaultAsync(x => x.BookId == bookId);

                    loadedBook?.UpdateReviewCachedValues(dto.RecalcReviewsCount, dto.RecalcReviewsAverageVotes ?? 0);
                }
            }

            if (dto.RecalcAuthorsOrdered != dto.AuthorsOrdered)
            {
                status.AddError($"SQL: AuthorsOrdered cached value incorrect {fixedThem}. " +
                                $"Actual authors string = {dto.RecalcAuthorsOrdered}, Cached AuthorsOrdered = {dto.AuthorsOrdered}. " +
                                $"Last updated {dto.LastUpdatedUtc:G}");

                if (fixBadCacheValues)
                {
                    loadedBook ??= await context.Books.SingleOrDefaultAsync(x => x.BookId == bookId);

                    loadedBook.ResetAuthorsOrdered(dto.RecalcAuthorsOrdered);
                }
            }

            return(status);
        }
コード例 #18
0
        public void TestStatusHasTwoErrorOnSamePropOk()
        {
            //SETUP
            var status = new StatusGenericHandler();

            status.AddError("An Error", "MyProp");
            status.AddError("Another Error", "MyProp");

            //ATTEMPT
            var actionResult = status.Response();

            //VERIFY
            actionResult.CheckResponse(status);
        }
コード例 #19
0
        public void TestStatusHasTwoErrors()
        {
            //SETUP
            var status = new StatusGenericHandler();

            //ATTEMPT
            status.AddError("This is an error");
            status.AddError("This is another error");

            //VERIFY
            status.HasErrors.ShouldBeTrue();
            status.Message.ShouldEqual("Failed with 2 errors");
            status.GetAllErrors().ShouldEqual("This is an error\nThis is another error");
        }
コード例 #20
0
        public IStatusGeneric NonStatusGenericNum(int i)
        {
            var status = new StatusGenericHandler();

            //add error and return immediately
            if (i <= 0)
            {
                return(status.AddError("input must be positive", nameof(i)));
            }

            //combine error from another non-StatusGeneric method and return if has errors
            status.CombineStatuses(NonStatusGenericString(i == 10 ? null : "good"));
            if (status.HasErrors)
            {
                return(status);
            }

            //combine errors from another generic status, keeping the status to extract later
            var stringStatus = StatusGenericNumReturnString(i);

            if (status.CombineStatuses(stringStatus).HasErrors)
            {
                return(status);
            }

            var stringResult = stringStatus.Result;

            //Other methods here

            return(status);
        }
コード例 #21
0
        public static IStatusGeneric <Order> CreateOrderFactory(
            string customerName, DateTime expectedDeliveryDate,
            IEnumerable <OrderBooksDto> bookOrders)
        {
            var status = new StatusGenericHandler <Order>();
            var order  = new Order
            {
                CustomerName         = customerName,
                ExpectedDeliveryDate = expectedDeliveryDate,
                DateOrderedUtc       = DateTime.UtcNow,
                HasBeenDelivered     = expectedDeliveryDate < DateTime.Today
            };

            byte lineNum = 1;

            order._lineItems = new HashSet <LineItem>(bookOrders
                                                      .Select(x => new LineItem(x.numBooks, x.ChosenBook, lineNum++)));
            if (!order._lineItems.Any())
            {
                status.AddError("No items in your basket.");
            }

            status.Result = order;
            return(status);
        }
コード例 #22
0
        /// <summary>
        /// This hard deletes this entity and any dependent entities that are already been cascade soft deleted
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="hardDeleteThisEntity">entity class with cascade soft delete interface. Mustn't be null</param>
        /// <param name="callSaveChanges">Defaults to calling SaveChanges. If set to false, then you must call SaveChanges</param>
        /// <returns>Returns a status. If no errors then Result contains the number of entities which were hard deleted, plus summary string in Message part</returns>
        public IStatusGeneric <int> HardDeleteSoftDeletedEntries <TEntity>(TEntity hardDeleteThisEntity, bool callSaveChanges = true)
            where TEntity : class, TInterface
        {
            if (hardDeleteThisEntity == null)
            {
                throw new ArgumentNullException(nameof(hardDeleteThisEntity));
            }
            var status = new StatusGenericHandler <int>();

            if (_config.GetSoftDeleteValue.Compile().Invoke(hardDeleteThisEntity) == 0)
            {
                return(status.AddError($"This entry isn't {_config.TextSoftDeletedPastTense}."));
            }

            //For reset you need to read every time because some of the collection might be soft deleted already
            var walker = new CascadeWalker <TInterface>(_context, _config, false,
                                                        CascadeSoftDelWhatDoing.HardDeleteSoftDeleted, false);

            walker.WalkEntitiesSoftDelete(hardDeleteThisEntity, 1).CheckSyncValueTaskWorked();
            if (callSaveChanges)
            {
                _context.SaveChanges();
            }

            return(ReturnSuccessFullResult(CascadeSoftDelWhatDoing.HardDeleteSoftDeleted, walker.NumFound));
        }
コード例 #23
0
        /// <summary>
        /// This with cascade soft delete this entity and any dependent entities with the correct delete behaviour
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="softDeleteThisEntity">entity class with cascade soft delete interface. Mustn't be null</param>
        /// <param name="callSaveChanges">Defaults to calling SaveChanges. If set to false, then you must call SaveChanges</param>
        /// <returns>Returns a status. If no errors then Result contains the number of entities that had been cascaded deleted, plus summary string in Message part</returns>
        public IStatusGeneric <int> SetCascadeSoftDelete <TEntity>(TEntity softDeleteThisEntity, bool callSaveChanges = true)
            where TEntity : class, TInterface
        {
            if (softDeleteThisEntity == null)
            {
                throw new ArgumentNullException(nameof(softDeleteThisEntity));
            }

            //If is a one-to-one entity we return an error
            var keys = _context.Entry(softDeleteThisEntity).Metadata.GetForeignKeys();

            if (!keys.All(x => x.DependentToPrincipal?.IsCollection == true || x.PrincipalToDependent?.IsCollection == true))
            {
                //This it is a one-to-one entity
                throw new InvalidOperationException("You cannot soft delete a one-to-one relationship. " +
                                                    "It causes problems if you try to create a new version.");
            }

            var status = new StatusGenericHandler <int>();

            if (_config.GetSoftDeleteValue.Compile().Invoke(softDeleteThisEntity) != 0)
            {
                return(status.AddError($"This entry is already {_config.TextSoftDeletedPastTense}."));
            }

            var walker = new CascadeWalker <TInterface>(_context, _config, CascadeSoftDelWhatDoing.SoftDelete, _config.ReadEveryTime);

            walker.WalkEntitiesSoftDelete(softDeleteThisEntity, 1);
            if (callSaveChanges)
            {
                _context.SaveChanges();
            }

            return(ReturnSuccessFullResult(CascadeSoftDelWhatDoing.SoftDelete, walker.NumFound));
        }
コード例 #24
0
        /// <summary>
        /// This with cascade soft delete this entity and any dependent entities with the correct delete behaviour
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="softDeleteThisEntity">entity class with cascade soft delete interface. Mustn't be null</param>
        /// <param name="callSaveChanges">Defaults to calling SaveChanges. If set to false, then you must call SaveChanges</param>
        /// <returns>Returns a status. If no errors then Result contains the number of entities that had been cascaded deleted, plus summary string in Message part</returns>
        public async Task <IStatusGeneric <int> > SetCascadeSoftDeleteAsync <TEntity>(TEntity softDeleteThisEntity, bool callSaveChanges = true)
            where TEntity : class, TInterface
        {
            if (softDeleteThisEntity == null)
            {
                throw new ArgumentNullException(nameof(softDeleteThisEntity));
            }
            _context.ThrowExceptionIfPrincipalOneToOne(softDeleteThisEntity);

            var status = new StatusGenericHandler <int>();

            if (_config.GetSoftDeleteValue.Compile().Invoke(softDeleteThisEntity) != 0)
            {
                return(status.AddError($"This entry is already {_config.TextSoftDeletedPastTense}."));
            }

            var walker = new CascadeWalker <TInterface>(_context, _config, true,
                                                        CascadeSoftDelWhatDoing.SoftDelete, _config.ReadEveryTime);
            await walker.WalkEntitiesSoftDelete(softDeleteThisEntity, 1);

            if (callSaveChanges)
            {
                await _context.SaveChangesAsync();
            }

            return(ReturnSuccessFullResult(CascadeSoftDelWhatDoing.SoftDelete, walker.NumFound));
        }
コード例 #25
0
        /// <summary>
        /// This will soft delete the single entity. This may delete other dependent
        /// </summary>
        /// <param name="softDeleteThisEntity">Mustn't be null</param>
        /// <param name="callSaveChanges">Defaults to calling SaveChanges. If set to false, then you must call SaveChanges</param>
        /// <returns>Returns status. If not errors then Result return 1 to say it worked. Zero if error</returns>
        public async Task <IStatusGeneric <int> > SetSoftDeleteAsync(TInterface softDeleteThisEntity, bool callSaveChanges = true)
        {
            if (softDeleteThisEntity == null)
            {
                throw new ArgumentNullException(nameof(softDeleteThisEntity));
            }

            var keys = _context.Entry(softDeleteThisEntity).Metadata.GetForeignKeys();

            if (!keys.All(x => x.DependentToPrincipal?.IsCollection == true || x.PrincipalToDependent?.IsCollection == true))
            {
                //This it is a one-to-one entity - setting a one-to-one as soft deleted causes problems when you try to create a replacement
                throw new InvalidOperationException("You cannot soft delete a one-to-one relationship. " +
                                                    "It causes problems if you try to create a new version.");
            }

            var status = new StatusGenericHandler <int>();

            if (_config.GetSoftDeleteValue.Compile().Invoke(softDeleteThisEntity))
            {
                return(status.AddError($"This entry is already {_config.TextSoftDeletedPastTense}."));
            }

            _config.SetSoftDeleteValue(softDeleteThisEntity, true);
            if (callSaveChanges)
            {
                await _context.SaveChangesAsync();
            }

            status.Message = $"Successfully {_config.TextSoftDeletedPastTense} this entry";
            status.SetResult(1);        //one changed
            return(status);
        }
コード例 #26
0
        /// <summary>
        /// This hard deletes (i.e. calls EF Core's Remove method) for this entity ONLY if it first been soft deleted.
        /// This will delete the entity and possibly delete other dependent entities.
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="hardDeleteThisEntity">The entity to delete</param>
        /// <param name="callSaveChanges">Defaults to calling SaveChanges. If set to false, then you must call SaveChanges yourself</param>
        /// <returns>The number of entities that were deleted. This will include any dependent entities that that had a cascade delete behaviour</returns>
        public async Task <IStatusGeneric <int> > HardDeleteSoftDeletedEntryAsync <TEntity>(TEntity hardDeleteThisEntity, bool callSaveChanges = true)
            where TEntity : class, TInterface
        {
            if (hardDeleteThisEntity == null)
            {
                throw new ArgumentNullException(nameof(hardDeleteThisEntity));
            }
            var status = new StatusGenericHandler <int>();

            if (!_config.GetSoftDeleteValue.Compile().Invoke(hardDeleteThisEntity))
            {
                return(status.AddError($"This entry isn't {_config.TextSoftDeletedPastTense}."));
            }

            _context.Remove(hardDeleteThisEntity);
            var numDeleted = 1;

            if (callSaveChanges)
            {
                numDeleted = await _context.SaveChangesAsync();
            }

            status.Message = $"Successfully {_config.TextHardDeletedPastTense} this entry";
            status.SetResult(numDeleted);
            return(status);
        }
コード例 #27
0
        //---------------------------------------------
        // private methods

        private IStatusGeneric CatchAndFixConcurrencyException(Exception ex, DbContext context)
        {
            var dbUpdateEx = ex as DbUpdateConcurrencyException;

            if (dbUpdateEx == null || dbUpdateEx.Entries.Count != 1)
            {
                return(null); //can't handle this error
            }
            var entry = dbUpdateEx.Entries.Single();

            if (!(entry.Entity is ProductStock failedUpdate))
            {
                return(null);
            }

            var status = new StatusGenericHandler();
            //This entity MUST be read as NoTracking otherwise it will interfere with the same entity we are trying to write
            var overwroteData
                = context.Set <ProductStock>().AsNoTracking().SingleOrDefault(p => p.ProductName == failedUpdate.ProductName);

            if (overwroteData == null)
            {
                //The ProductStock was deleted
                return(status.AddError("The product you were interested in has been removed from our stock."));
            }

            var addedChange   = failedUpdate.NumAllocated - (int)entry.Property(nameof(ProductStock.NumAllocated)).OriginalValue;
            var combinedAlloc = overwroteData.NumAllocated + addedChange;

            entry.Property(nameof(ProductStock.NumAllocated)).CurrentValue  = combinedAlloc;
            entry.Property(nameof(ProductStock.NumAllocated)).OriginalValue = overwroteData.NumAllocated;

            return(status);
        }
コード例 #28
0
        /// <summary>
        /// This looks for this entity and any dependent entities that are already been cascade soft deleted and are valid to be hard deleted.
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="checkHardDeleteThisEntity">entity class with cascade soft delete interface. Mustn't be null</param>
        /// <returns>Returns a status. If no errors then Result contains the number of entities which are eligible for hard delete, plus summary string in Message part</returns>
        public IStatusGeneric <int> CheckCascadeSoftDelete <TEntity>(TEntity checkHardDeleteThisEntity)
            where TEntity : class, TInterface
        {
            if (checkHardDeleteThisEntity == null)
            {
                throw new ArgumentNullException(nameof(checkHardDeleteThisEntity));
            }
            var status = new StatusGenericHandler <int>();

            if (_config.GetSoftDeleteValue.Compile().Invoke(checkHardDeleteThisEntity) == 0)
            {
                return(status.AddError($"This entry isn't {_config.TextSoftDeletedPastTense}."));
            }

            //For reset you need to read every time because some of the collection might be soft deleted already
            var walker = new CascadeWalker <TInterface>(_context, _config, false,
                                                        CascadeSoftDelWhatDoing.CheckWhatWillDelete, _config.ReadEveryTime);
            var valueTask = walker.WalkEntitiesSoftDelete(checkHardDeleteThisEntity, 1);

            if (!valueTask.IsCompleted)
            {
                throw new InvalidOperationException("Can only run sync tasks");
            }
            return(ReturnSuccessFullResult(CascadeSoftDelWhatDoing.CheckWhatWillDelete, walker.NumFound));
        }
コード例 #29
0
        /*******************************************************************
         #A This method returns a status with the created Order, which is null if there are no errors
         #B The PlaceOrderInDto contains a TandC bool and a collection of BookIds and number of books
         #C This status is used to gather and errors and, if no errors, return an Order
         #D These validate the user's input
         #E The _dbAccess contains the code to find each book - see listing 4.3
         #F This method creates list of bookId and number of books - see end of listing 4.2
         #G If any errors were found while checking each order line, then it returns the error status
         #H This calls the Order static factory. It is the Order's job to form the Order with LineItems
         #I Again, any errors will abort the Order and the errors returned
         #J The _dbAccess contains the code add the Order and call SaveChangesAsync
         #K Finally it returns a successful status with the created Order entity
         ****************************************************************/

        private IStatusGeneric <List <OrderBookDto> > FormLineItemsWithErrorChecking
            (IEnumerable <OrderLineItem> lineItems,
            IDictionary <int, BookView> booksDict)
        {
            var status = new StatusGenericHandler <List <OrderBookDto> >();
            var result = new List <OrderBookDto>();

            foreach (var lineItem in lineItems)
            {
                if (!booksDict.ContainsKey(lineItem.BookId))
                {
                    throw new InvalidOperationException(
                              $"An order failed because book, id = {lineItem.BookId} was missing.");
                }

                var bookView = booksDict[lineItem.BookId];
                if (bookView.ActualPrice <= 0)
                {
                    status.AddError($"Sorry, the book '{bookView.Title}' is not for sale.");
                }
                else
                {
                    //Valid, so add to the order
                    result.Add(new OrderBookDto(bookView, lineItem.NumBooks));
                }
            }
            return(status.SetResult(result));
        }
        /// <summary>
        /// This will soft delete the single entity. This may delete other dependent
        /// </summary>
        /// <param name="softDeleteThisEntity">Mustn't be null</param>
        /// <param name="callSaveChanges">Defaults to calling SaveChanges. If set to false, then you must call SaveChanges</param>
        /// <returns>Returns status. If not errors then Result return 1 to say it worked. Zero if error</returns>
        public async Task <IStatusGeneric <int> > SetSoftDeleteAsync(TInterface softDeleteThisEntity, bool callSaveChanges = true)
        {
            if (softDeleteThisEntity == null)
            {
                throw new ArgumentNullException(nameof(softDeleteThisEntity));
            }
            _context.ThrowExceptionIfPrincipalOneToOne(softDeleteThisEntity);

            var status = new StatusGenericHandler <int>();

            if (_config.GetSoftDeleteValue.Compile().Invoke(softDeleteThisEntity))
            {
                return(status.AddError($"This entry is already {_config.TextSoftDeletedPastTense}."));
            }

            _config.SetSoftDeleteValue(softDeleteThisEntity, true);
            if (callSaveChanges)
            {
                await _context.SaveChangesAsync();
            }

            status.Message = $"Successfully {_config.TextSoftDeletedPastTense} this entry";
            status.SetResult(1);        //one changed
            return(status);
        }