如何在没有重复代码的情况下迭代读取器以获取notnull

时间:2010-08-14 00:05:28

标签: c# asp.net ado.net

首先,我是编程新手(特别是使用C#)并感谢您的帮助。

我有一个包含大约150个表单对象(大多数复选框)的静态Web表单。我决定在sql db中为每个表单提交1条记录。因此,例如,问题X可以选择5个复选框。这5个复选框中的每一个都在db中有一列。

我的帖子页面已完成(正在运行),我正在构建一个编辑页面,我在其中加载记录然后填充表单。

我这样做是通过传递存储过程的id,然后将所有返回的列值放入相应的对象属性,然后将asp控件对象设置为它们。

将asp控件设置为所选值的示例:

questionX.Items[0].Selected = selectedForm.questionX0
questionX.Items[1].Selected = selectedForm.questionX1
questionX.Items[2].Selected = selectedForm.questionX2

如你所见,这非常令人厌烦,因为有超过150个这样做。另外,我刚刚发现响应是否为NULL然后我得到它无法转换为字符串的错误。所以,我添加了这行代码来解决它:

这是我将返回的列值填充到对象属性(实体是对象)的部分:

if (!String.IsNullOrEmpty((string)reader["questionX0"].ToString()))
{entity.patientUnderMdTreatment = (string)reader["questionX0"];}

因此,如果那时声明150次以上,则不必添加此项。必须有办法更有效地做到这一点。

4 个答案:

答案 0 :(得分:1)

首先,您似乎正在使用string.IsNullOrEmpty(value),但这不会检查数据为空时从数据库返回的特殊DBNull值。您应该使用更类似于value is DBNull的内容。

你问题的其余部分听起来很复杂,所以如果我的答案也很复杂,请不要推迟。我个人会使用自定义属性:

声明自定义属性

以下是一个给你这个想法的骨架。您可能希望使用Visual Studio中的“属性”代码段来了解有关如何声明这些代码的更多信息。

[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public sealed class QuestionColumnAttribute : Attribute
{
    public string ColumnName { get; private set; }
    public QuestionColumnAttribute(string columnName)
    {
        ColumnName = columnName;
    }
}

在实体类

中使用自定义属性

在声明实体类的地方,将此自定义属性添加到每个字段,例如声明patientUnderMdTreatment的位置:

[QuestionColumn("questionX0")]
public string patientUnderMdTreatment;

遍历字段

不是遍历阅读器中的列,而是迭代字段。对于每个都有QuestionColumnAttribute的字段,请从阅读器中获取相关列:

foreach (var field in entity.GetType().GetFields())
{
    var attributes = field.GetCustomAttributes(typeof(QuestionColumnAttribute), true);
    if (attributes.Length == 0)
        continue;

    object value = reader[attributes[0].ColumnName];
    if (!(value is DBNull))
        field.SetValue(entity, value.ToString());
}

对于设置ASP控件的问题的第一部分,您可以使用类似的策略迭代selectedForm的字段,这可能更简单,因为您不需要自定义属性 - 只是只取名字以“questionX”开头的字段。

答案 1 :(得分:0)

这是一个快速的&这样做的简单方法..有一些建议可以调查LINQ,我会先解决这些问题。

for (int i = 0; i < 150; i++)
{
    if (!String.IsNullOrEmpty((string)reader["questionX" + i.ToString()].ToString()))
    {entity.patientUnderMdTreatment = (string)reader["questionX" + i.ToString()];}

}

......虽然这对

没有任何好处
questionX.Items[0].Selected = selectedForm.questionX0
questionX.Items[1].Selected = selectedForm.questionX1
questionX.Items[2].Selected = selectedForm.questionX2

答案 2 :(得分:0)

所以我听到两个问题:
- 如何处理来自IDataReader的null? - 如何处理多个领域?

让我们从简单的开始。定义一个帮助方法:

public static T IsDbNull<T>(object value, T defaultValue)
{
    return (T)(value is DBNull ? defaultValue : value);
}

然后使用它:

entity.patientUnderMdTreatment = IsDbNull<string>(reader["question"], null);

现在如何将实体字段映射到表单?那真的取决于你。您可以对其进行硬编码或使用反射。运行时映射与编译时间的差异可能与您的情况完全无关 如果您的表单字段与数据库中的表单字段具有相同的名称,则会有所帮助,因此您不必在其上进行名称映射(如Timwi的帖子中所示),但最终您可能会发现您必须无论如何,对它们中的许多进行验证/规范化,此时硬编码确实是你所需要的,因为根据不断变化的规范,没有办法动态生成逻辑。如果您必须重命名150个db字段或附加150个属性并不重要 - 最后它总是一个O(n)解决方案,其中n是字段数。

我仍然有点不确定为什么你需要读回数据。如果您需要在表单重新加载时保留用户的输入(由于验证错误?),从请求中重新加载它们会不会更容易/更好? entityselectedForm也是同一个对象类型?我假设它不是db实体(否则为什么要使用reader?)。

你可能会采取一些捷径,但我很难跟踪你的阅读和写作时间以及时间。

答案 3 :(得分:-1)

我建议使用NullableDataReader。它消除了这个问题。