如何加速基于Linq的数据获取&循环到不同的表?

时间:2015-05-07 14:54:01

标签: c# sql json linq

我有一个WPF应用程序,它使用web-Service来获取记录列表。 此列表通常只包含3到6条记录,每条记录大约有4到7个属性。

但是要计算这些结果,我必须遍历LINQ语句。 例如:请参阅下面的代码(注意此代码(用于的方法)执行嵌套迭代以获取值):

public List<ReturnType> CalculateSomeResult(DateTime startDate, DateTime endDate, int tempID)
    {           
        //Start here...
        List<ReturnType> listResult = new List<ReturnType>();

        string aFormula = GetaFormula(tempID);  //  net worth
        int index = int.Parse(aFormula);

        SomeResult resultTotal = new SomeResult();
        resultTotal.NetWorth = getBeforeEndDate(index, tempID, 0, endDate);

        decimal[] incomes = CalculateProfit(startDate, endDate, tempID);
        decimal[] expenses = CalculateExpense(startDate, endDate, tempID);

        resultTotal.old = incomes[0] - expenses[0];
        resultTotal.current = incomes[1] - expenses[1];

        resultTotal.EndingNetWorth = resultTotal.NetWorth
            + resultTotal.old
            + resultTotal.current;


        ReturnType tempValTotal = new ReturnType();
        tempValTotal.objSomeResult = resultTotal;
        tempValTotal.Name = "Total";

        ReturnType tempVal = new ReturnType();

        using (DCMyDataContext context = new DCMyDataContext())
        {
            try
            {
                var currentEntity = context.Persons.Where(x => x.ID == tempID).FirstOrDefault();
                var contactList = getCByT(CT.I_O, tempID).OrderBy(x => x.ID).ToList();

                //This is where, it converts the DB String column value into 
                //JSON Object list
                List<jsonVal> jsonVals = jsonVal.fromJson<List<jsonVal>>(currentEntity.jsonVal);

                foreach (Contact contact in contactList)
                {                       
                    var objA = jsonVals.Where(x => x.ContactID == contact.ID &&
                        ((x.EndDate.HasValue == false) ||
                        (x.EndDate.HasValue == true && 
                        ((x.StartDate >= startDate && x.StartDate <= endDate) || 
                        (x.EndDate.Value >= startDate && x.EndDate.Value <= endDate)))));

                    var objPreviousA = jsonVals.Where
                        (x => x.ContactID == contact.ID &&
                        ((x.EndDate.HasValue == false) ||
                        ((x.EndDate.HasValue == true && (x.StartDate < startDate || x.EndDate.Value < startDate)))));

                    if (objA.Any() || objPreviousA.Any())
                    {
                    }
                    else
                    {
                        continue;
                    }

                    SomeResult result = new SomeResult();
                    result.NetWorth = getBeforeEndDate(index, tempID, contact.ID, endDate);


                    decimal oldIncome = 0;
                    decimal oldExp = 0;
                    decimal cIncome = 0;
                    decimal cExp = 0;
                    decimal lastaPercent = 0;
                    decimal lastIncomePercent = 0;

                    var lastjsonValRecord = objA.OrderByDescending(x => x.StartDate);
                    if (lastjsonValRecord.Any())
                    {
                        if (lastjsonValRecord.FirstOrDefault().a.HasValue)
                            lastaPercent = lastjsonValRecord.FirstOrDefault().a.Value;
                        if (lastjsonValRecord.FirstOrDefault().Income.HasValue)
                            lastIncomePercent = lastjsonValRecord.FirstOrDefault().Income.Value;
                    }
                    IEnumerable<int> incomeIDs = GetLeafAccountIDs(5, tempID);
                    IEnumerable<int> expenseIDs = GetLeafAccountIDs(6, tempID);

                    if (objA.Any())
                    {
                        foreach (jsonVal ownerRec in objA.ToList())
                        {
                            DateTime dtEnd = endDate;
                            if (ownerRec.EndDate.HasValue)
                                dtEnd = ownerRec.EndDate.Value;
                            if (dtEnd > endDate)
                                dtEnd = endDate;
                            DateTime dtStart = ownerRec.StartDate;
                            if (ownerRec.StartDate <= startDate)
                                dtStart = startDate;
                            decimal incomePercent = 0;
                            if (ownerRec.Income.HasValue) incomePercent = ownerRec.Income.Value;
                            if (incomePercent > 0 )
                            {
                                foreach (int id in incomeIDs)
                                {
                                    decimal bal = CalculateB(id, dtStart, dtEnd);
                                    cIncome += (bal * incomePercent / 100m);
                                }
                                foreach (int id in expenseIDs)
                                {
                                    decimal bal = CalculateB(id, dtStart, dtEnd);
                                    cExp += (bal * incomePercent / 100m);
                                }
                            }
                        }
                    }

                    if (objPreviousA.Any())
                    {
                        foreach (jsonVal ownerRec in objPreviousA.ToList())
                        {
                            DateTime dtEnd = endDate;
                            DateTime dtStart = ownerRec.StartDate;
                            if (ownerRec.EndDate.HasValue)
                                dtEnd = ownerRec.EndDate.Value;
                            if (dtEnd > startDate)
                                dtEnd = startDate;
                            if (dtStart > startDate)
                                dtStart = startDate;

                            decimal incomePercent = 0;
                            if (ownerRec.Income.HasValue) incomePercent = ownerRec.Income.Value;
                            if (incomePercent > 0 && ownerRec.StartDate > new DateTime(1, 1, 1))
                            {
                                foreach (int id in incomeIDs)
                                {
                                    decimal bal = CalculateB(id, dtStart, dtEnd);
                                    oldIncome += (bal * incomePercent / 100m);
                                }
                                foreach (int id in expenseIDs)
                                {
                                    decimal bal = CalculateB(id, dtStart, dtEnd);
                                    oldExp += (bal * incomePercent / 100m);
                                }
                            }
                        }
                    }

                    result.old = oldIncome - oldExp;
                    result.current = cIncome - cExp;

                    result.EndingNetWorth = result.NetWorth
                            + result.old
                            + result.current;

                    tempVal = new ReturnType();
                    tempVal.objSomeResult = result;
                    tempVal.Name = contact.FirstName;
                    listResult.Add(tempVal);
                }
            }
            catch 
            {
            }
        }

        listResult.Add(tempValTotal);

        //Reach here after 15 seconds...
        return listResult;

    }

