干净的设计处理多个结果集从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"));
}
我们处理这个问题的方式不是对下一个结果进行循环,而是显式地对其进行编码以匹配底层数据。这种方法的预期结果在视觉上更加明显(当然,在我看来)。
下面是重写的示例,假设顺序是成员模型、属性和备选项。
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属性映射,并且仅在您得到特殊条件时才覆盖。