开发者

Improving method performance

I wrote the following method that receives a list and updates the database based on certain criteria:

 public void UpdateInventoryGoods(List<InventoryGoods> list, int id)
        {
            int index = 0;

            var query = from inventoryGoods in context.InventoryGoods
                        where inventoryGoods.ParentId == id
                        select inventoryGoods;

            List<InventoryGoods> goodsList = query.ToList();

            using (var scope = new TransactionScope())
            {
                foreach (InventoryGoods i in list)
                {
                    foreach (InventoryGoods e in goodsList)
                    {
                        if (index == 30)
                        {
                            index = 0;
                            context.SubmitChanges();
                        }

                        if (e.Gid == i.Gid && !getEventId(e.Id).HasValue && !e.ActionOn.HasValue)
                        {
                            e.Action = i.Action;

                        }
                        else if ((e.Gid == i.Gid && getEventId(e.Id).HasValue) && (e.Action != i.Action || i.ActionOn == DateTime.MinValue))
                        {
                            e.Action = i.Action;
                            e.ActionOn = null;

                            var allEvents = from invent in context.InventoryGoodsEvents
                                            where invent.InventoryGood == e.Id
                                            select invent;

                            List<InventoryGoodsEvents> inventoryGoodsEventsList = allEvents.ToList();

                            var events = from g in context.GoodsEvent                                         
                                         select g;

                            List<GoodsEvent> goodsEventList = events.ToList();

                            foreach (InventoryGoodsEvents goodsEvent in inventoryGoodsEventsList)
                            {
                                context.InventoryGoodsEvents.DeleteOnSubmit(goodsEvent);

                                foreach (GoodsEvent ge in goodsEventList)
                                {
                                    if (ge.开发者_Python百科Id == goodsEvent.EventId)
                                    {
                                        ge.IsDeleted = true;
                                        ge.DeletedOn = DateTime.Now;
                                        ge.DeletedBy = System.Web.HttpContext.Current.User.Identity.Name;
                                    }
                                }                                
                            }




                        }
                        ++index;
                    }
                }
                context.SubmitChanges();
                scope.Complete();
            }

        }

        public int? getEventId(int InventoryGood)
        {


            var InventoryGoodsEvents = from i in context.InventoryGoodsEvents
                                       where i.InventoryGood == InventoryGood
                                       select i;

            List<InventoryGoodsEvents> lst = InventoryGoodsEvents.ToList();

            if (lst.Count() > 0)
            {
                return lst[0].EventId;
            }
            else
            {
                return null;
            }
        }

Though this method works well for about 500 or 1000 objects, it gets too slow or eventually times out when I feed it over 8000 objects or more. So, where could I improve its performance a little?


Don't call the database in a loop.

Try moving the queries outside the loops like this:

 public void UpdateInventoryGoods(List<InventoryGoods> list, int id)
 {
     int index = 0;

     var query = from inventoryGoods in context.InventoryGoods
                 where inventoryGoods.ParentId == id
                 select inventoryGoods;

     List<InventoryGoods> goodsList = query.ToList();

     using (var scope = new TransactionScope())
     {
         var allEvents = from invent in context.InventoryGoodsEvents
                         where goodsList.Contains(invent.InventoryGood)
                         select invent;

         List<InventoryGoodsEvents> inventoryGoodsEventsList = allEvents.ToList();

         var events = from g in context.GoodsEvent
                      select g;

         List<GoodsEvent> goodsEventList = events.ToList();

         foreach (InventoryGoods i in list)
         {
             foreach (InventoryGoods e in goodsList)
             {
                 if (index == 30)
                 {
                     index = 0;
                     context.SubmitChanges();
                 }

                 var eventId = getEventId(e.Id);
                 if (e.Gid == i.Gid && !eventId.HasValue && !e.ActionOn.HasValue)
                 {
                     e.Action = i.Action;

                 }
                 else if ((e.Gid == i.Gid && eventId.HasValue) && (e.Action != i.Action || i.ActionOn == DateTime.MinValue))
                 {
                     e.Action = i.Action;
                     e.ActionOn = null;

                     foreach (InventoryGoodsEvents goodsEvent in inventoryGoodsEventsList)
                     {
                         context.InventoryGoodsEvents.DeleteOnSubmit(goodsEvent);

                         foreach (GoodsEvent ge in goodsEventList)
                         {
                             if (ge.Id == goodsEvent.EventId)
                             {
                                 ge.IsDeleted = true;
                                 ge.DeletedOn = DateTime.Now;
                                 ge.DeletedBy = System.Web.HttpContext.Current.User.Identity.Name;
                             }
                         }
                     }
                 }
                 ++index;
             }
         }
         context.SubmitChanges();
         scope.Complete();
     }
 }


I'm no Linq expert, but I think you can probably improve getEventId (should be capital first letter btw) with something like

public int? GetEventId(int inventoryGood)
{
    var firstInventoryGoodsEvent = context.InventoryGoodsEvents
                  .Where(i => i.InventoryGood == inventoryGood)
                  .FirstOrDefault();

    // ...etc
}

The use of FirstOrDefault() means you don't process the whole list if you find a matching element.

There are probably other optimisations but it's quite difficult to follow what you're doing. As an example:

 foreach (InventoryGoods i in list)
 {
     foreach (InventoryGoods e in goodsList)
     {
     }
 }

i and e don't confer much meaning here. It might be obvious to you what they mean but they aren't very descriptive to someone who has never seen your code before. Similarly, list is not the best name for a List. List of what? Your variable name should describe it's purpose.

Edit:

I'm not sure about anything else. You seem to be using ToList() in a few places where as far as I can see it's not necessary. I don't know what effect that would have on performance, but someone cleverer than me could probably tell you.

You could also try hoisting a few of your values outside of loops, eg:

foreach (foo)
{
    foreach (bar)
    {
        DeletedOn = DateTime.Now;
        DeletedBy = System.Web.HttpContext.Current.User.Identity.Name;
    }
}

can be re-written as

var deletedOn = DateTime.Now;
var deletedBy = System.Web.HttpContext.Current.User.Identity.Name;

foreach (foo)
{
    foreach (bar)
    {
        DeletedOn = deletedOn;
        DeletedBy = deletedBy;
    }
}

Again, I'm not sure how much difference if any that would make, you'll need to test it and see.


It's not going in batches of 30, it's going in batches of 1.

There's a query with no criteria, so it loads the whole table. Is that your intention?

getEventId(e.Id) returns a consistent value. Don't call it twice (per loop).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