当我调试此代码时,需要1个15秒才能到达return语句。

我试图将整个处理转换为SQL Stored proc,可能会提高处理速度。但我有一个块点,在数据库表中我将Json字符串存储在一列和一列中。这里使用的结果来获得结果。

我知道我需要创建自定义功能以将其解析为SQL中的相关表对象。或者我需要更改将Json字符串保存到列中的默认行为,以将其保存到新表中。

但这对我来说需要花费很多时间。 我需要任何建议,以加快处理速度。 我会考虑所有&amp;选择那个适合我的。

由于

2 个答案:

答案 0 :(得分:0)

您应该运行调试会话并找到大部分时间占用的确切行。几乎不可能在工作环境中为你检查代码(它可能是很多东西,sql转换.ToList()需要太长时间,缺少索引,有几个调用到其他一些方法,等等)

如果您运行调试会话,则可以登录每个&#34;部分&#34;该代码,然后注意大部分时间的部分,并将注意力集中在该特定行,以找到解决方案。

答案 1 :(得分:0)

减少您正在进行的查询次数。既然您知道自己需要为每个联系人运行objAobjPreviousA,而不是一次只获取一个联系人,请抓住所有联系人并在一次调用中将它们放入列表/字典中,然后将objA / objPreviousA设置为循环中的适当值。

类似的东西:

var contactIds=contactList.Select(c=>c.id).ToArray();
var objAs = jsonVals.Where(x => contactIds.Any(cid=>cid==x.ContactID) &&
                    ((x.EndDate.HasValue == false) ||
                    (x.EndDate.HasValue == true && 
                    ((x.StartDate >= startDate && x.StartDate <= endDate) || 
                    (x.EndDate.Value >= startDate 
                       && x.EndDate.Value <= endDate)))))
     .ToList();

foreach(var contact in contactList)
{
    var objA=objAs.Where(a=>a.ContactId==contact.id).ToList();
    ...

这适用于中小量的记录。如果它变得太大,那么你应该转换为使用Dictionary而不是List,以减少循环中的查找时间。