using System; using System.Collections.Generic; using System.Linq; using System.Transactions; using PizzaDAO; using PizzaModel; // Stateless singleton object for admin part of service API. // Each call to a service method gets a new context and transaction. // If an exception (unhandled within the scope) occurs in the transaction // scope, the transaction is automatically rolled back. The actual commit // happens at the } at the end of the transaction scope. // Since the catch is not needed for rollback, we could let the // exception go to the presentation layer, but by catching it and // re-throwing, we can attach an error message to it. // All this repetitive code could be hidden away by using // an interceptor via AOP. namespace PizzaService { public class AdminService { public AdminService() { } public int CurrentDay { get { int day; using (PizzaEntities context = new PizzaEntities()) { AdminDAO adminDAO = new AdminDAO(context); try { using (TransactionScope tx = new TransactionScope()) { day = adminDAO.FindCurrentDay(); tx.Complete(); } // tx commit here, can fail, cause exception return day; } catch (Exception e) { throw new ApplicationException("DB access failed" + e.InnerException.Message, e); } } } } public void AddPizzaSize(String sizeName) { using (PizzaEntities context = new PizzaEntities()) { PizzaOrderDAO orderDAO = new PizzaOrderDAO(context); AdminDAO adminDAO = new AdminDAO(context); try { using (TransactionScope tx = new TransactionScope()) { adminDAO.AddPizzaSize(sizeName); context.SaveChanges(); tx.Complete(); } } catch (Exception e) { throw new ApplicationException("AddPizzaSize: DB problem" + e.InnerException.Message, e); } } } public void AddTopping(String toppingName) { using (PizzaEntities context = new PizzaEntities()) { PizzaOrderDAO orderDAO = new PizzaOrderDAO(context); AdminDAO adminDAO = new AdminDAO(context); try { using (TransactionScope tx = new TransactionScope()) { adminDAO.AddTopping(toppingName); context.SaveChanges(); tx.Complete(); } } catch (Exception e) { throw new ApplicationException("AddTopping: DB problem: " + e.InnerException.Message, e); } } } public void DeleteTopping(String toppingID) { using (PizzaEntities context = new PizzaEntities()) { PizzaOrderDAO orderDAO = new PizzaOrderDAO(context); AdminDAO adminDAO = new AdminDAO(context); try { using (TransactionScope tx = new TransactionScope()) { Topping top = orderDAO.FindToppingByID(toppingID); adminDAO.DeleteTopping(top); context.SaveChanges(); tx.Complete(); } } catch (Exception e) { throw new ApplicationException("DeleteTopping: DB problem: " + e.InnerException.Message, e); } } } public void DeletePizzaSize(String sizeID) { using (PizzaEntities context = new PizzaEntities()) { PizzaOrderDAO orderDAO = new PizzaOrderDAO(context); AdminDAO adminDAO = new AdminDAO(context); try { using (TransactionScope tx = new TransactionScope()) { PizzaSize size = orderDAO.FindPizzaSizeByID(sizeID); adminDAO.DeletePizzaSize(size); context.SaveChanges(); tx.Complete(); } } catch (Exception e) { throw new ApplicationException("DeletePizzaSize: DB problem: " + e.InnerException.Message, e); } } } // find the oldest pizza (lowest order id) that is now marked "Preparing" // and make it marked Baked public void MarkNextOrderReady() { using (PizzaEntities context = new PizzaEntities()) { PizzaOrderDAO orderDAO = new PizzaOrderDAO(context); AdminDAO adminDAO = new AdminDAO(context); try { using (TransactionScope tx = new TransactionScope()) { PizzaOrder order = orderDAO.FindFirstOrder( (int)PizzaOrder.OrderStatus.Preparing); order.Status = (int)PizzaOrder.OrderStatus.Baked; context.SaveChanges(); tx.Complete(); } } catch (System.Data.ObjectNotFoundException e) { throw new ApplicationException("no orders there for today", e); } catch (Exception e) { throw new ApplicationException( "Error in marking the next order ready" +e.InnerException.Message, e); } } } // advance day for end-of-day work: finish the pizzas (throw them away), // advance the day number public void AdvanceDay() { using (PizzaEntities context = new PizzaEntities()) { PizzaOrderDAO orderDAO = new PizzaOrderDAO(context); AdminDAO adminDAO = new AdminDAO(context); try { using (TransactionScope tx = new TransactionScope()) { int today = adminDAO.FindCurrentDay(); IEnumerable pizzaOrders = orderDAO.FindOrdersByDays(today, today); // day is done, so mark today's pizzas as "finished" foreach (PizzaOrder order in pizzaOrders) { order.Status = (int)PizzaOrder.OrderStatus.Finished; } adminDAO.AdvanceDay(); context.SaveChanges(); tx.Complete(); } } catch (Exception e) { throw new ApplicationException("Unsuccessful advance day" + e.InnerException.Message, e); } } } // get report on today's pizzas public List GetDailyReport() { using (PizzaEntities context = new PizzaEntities()) { PizzaOrderDAO orderDAO = new PizzaOrderDAO(context); AdminDAO adminDAO = new AdminDAO(context); List orders; try { using (TransactionScope tx = new TransactionScope()) { int today = adminDAO.FindCurrentDay(); // make sure orders are put in objects during Tx: run query orders = orderDAO.FindOrdersByDays(today, today).ToList(); tx.Complete(); } } catch (Exception e) { throw new ApplicationException("Error while getting daily report" + e.InnerException.Message, e); } return orders; } } // get report since last admin report public List GetAdminReport() { using (PizzaEntities context = new PizzaEntities()) { List report; PizzaOrderDAO orderDAO = new PizzaOrderDAO(context); AdminDAO adminDAO = new AdminDAO(context); try { using (TransactionScope tx = new TransactionScope()) { int prevLastReportDay = adminDAO.FindLastReportDay(); int today = adminDAO.FindCurrentDay(); report = orderDAO.FindOrdersByDays(prevLastReportDay + 1, today).ToList(); if (today > prevLastReportDay) adminDAO.UpdateLastReportDay(today); // advance past reported days context.SaveChanges(); tx.Complete(); } } catch (Exception e) { throw new ApplicationException("Error in admin report" + e.InnerException.Message, e); } return report; } } } }