简体   繁体   中英

Using virtual collection in C# to make code more efficient

Hello I have a model that looks like this,

  public class Site
    {
        public int ID { get; set; }

        public string Name { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string Province { get; set; }
        public string PostalCode { get; set; }

        public virtual ICollection<OffSiteItemDetails> ItemDetails { get; private set; }
        public virtual ICollection<SalesOrder> soDetails { get; private set; }
        public virtual ICollection<SODetails> SODDetails { get; private set; }

        public string IncomingTotalOSI(Site s)
        {
            PIC_Program_1_0Context db = new PIC_Program_1_0Context();
            float? partCost = 0;
            float? componentCost = 0;
            float? itemCost = 0;
            float? incomingCost = 0;
            List<OffSiteItemDetails> d = ItemDetails.Where(x => x.siteID == s.ID).ToList();


            var less30days = DateTime.Now.AddDays(-30);
            //List<SalesOrder> so = soDetails.Where(x => x.OrderType == SOType.OffSiteInventory).Where(x => x.DateCreated > less30days).ToList();
            List<SalesOrder> so = db.SalesOrders.Where(x => x.OrderType == SOType.OffSiteInventory).Where(x => x.DateCreated > less30days).ToList();
            List<SODetails> sod = db.SODetails.Where(x => x.SiteID == s.ID).ToList();

       foreach (var order in so)
        {

            foreach (var details in sod)
            {

                if (order.ID == details.SalesOrderID)
                {

                    if (details.PartID != null){
                        partCost += details.part_qty * db.Parts.Where(x => x.ID == details.PartID).FirstOrDefault().AveCostPerUnit;
                    }
                    else if (details.ComponentID != null){
                        componentCost += details.comp_qty * db.Components.Where(x => x.ID == details.ComponentID).FirstOrDefault().AveCostPerUnit;
                    }
                    else{
                        itemCost += details.item_qty * db.Items.Where(x => x.ID == details.ItemID).FirstOrDefault().CostPerUnit;
                    }
                }

            }
        }
        incomingCost = partCost + componentCost + itemCost;

            string cost = String.Format("{0:C}", incomingCost);

            return cost;
        }
  }

But this is inefficient as it looping over the same data set multiple times. And the more orders that are added, the slower the program will be become. I'm still learning MVC and have looked into virtual collections but I'm still confused on how I could you it in this scenario to improve the efficiency of the program

To begin with, I would suggest removing the .ToList() from this line:

List sod = db.SODetails.Where(x => x.SiteID == s.ID).ToList();

When you use ToList() there, you are forcing an execution and enumeration to occur against the underlying data store at that point rather than deferring execution until you actually need to enumerate the desired results.

Then change the following line:

foreach (var details in sod)

To:

foreach (var details in db.SODetails .Where(x => x.SiteID == s.ID && details.SalesOrderID == order.ID))

The trade-off of course is that you are hitting the database with a query for every sales order, but you are not iterating over the same data multiple times.

You could also get rid of the if() statement in the inner most loop and simply put your condition in the Linq to limit what is looped over. This may improve performance as well:

foreach (var details in sod.Where(detail => detail.SalesOrderID == order.ID)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM