干净的设计处理多个结果集从IDataReader

本文关键字:结果 IDataReader 处理 | 更新日期: 2023-09-27 18:16:33

也许SO不是这个地方,如果不是,我很抱歉,但我忍不住想有更好的方法来做到这一点。这似乎是一种粗糙且不太干净的检查结果集的方法,然后执行相应的操作。有人有什么建议吗?(请忽略我总是返回null的事实)。

public MemberDto Load(long entityId)
    {
        using (var cn = new SqlConnection(@"connectionstringstuff"))
        {
            cn.Open();
            using (SqlCommand cm = cn.CreateCommand())
            {
                cm.CommandText = "Client.[MemberGet]";
                cm.CommandType = CommandType.StoredProcedure;
                cm.Parameters.AddWithValue("@EntityId", entityId);
                using (IDataReader dr = cm.ExecuteReader())
                {
                    var memberModel = new MemberDto();
                    do
                    {
                        while (dr.Read())
                        {
                            var sdr = new SafeDataReader(dr);
                            var firstColumn = sdr.GetName(0);
                            if (firstColumn.StartsWith("Attribute"))
                            {
                                AddAttribute(memberModel, sdr);
                            }
                            else if (firstColumn.StartsWith("AlternateId"))
                            {
                                AddAlternateId(memberModel, sdr);
                            }
                            else
                            {
                                memberModel.ClientId = sdr.GetInt64("ClientId");
                                memberModel.Id = sdr.GetInt64("EntityId");
                                memberModel.Name = sdr.GetString("EntityName");
                            }
                        }
                    } while (dr.NextResult());
                }
            }
        }
        return null;
    }
    private void AddAttribute(MemberDto model, SafeDataReader reader)
    {
        model.Attributes.Add(
            reader.GetInt32("AttributeTypeId").As<EntityAttributeType>(),
            reader.GetString("Value"));
    }
    private void AddAlternateId(MemberDto model, SafeDataReader reader)
    {
        model.Attributes.Add(
            reader.GetInt32("AlternateIdTypeId").As<EntityAttributeType>(),
            reader.GetString("Value"));
    }

干净的设计处理多个结果集从IDataReader

我们处理这个问题的方式不是对下一个结果进行循环,而是显式地对其进行编码以匹配底层数据。这种方法的预期结果在视觉上更加明显(当然,在我看来)。

下面是重写的示例,假设顺序是成员模型、属性和备选项。

    while (dr.Read())
    {
        var sdr = new SafeDataReader(dr);
        memberModel.ClientId = sdr.GetInt64("ClientId");
        memberModel.Id = sdr.GetInt64("EntityId");
        memberModel.Name = sdr.GetString("EntityName");
    }
    if (dr.NextResult())
    {
        while (dr.Read())
        {
            AddAttribute(memberModel, new SafeDataReader(dr));
        }
    }
    if (dr.NextResult())
    {
        while (dr.Read())
        {
            AddAlternateId(memberModel, new SafeDataReader(dr));
        }
    }

也许所有返回多个结果集的sp都应该首先包含一个结果集,指定返回结果集的顺序:

dr = multRsCmd.ExecureReader();
// first rs is always the meta
List<string> resultSetIds = new List<string>();
while (dr.Read())
   resultSetIds.Add(dr[0]
foreach (string rsId in resultSetIds)
{
   if (!dr.NextResult())
      break; // or throw, should not happen
   if (rsId == "ClientDataWithAttribute")
   {
      // code to handle the exact rs layout for ClientDataWithAttribute
      //
      //
   }
   else if (rsId == "ClientDataWithAltId")
   {
      // code to handle the exact rs layout for ClientDataWithAltId
      //
      //   
   }
   else if (rsId == "ClientData")
   {
      // code to handle the exact rs layout for ClientData
      //
      //   
   }
}

这当然需要重构:

dr = multRsCmd.ExecureReader();
// first rs is always the meta
List<string> resultSetIds = new List<string>();
while (dr.Read())
   resultSetIds.Add(dr[0]
foreach (string rsId in resultSetIds)
{
   if (!dr.NextResult())
      break; // or throw, should not happen
   // pull subclass out of registry of readers
   ResultSetReader rsr = ResultSetReaders.Find(rsId);
   // subclass cleanly holds the layout-dependent logic
   memberModel = rsr.FromDataReader(dr);
 }

这看起来很干净,但是您甚至可以在ResultSetReader中添加默认行为来驱动来自配置文件或其他源的DTO属性映射,并且仅在您得到特殊条件时才覆盖。