在复杂类型的列表中填充复杂类型

时间:2018-05-08 16:23:46

标签: c#

我们说我有一个复杂类型的列表(称为' ClientMessage')。 ClientMessage有一种名为' MsgText'以及名为' ClientMessageDeeplinkResponse'的班级列表除了一堆其他简单的类型之外。

目前,存储过程返回三个数据集。 tmpMsgResult是主要结果,tmpDeeplinkResult和tmpMsgTxt是次要结果,将用于丰富最终结果。

存储过程快速执行(sub second)。 tmpMsgResult返回26000行,tmpDeeplinkResult返回21000行,tmpMsgTxt返回63300行。

如何填充' MsgText'和' ClientMessageDeeplinkResponse'在ClientMessage中快速?我尝试了几种方法,从20秒到45秒。

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ItchyScratchy13
{
    class CMCSimple
    {
        public static List<ClientMessage> ReadClientMessagesSP(string connString, string GCN, bool? messageDeleted, bool? messageArchived)
        {
            List<ClientMessage> results = new List<ClientMessage>();

            using (SqlConnection conn = new SqlConnection(connString))
            {
                using (SqlCommand cmd = new SqlCommand("cmc.GetCmcMessages", conn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;

                    cmd.Parameters.Add("@GCN", SqlDbType.VarChar).Value = GCN;
                    cmd.Parameters.Add("@DeletedMsgs", SqlDbType.Bit).Value = messageDeleted;
                    cmd.Parameters.Add("@ArchivedMsgs", SqlDbType.Bit).Value = messageArchived;

                    conn.Open();

                    DataSet ds = new DataSet();
                    SqlDataAdapter adapter;
                    adapter = new SqlDataAdapter(cmd);
                    adapter.Fill(ds);

                    var tmpMsgResult = ds.Tables[0].AsEnumerable().Select(s => new ClientMessage
                    {
                        MsgID = s.Field<int>("MessageId"),
                        MsgAuditID = s.Field<int>("MessageAuditId"),
                        MsgGUID = s.Field<Guid>("MsgGuid"),
                    }).ToList();

                    var tmpDeeplinkResult = ds.Tables[1].AsEnumerable().Select(s => new AdminClientMessageDeeplink
                    {
                        MessageId = s.Field<int>("MessageId"),
                        DeeplinkMask = s.Field<string>("DeeplinkMask"),
                        DeeplinkName = s.Field<string>("DeeplinkName"),
                        DeepLinkValue = s.Field<string>("DeeplinkValue"),
                    }).ToList();

                    var tmpMsgTxt = ds.Tables[2].AsEnumerable().Select(s => new AdminClietnMsgTxt
                    {
                        MessageId = s.Field<int>("MessageId"),
                        MessageTxt = s.Field<string>("MessageText"),
                        RowNumber = int.Parse(s.Field<Int64>("ROW_NUMBER").ToString()),

                    }).ToList();



                    //ATTEMPT 1
                    Parallel.ForEach(tmpMsgResult, item =>
                    {
                        item.DeepLink = tmpDeeplinkResult.Where(wh => wh.MessageId == item.MsgID).Select(s => new ClientMessageDeeplinkResponse
                        {
                            DeeplinkMask = s.DeeplinkMask,
                            DeeplinkName = s.DeeplinkName,
                            DeepLinkValue = s.DeepLinkValue,
                        }).ToList();

                        item.MsgText = tmpMsgTxt.Where(wh => wh.MessageId == item.MsgID).Select(s => new KeyValuePair<int, string>(s.RowNumber, s.MessageTxt)).ToDictionary(x => x.Key, x => x.Value);
                    });

                    //ATTEMPT 2
                    results = tmpMsgResult.Select((x, i) => new ClientMessage
                    {
                        DeepLink = tmpDeeplinkResult.Where(wh => wh.MessageId == x.MsgID).AsParallel().Select(s => new ClientMessageDeeplinkResponse() { DeeplinkMask = s.DeeplinkMask, DeeplinkName = s.DeeplinkName, DeepLinkValue = s.DeepLinkValue }).ToList(),
                        MsgAuditID = x.MsgAuditID,
                        MsgGUID = x.MsgGUID,
                        MsgID = x.MsgID,
                        MsgText = tmpMsgTxt.Where(wh => wh.MessageId == x.MsgID).AsParallel().Select(s => new { s.RowNumber, s.MessageTxt }).ToDictionary(td => td.RowNumber, td => td.MessageTxt)
                    }).ToList();

                    //ATTEMPT 3
                    foreach (var item in tmpMsgResult)
                    {
                        item.DeepLink = tmpDeeplinkResult.Where(wh => wh.MessageId == item.MsgID).Select(s => new ClientMessageDeeplinkResponse
                        {
                            DeeplinkMask = s.DeeplinkMask,
                            DeeplinkName = s.DeeplinkName,
                            DeepLinkValue = s.DeepLinkValue
                        }).ToList();

                        item.MsgText = tmpMsgTxt.Where(wh => wh.MessageId == item.MsgID).Select(s => new KeyValuePair<int, string>(s.RowNumber, s.MessageTxt)).ToDictionary(x => x.Key, x => x.Value);
                    }

                    //ATTEMPT 4, super fast but not correct result set
                    results = (from zxc in tmpMsgResult
                               join vbn in tmpDeeplinkResult
                                 on zxc.MsgID equals vbn.MessageId
                               join asd in tmpMsgTxt
                                   on zxc.MsgID equals asd.MessageId
                               select new ClientMessage
                               {                                   
                                   DeepLink = new List<ClientMessageDeeplinkResponse>() { vbn },                                   
                                   MsgAuditID = zxc.MsgAuditID,                                   
                                   MsgGUID = zxc.MsgGUID,
                                   MsgID = zxc.MsgID,                                   
                                   MsgText = new Dictionary<int, string> { { asd.RowNumber, asd.MessageTxt } }
                               }).ToList();
                }
            }
            return results;
        }

    }

    public class ClientMessage
    {
        public int MsgID { get; set; }
        public int MsgAuditID { get; set; }
        public Guid? MsgGUID { get; set; }
        public Dictionary<int, string> MsgText { get; set; }
        public List<ClientMessageDeeplinkResponse> DeepLink { get; set; }
    }

    public class AdminClientMessageDeeplink : ClientMessageDeeplinkResponse
    {
        public int MessageId { get; set; }
        public int DeeplinkId { get; set; }
    }

    public class AdminClietnMsgTxt
    {
        public int MessageId { get; set; }
        public string MessageTxt { get; set; }
        public int RowNumber { get; set; }
    }

    public class ClientMessageDeeplinkResponse
    {
        public string DeeplinkName { get; set; }
        public string DeepLinkValue { get; set; }
        public string DeeplinkMask { get; set; }
    }
}

1 个答案:

答案 0 :(得分:1)

使用GroupByDictionaries应该可以按照以下方式执行操作:

....

// It's better to use Dictionary for tmpDeeplinkResult and tmpMsgTxt

var grouppedTmpDeeplinkResult = tmpDeeplinkResult.GroupBy(x => x.MessageId).ToDictionary(g => g.Key, g => g.ToList());
var grouppedTmpMsgTxt = tmpDeeplinkResult.GroupBy(x => x.MessageId).ToDictionary(g => g.Key, g => g.ToDictionary(x => x.RowNumber, x => x.MessageTxt));

foreach (var item in tmpMsgResult)
{
    item.DeepLink = grouppedTmpDeeplinkResult[item.MsgID].Select(s => new ClientMessageDeeplinkResponse
    {
        DeeplinkMask = s.DeeplinkMask,
        DeeplinkName = s.DeeplinkName,
        DeepLinkValue = s.DeepLinkValue
    }).ToList();
    item.MsgText = grouppedTmpMsgTxt[item.MsgID];
}

....

字典的查找(例如dict [x])可能看起来与List相同,但它使用hashset并且具有O(1)复杂度,而list.Where(...)具有O(N)的复杂性。

相关问题