[Dapper] Query Parent-Child อย่างไร ?

หลังจากลองทำ Framework ที่เอา Dapper เป็น ORM ครับ ตอนนี้ก็ติดปัญหาว่า เราจะดึงข้อมูลที่อยู่ในรูปแบบ Parent-Child กันอย่างไรครับ โดยผมมีรายละเอียด ดังนี้

โจทย์ที่ผมต้องการ คือ เวลา Query ข้อมูลจาก Table Corporateaction แล้ว ให้มันดึงข้อมูลของ Table ลูก CorporateDetail ขึ้นมาให้หมด โดยการ Query เพียงคร้งเดียวเท่านั้นครับ

POCO Class ของผม มีโครงคร่าวๆ ดังนี้ครับ

  • Parent Class
[Serializable]
[Table("corporateaction")]
public class CorporateActionDTO : MasterDTO
{ 
   //CorporateActionDTO  is Parent Class
   private new object Id { get; set; }
   [Key]
   public int CorporateActionId { get { return (int)base.Id; } set { base.Id = (int)value; } }

   public int? SecurityId { get; set; }

   public string ActionType { get; set; }

   public DateTime ExDate { get; set; }

   //Many Field ...
   
   //CorporateDetailDTO  is Child Class
   [NotIn]
   public IList<CorporateDetailDTO> CorporateDetails { get; set; }
}
  • Child Class
[Serializable]
[Table("CorporateDetail")]
public class CorporateDetailDTO : MasterDTO
{
   //CorporateDetailDTO  is Child Class
   private new object Id { get; set; }

   public int? CorporateDetailId { get { return (int?)base.Id; } set { base.Id = (int?)value; } }

   public int? CorporateActionId { get; set; }

   public string IsExercise { get; set; }
   public int? RightSecurityId { get; set; }
   public decimal MasterSecRatio { get; set; }
   public decimal RightSecRatio { get; set; }
   public decimal RightPrice { get; set; }
   public DateTime TradableDate { get; set; }
}

Query ที่ผมเขียนไว้

SELECT CA.*, CAD.*
FROM CORPORATEACTION CA
   INNER JOIN CORPORATEDETAIL CAD
      ON CA.CORPORATEACTIONID = CAD.CORPORATEACTIONID
         AND CA.CREATETIME = CAD.CREATETIME
WHERE CA.EXDATE = @EXDATE
  AND CA.ACTIVEFLAG = 'A'

Code ในส่วนของ Data Access

ผมเขียนประมาณนี้ครับ

public class CorporateActionADO : MasterADO<CorporateActionDTO, IDictionary<string, object>>, ICorporateActionDAO
{
   public IList FetchWithAllDetailList(IList pActionTypeList
                                                         , DateTime pExDate
                                                         , IList pParentSecurityList)
   {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine(INV_SQL_COMMAND.CORPORATEACTION_FETCHWITHALLDETAIL);

        Dictionary<string, object> parameter = new Dictionary<string, object>();
	parameter.Add("EXDATE", pExDate);

        var lookup = new Dictionary<int, CorporateActionDTO>();
        connection.Query<CorporateActionDTO, CorporateDetailDTO, CorporateActionDTO>(sb.ToString()
                  , (CorporateAction, CorporateActionDetail) => {
                        CorporateActionDTO CA;
                        if (!lookup.TryGetValue((int)CorporateAction.Id, out CA))
                        {
                            lookup.Add((int)CorporateAction.Id, CA = CorporateAction);
                        }
                        if (CA.CorporateDetails == null)
                        {
                            CA.CorporateDetails = new List();
                        }
                        CA.CorporateDetails.Add(CorporateActionDetail);
                        return CA;
                    }, parameter, splitOn: "CorporateDetailId").AsQueryable();
        var resultList = lookup.Values;
      	return resultList.ToList();
   }
}

เดี๋ยวมาอธิบาย Code ของ Data Access กันก่อนครับ สังเกตุว่าจริงๆ มันก็ Query มาทั้งหมดครับ แต่ใช้ Feature Data Mapping กับ Dictionary มาช่วยจัด Data ให้อยุ่ใน Format ที่ต้องการครับ

สำหรับ Blog นี้เกิดจากการไปขุด Unit Test ของ Dapper ครับ จาก Dapper/Dapper.Tests/MultiMapTests.cs ซึ่งนั้นหมายความว่า ถ้า Library มีเป็นลักษณะ Open Source ถึงแม้ว่าเราจะไม่เจอคู่มือ แต่เราสามารถไปดู Unit Test เพื่อมาศึกษา และประยุกต์ใช้ง่ายได้ครับ ^___^

Reference


Discover more from naiwaen@DebuggingSoft

Subscribe to get the latest posts sent to your email.