public async Task <CreateMockChatsTxn_Output> Execute(CreateMockChatsTxn_Input input, IServiceProvider serviceProvider, MVCDbContext contextFather = null, bool autoCommit = true)
        {
            CreateMockChatsTxn_Output output = new CreateMockChatsTxn_Output();

            output.ResultConfirmation = resultConfirmation.resultBad(_ResultMessage: "TXN_NOT_STARTED");

            // Error handling
            bool error = false; // To Handle Only One Error

            try
            {
                MVCDbContext contextMGT = (contextFather != null) ? contextFather : new MVCDbContext();
                // An using statement is in reality a try -> finally statement, disposing the element in the finally. So we need to take advance of that to create a DBContext inheritance
                try
                {
                    // DBContext by convention is a UnitOfWork, track changes and commits when SaveChanges is called
                    // Multithreading issue: so if we use only one DBContext, it will track all entities (_context.Customer.Add) and commit them when SaveChanges is called,
                    // No Matter what transactions or client calls SaveChanges.
                    // Note: Rollback will not remove the entities from the tracker in the context. so better dispose it.

                    //***** 0. Make The Validations - Be careful : Concurrency. Same name can be saved multiple times if called at the exact same time. Better have an alternate database constraint

                    // Company company = await contextMVC.Company.Where(x => x.Id.Equals(input.Company.Id)).FirstOrDefaultAsync();

                    // Validate user status, user company, user not blocked, etc

                    // One way to do it: Try to save without validations, if constraints fail (inner update db update) then run queries to check what went wrong

                    // Call transaction to create a New Company
                    CreateCompanyTxn_Input createCompanyTxn_Input = new CreateCompanyTxn_Input {
                        Company = new company {
                            name = input.CompanyName, email = input.CompanyName + "@company.com", password = input.CompanyName + "123"
                        }
                    };
                    CreateCompanyTxn_Output createCompanyTxn = await new GraphQLMutation().CreateCompanyTxn(input: createCompanyTxn_Input, serviceProvider: serviceProvider);
                    if (!createCompanyTxn.ResultConfirmation.resultPassed)
                    {
                        error = true;
                        output.ResultConfirmation = createCompanyTxn.ResultConfirmation;
                        return(output);
                    }

                    // Create Users
                    for (int i = 0; i < input.UsersToCreate; i++)
                    {
                        // Call transaction to create a New User
                        CreateUserTxn_Input createUserTxn_Input = new CreateUserTxn_Input {
                            User = new userApp {
                                userName = i.ToString() + "_" + createCompanyTxn.Company.companyId, email = i.ToString() + "@User.com", password = "******"
                            }, Company = new company {
                                companyId = createCompanyTxn.Company.companyId
                            }
                        };
                        CreateUserTxn_Output createUserTxn = await new GraphQLMutation().CreateUserTxn(input: createUserTxn_Input, serviceProvider: serviceProvider);
                        if (!createUserTxn.ResultConfirmation.resultPassed)
                        {
                            error = true;
                            output.ResultConfirmation = createUserTxn.ResultConfirmation;
                            return(output);
                        }
                    }

                    // Create chats
                    List <chat> chatsNew = new List <chat>();
                    for (int i = 0; i < input.ChatsToCreate; i++)
                    {
                        DateTime utcNow = DateTime.UtcNow;
                        // Create the chat
                        chat chat = new chat {
                            chatId = 0, name = "Chat " + i, companyId = createCompanyTxn.Company.companyId, createdAt = utcNow, updatedAt = utcNow, type = "Chat"
                        };

                        // Add participants
                        List <participant> participants = (from user in contextMGT.UserApp
                                                           where user.companyId.Equals(createCompanyTxn.Company.companyId)
                                                           select new participant {
                            participantId = 0, chatId = 0, isAdmin = false, userAppId = user.userAppId
                        })
                                                          .OrderBy(x => x.userAppId)
                                                          .Take(input.UsersToCreate - i)
                                                          .ToList();

                        chat.participants = participants;

                        /*
                         * // Add comments Seen
                         * List<Comment> commentsSeen = (from part in participants
                         *                           select new Comment { CommentId = 0, ChatId = 0, Message = "Message ", CreatedAt = utcNow.AddMinutes(-1), UserAppId = part.UserAppId })
                         *                           .ToList();
                         *
                         * foreach (var comm in commentsSeen)
                         * {
                         *  // Create and Save the CommentInfo for each user.
                         *  var query = from user in participants
                         *              select new CommentInfo { CommentInfoId = 0, CommentId = 0, CreatedAt = utcNow.AddMinutes(-1), Delivered = true, Seen = true, SeenAt = utcNow.AddMinutes(-1), UserAppId = user.UserAppId };
                         *
                         *  comm.CommentsInfo = query.ToList();
                         * }
                         *
                         * // Add comments Seen
                         * List<Comment> commentsUnseen = (from part in participants
                         *                            select new Comment { CommentId = 0, ChatId = 0, Message = "Message ", CreatedAt = utcNow, UserAppId = part.UserAppId })
                         *                           .ToList();
                         *
                         * foreach (var comm in commentsUnseen)
                         * {
                         *  // Create and Save the CommentInfo for each user.
                         *  var query = from user in participants
                         *              select new CommentInfo { CommentInfoId = 0, CommentId = 0, CreatedAt = utcNow, Delivered = true, Seen = false, UserAppId = user.UserAppId };
                         *
                         *  comm.CommentsInfo = query.ToList();
                         * }
                         */

                        // Add one comment for each participant
                        List <comment> commentsUnseen = (from part in participants
                                                         select new comment {
                            commentId = 0, chatId = 0, message = "Msg " + part.userAppId, createdAt = utcNow, userAppId = part.userAppId
                        })
                                                        .ToList();

                        foreach (var comm in commentsUnseen)
                        {
                            // Create and Save the CommentInfo for each user.
                            var query = from user in participants
                                        select new commentInfo {
                                commentInfoId = 0, commentId = 0, createdAt = utcNow, delivered = true, seen = false, userAppId = user.userAppId
                            };

                            comm.commentsInfo = query.ToList();
                        }

                        chat.comments = commentsUnseen;

                        // Call transaction to create a New Chat
                        CreateChatTxn_Input createChatTxn_Input = new CreateChatTxn_Input {
                            Chat = chat
                        };
                        CreateChatTxn_Output createChatTxn = await new GraphQLMutation().CreateChatTxn(input: createChatTxn_Input);
                        if (!createChatTxn.ResultConfirmation.resultPassed)
                        {
                            error = true;
                            output.ResultConfirmation = createChatTxn.ResultConfirmation;
                            return(output);
                        }

                        chatsNew.Add(createChatTxn.Chat);



                        //***** 4. Save and Commit to the Database (Atomic because is same Context DB)
                        if (!error && autoCommit)
                        {
                            await contextMGT.SaveChangesAsync(); // Call it only once so do all other operations first
                        }
                    }// for (int i = 0; i < input.ChatsToCreate; i++)

                    //***** 4. Save and Commit to the Database (Atomic because is same Context DB)
                    if (!error && autoCommit)
                    {
                        await contextMGT.SaveChangesAsync(); // Call it only once so do all other operations first
                    }

                    //***** 5. Execute Send e-mails or other events once the database has been succesfully saved
                    //***** If this task fails, there are options -> 1. Retry multiple times 2. Save the event as Delay, 3.Rollback Database, Re

                    //***** 6. Confirm the Result (Pass | Fail) If gets to here there are not errors then return the new data from database
                    output.ResultConfirmation = resultConfirmation.resultGood(_ResultMessage: "CHAT_SUCESSFULLY_CREATED"); // If OK
                    output.Chats = chatsNew;
                }
                finally
                {
                    // If the context Father is null the context was created on his own, so dispose it
                    if (contextMGT != null && contextFather == null)
                    {
                        contextMGT.Dispose();
                    }
                }
            }
            catch (Exception ex) // Main try
            {
                System.Diagnostics.Debug.WriteLine("Error: " + ex.Message);
                string innerError = (ex.InnerException != null) ? ex.InnerException.Message : "";
                System.Diagnostics.Debug.WriteLine("Error Inner: " + innerError);
                output = new CreateMockChatsTxn_Output(); // Restart variable to avoid returning any already saved data
                output.ResultConfirmation = resultConfirmation.resultBad(_ResultMessage: "EXCEPTION", _ResultDetail: ex.Message);
            }
            finally
            {
                // Save Logs if needed
            }

            return(output);
        }
