繁体   English   中英

使用Lambda / Linq C#和DTO进行多表联接

[英]Multiple table join using lambda/linq c# with DTO

这真让我难过。 我的数据库中有四个表,不幸的是,设计该表的人没有创建引用约束。 因此,没有可用的导航属性。

四个表是:

CiscoPhoneReport
ApplicationSummary
CSQActivityReport
CallDistributionSummary

这个想法是,对于PhoneReportID中的每个PhoneReportID ,都有一个ApplicationSummary ,三个CSQActivityReport和三个CallDistributionSummary

我想要以下JSON格式的输出:

`[{
   "appSummary":{
   "startDate":"2015-09-01T00:00:00",
   "endDate":"2015-09-30T00:00:00",
   "applicationName":"RationalDrugTherapy",
   "callsPresented":14504,
   "callsAbandoned":1992,
   "callsHandled":12512
  },
  "csqModel":[
   {
     "startDate":null,
     "csqid":"3",
     "callsPresented":6271,
     "avgQueueTime":"00:00:21",
     "callsHandled":0,
     "avgAnswerSpeed":"00:00:00",
     "avgHandleTime":"00:02:08",
     "callsHandledGreaterThan3t":5742,
     "callsAbandoned":99,
     "avgAbandonTime":"00:02:20",
     "maxQueueTime":"00:25:26",
     "maxHandleTime":"00:19:33",
     "maxAbandonTime":"00:17:50"
   },{
     "startDate":null,
     "csqid":"3",
     "callsPresented":6271,
     "avgQueueTime":"00:00:21",
     "callsHandled":0,
     "avgAnswerSpeed":"00:00:00",
     "avgHandleTime":"00:02:08",
     "callsHandledGreaterThan3t":1728,
     "callsAbandoned":99,
     "avgAbandonTime":"00:02:20",
     "maxQueueTime":"00:25:26",
     "maxHandleTime":"00:19:33",
     "maxAbandonTime":"00:17:50"
  }, {
    "startDate":null,
    "csqid":"3",
    "callsPresented":6271,
    "avgQueueTime":"00:00:21",
    "callsHandled":0,
    "avgAnswerSpeed":"00:00:00",
    "avgHandleTime":"00:02:08",
    "callsHandledGreaterThan3t":3363,
    "callsAbandoned":99,
    "avgAbandonTime":"00:02:20",
    "maxQueueTime":"00:25:26",
    "maxHandleTime":"00:19:33",
    "maxAbandonTime":"00:17:50"
  }]
}]`

为此,我创建了DTO:

`public class AppSummary
 {
   public string PhoneReportID { get; set; }
   public DateTime StartDate { get; set; }
   public DateTime EndDate { get; set; }
   public string ApplicationName { get; set; }
   public int CallsPresented { get; set; }
   public int CallsAbandoned { get; set; }
   public int CallsHandled { get; set; }
 }
`

`public class CSQModel
    {
        public string StartDate { get; set; }
        public string CSQID { get; set; }
        public int CallsPresented { get; set; }
        public TimeSpan AvgQueueTime { get; set; }
        public int CallsHandled { get; set; }
        public TimeSpan AvgAnswerSpeed { get; set; }
        public TimeSpan AvgHandleTime { get; set; }
        public int CallsHandledGreaterThan3t { get; set; }
        public int CallsAbandoned { get; set; }
        public TimeSpan AvgAbandonTime { get; set; }
        public TimeSpan MaxQueueTime { get; set; }
        public TimeSpan MaxHandleTime { get; set; }
        public TimeSpan MaxAbandonTime { get; set; }      
    }
`

`public class PhoneReport
    {
        public AppSummary AppSummary { get; set; }
        //Initially, I had it like this
        public CSQModel CSQModel { get; set; }

        //I renamed the property as LIST to see if I could use it and add data to the list in linq, but I couldn't use the list within select expression in linq.
        //public List<CSQModel> CSQModel { get; set; }

    }
`

CSQModel类从CSQActivityReportCallDistributionSummary表中都需要数据。

我能够使用表连接创建linq语句,如下所示。

