改善方法性能

时间:2010-07-23 09:51:30

标签: linq-to-sql

我编写了以下方法,该方法接收列表并根据特定条件更新数据库:

 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.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;
            }
        }

虽然这种方法适用于大约500或1000个对象,但是当我将它提供超过8000个或更多对象时,它会变得太慢或最终超时。 那么,我可以在哪里提高它的性能呢?

3 个答案:

答案 0 :(得分:0)

我不是Linq专家,但我认为你可能会改进getEventId(应该是首字母btw),如

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

    // ...etc
}

使用FirstOrDefault()表示如果找到匹配的元素,则不会处理整个列表。

可能还有其他一些优化措施,但很难跟进你正在做的事情。举个例子:

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

ie在这里没有多大含义。这对你来说可能是显而易见的,但对于从未见过你的代码的人来说,它们并不是很具描述性。同样,list不是List的最佳名称。清单是什么?您的变量名称应描述它的用途。

修改

我不确定其他任何事情。您似乎在一些地方使用ToList(),据我所知,没有必要。我不知道会对表现产生什么影响,但是比我聪明的人可能会告诉你。

您也可以尝试在循环之外提升一些值,例如:

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

可以重写为

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

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

同样,我不确定如果有任何不同,你需要测试它并看到。

答案 1 :(得分:0)

它不会分批进行30次,而是分批进行。

有一个没有条件的查询,所以它加载整个表。这是你的意图吗?

getEventId(e.Id)返回一致的值。不要调用它两次(每个循环)。

答案 2 :(得分:0)

不要循环调用数据库。

尝试在循环之外移动查询,如下所示:

 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();
     }
 }