Example #2
0
        public async Task <CreateChatTxn_Output> Execute(CreateChatTxn_Input input, MVCDbContext contextFather = null, bool autoCommit = true)
        {
            CreateChatTxn_Output output = new CreateChatTxn_Output();

            output.ResultConfirmation = resultConfirmation.resultBad(_ResultMessage: "TXN_NOT_STARTED");

            // Error handling
            bool error     = false; // To Handle Only One Error
            bool chatFound = false; // To see if the chat already exists

            try
            {
                MVCDbContext contextMGT = (contextFather != null) ? contextFather : new MVCDbContext();
                // An using statement is in reality a try -> finally statement, disposing the element in the finally. So we need to take advance of that to create a DBContext inheritance
                try
                {
                    // DBContext by convention is a UnitOfWork, track changes and commits when SaveChanges is called
                    // Multithreading issue: so if we use only one DBContext, it will track all entities (_context.Customer.Add) and commit them when SaveChanges is called,
                    // No Matter what transactions or client calls SaveChanges.
                    // Note: Rollback will not remove the entities from the tracker in the context. so better dispose it.

                    //***** 0. Make The Validations - Be careful : Concurrency. Same name can be saved multiple times if called at the exact same time. Better have an alternate database constraint

                    // Company company = await contextMVC.Company.Where(x => x.Id.Equals(input.Company.Id)).FirstOrDefaultAsync();

                    // Validate user status, user company, user not blocked, etc

                    // One way to do it: Try to save without validations, if constraints fail (inner update db update) then run queries to check what went wrong

                    company companyDb = await contextMGT.Company.Where(x => x.companyId.Equals(input.Chat.companyId)).FirstOrDefaultAsync();

                    if (companyDb == null)
                    {
                        error = true;
                        output.ResultConfirmation = resultConfirmation.resultBad(_ResultMessage: "COMPANY_DOES_NOT_EXIST_ERROR", _ResultDetail: "");
                    }

                    // Try to find a Chat already crated for the same users. If the chat exists, return the chat

                    if (!error)
                    {
                        DateTime nowUTC = DateTime.UtcNow;

                        //***** 0. Validate if the Chat exists, so return that Chat

                        List <String> userIds = input.Chat.participants
                                                .GroupBy(g => g.userAppId)
                                                .Select(user => user.Key) // extract unique Ids from users
                                                .ToList();

                        chat chatDb = await contextMGT.Chat.Include(o => o.participants)
                                      .Where(company => company.companyId == input.Chat.companyId)                // It's the same company
                                      .Where(x => x.participants.Count == input.Chat.participants.Count)          // Have the same number of users
                                      .Where(x => x.participants.All(users => userIds.Contains(users.userAppId))) // Have the same users by Id
                                      .FirstOrDefaultAsync();

                        if (chatDb != null)
                        {
                            chatFound        = true;
                            chatDb.updatedAt = nowUTC;

                            input.Chat.comments = null;

                            /* Dont save comments during Create Chat
                             *
                             *
                             * // Save the comments into the Database
                             * foreach (var comment in input.Chat.Comments)
                             * {
                             *  comment.CommentId = 0;
                             *  comment.ChatId = chatDb.ChatId;
                             *  comment.CreatedAt = nowUTC;
                             *  contextMGT.Comment.Add(comment);
                             * }
                             */

                            output.ResultConfirmation = resultConfirmation.resultGood(_ResultMessage: "CHAT_SUCESSFULLY_FOUND"); // If Found
                            output.Chat = chatDb;
                        }

                        //***** 1. Create the Chat (Atomic because is same Context DB)
                        if (!chatFound)
                        {
                            // Create the Chat To Save
                            input.Chat.chatId    = 0;
                            input.Chat.createdAt = nowUTC;
                            input.Chat.updatedAt = nowUTC;

                            if (input.Chat.comments != null)
                            {
                                input.Chat.comments.ForEach(x => x.createdAt = nowUTC);
                            }

                            // Save the chat to the context
                            contextMGT.Chat.Add(input.Chat);
                            output.ResultConfirmation = resultConfirmation.resultGood(_ResultMessage: "CHAT_SUCESSFULLY_CREATED"); // If OK
                            output.Chat = input.Chat;
                        }

                        //***** 4. Save and Commit to the Database (Atomic because is same Context DB)
                        if (!error && autoCommit)
                        {
                            await contextMGT.SaveChangesAsync(); // Call it only once so do all other operations first
                        }

                        //***** 5. Execute Send e-mails or other events once the database has been succesfully saved
                        //***** If this task fails, there are options -> 1. Retry multiple times 2. Save the event as Delay, 3.Rollback Database, Re

                        //***** 6. Confirm the Result (Pass | Fail) If gets to here there are not errors then return the new data from database
                    }// if (!error)
                }
                finally
                {
                    // If the context Father is null the context was created on his own, so dispose it
                    if (contextMGT != null && contextFather == null)
                    {
                        contextMGT.Dispose();
                    }
                }
            }
            catch (Exception ex) // Main try
            {
                System.Diagnostics.Debug.WriteLine("Error: " + ex.Message);
                string innerError = (ex.InnerException != null) ? ex.InnerException.Message : "";
                System.Diagnostics.Debug.WriteLine("Error Inner: " + innerError);
                output = new CreateChatTxn_Output(); // Restart variable to avoid returning any already saved data
                output.ResultConfirmation = resultConfirmation.resultBad(_ResultMessage: "EXCEPTION", _ResultDetail: ex.Message);
            }
            finally
            {
                // Save Logs if needed
            }

            return(output);
        }