var res = from cpr in db.CiscoPhoneReport 
        join app in db.ApplicationSummary on cpr.PhoneReportID equals          app.PhoneReportID into g1
        from appGroup in g1.DefaultIfEmpty()
        join csq in db.CSQActivityReport on cpr.PhoneReportID equals csq.PhoneReportID into g2
        from csqGroup in g2.DefaultIfEmpty()
        join call in db.CallDistributionSummary on cpr.PhoneReportID equals call.PhoneReportID into g3
        from callGroup in g3.DefaultIfEmpty()
        where cpr.PhoneReportID == phoneReportID
        select new PhoneReport
        {
           AppSummary = new AppSummary
          {
             StartDate = cpr.StartDate,
             EndDate = cpr.EndDate,
             ApplicationName = appGroup.ApplicationName,
             CallsPresented = appGroup.CallsPresented,
             CallsAbandoned = appGroup.CallsAbandoned,
             CallsHandled = appGroup.CallsHandled

         },
         CSQModel = new CSQModel
         {
             CSQID = csqGroup.CSQID.ToString(),
             CallsPresented = csqGroup.CallsPresented,
             AvgQueueTime = csqGroup.AvgQueueTime,                                                
             AvgHandleTime = csqGroup.AvgHandleTime, 
             CallsHandledGreaterThan3t = callGroup.CallsHandledGreaterThan3t, 
             CallsAbandoned = csqGroup.CallsAbandoned,
             AvgAbandonTime = csqGroup.AvgAbandonTime,
             MaxQueueTime = csqGroup.MaxQueueTime,
             MaxHandleTime = csqGroup.MaxHandleTime,
             MaxAbandonTime = csqGroup.MaxAbandonTime
         }
   };
`

我得到的结果是一组具有9行的数据,这很有意义-就像在SQL中的内部联接一样。 但这不是我想要的。

如何获取上述JSON格式的数据? 我完全不知道。

我认为看到9条记录的部分原因是因为您使用的语法是Linq中用于左外部联接的语法。

可能的工作是使用子查询以所需的格式获取所需的数据。

例如

var res = from cpr in db.CiscoPhoneReport
          join app in db.ApplicationSummary on cpr.PhoneReportID equals app.PhoneReportID
          where cpr.PhoneReportID == phoneReportID
          select new PhoneReport
          {
              AppSummary = new AppSummary
              {
                  // Mappings
              },
              CSQModel = (from model in db.CSQActivityReport
                          where model.PhoneReportId == phoneReportID
                          select new CSQModel
                          {
                              // Mappings
                          }).ToList()
          }

没错,您需要CSQModels是某种类型的集合,无论是List还是CSQModel类型的基本ICollection 您可以根据需要为CallDistributionSummary编写另一个子查询。

对于每个主记录,在2个单独的子表中都有3条记录。 除非您添加更多信息,否则您执行的任何联接都会给您9条记录(即使您直接使用T-SQL)。

在SQL中执行此操作的一种方法是将表A中的记录1连接到表B中的记录1,您将需要一个索引器来执行此操作。 T-SQL中的一个选项是在每个子表上使用ROW_NUMBER()函数,并在联接中使用该值。 但是, ROW_NUMBER()尚未扩展到LINQ。

如果您不能忍受获取重复的记录,而只是对每个子结果集执行Distinct()调用。 然后,您可以将其作为两个或三个单独的查询来执行。

注意:您可以将其捆绑到存储过程中的3个结果集中。您可以轻松获取EntityFramework以将每个结果反序列化为POCO。

            var objCtx = ((IObjectContextAdapter)ctx).ObjectContext;

            using (SqlCommand cmd = ctx.Database.Connection.CreateCommand() as SqlCommand)
            {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.CommandText = "<your proc here>";

                var param = cmd.CreateParameter();
                param.ParameterName = "@param1";
                param.Value = someValue;
                cmd.Parameters.Add(param);

                await cmd.Connection.OpenAsync();
                using (var reader = await cmd.ExecuteReaderAsync())
                {
                    var results = objCtx.Translate<type1Here>(reader).ToList();
                    reader.NextResult();
                    var results2 = objCtx.Translate<type2Here>(reader).ToList();
                    reader.NextResult();
                    var results3 = objCtx.Translate<type3Here>(reader).ToList();
                    reader.NextResult();
                }
            }

您可以序列化对象:

            DataContractJsonSerializer serializer = new DataContractJsonSerializer(GenericObject.GetType());

            MemoryStream ms = new MemoryStream();
            serializer.WriteObject(ms, GenericObject);
            string json = Encoding.UTF8.GetString(ms.ToArray());
            ms.Close();
            return json;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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