C# 如何在不反复重复代码的情况下遍历notnull的读取器

C# 如何在不反复重复代码的情况下遍历notnull的读取器,c#,asp.net,ado.net,C#,Asp.net,Ado.net,首先,我刚开始编程,尤其是C语言,谢谢你的帮助 我有一个静态web表单,大多数复选框中有大约150个表单对象。我决定在sql db中为每个表单提交一条记录。例如,问题X有5个复选框可供选择。这5个复选框中的每一个在数据库中都有一列 我已经完成了post页面的工作,正在构建一个编辑页面,在那里我加载记录,然后填充表单 我是如何做到这一点的,通过将存储的proc传递id,然后将所有返回的列值放入相应的对象属性中,然后将asp控件对象设置为它们 将asp控件设置为选定值的示例: questionX.I

首先,我刚开始编程,尤其是C语言,谢谢你的帮助

我有一个静态web表单,大多数复选框中有大约150个表单对象。我决定在sql db中为每个表单提交一条记录。例如,问题X有5个复选框可供选择。这5个复选框中的每一个在数据库中都有一列

我已经完成了post页面的工作,正在构建一个编辑页面,在那里我加载记录,然后填充表单

我是如何做到这一点的,通过将存储的proc传递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"];}

因此,不必将if-then语句添加150多次。必须有一种更有效的方法。我建议使用。它消除了这个问题。

这是一种快速简便的方法。。有一些关于调查LINQ的建议,我首先同意这些建议

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

}

首先,您似乎在使用string.IsNullOrEmptyvalue,但这不会检查数据为null时从数据库返回的特殊DBNull值。您应该使用更类似于value is DBNull的东西

你剩下的问题听起来很复杂,所以如果我的答案也很复杂,请不要拖延。我个人会使用自定义属性:

声明自定义属性 以下是一个框架,让你的想法。您可能希望在VisualStudio中使用“属性”代码段来了解有关如何声明这些属性的更多信息

[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”开头的字段即可。

因此我听到两个问题: -如何处理来自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个属性,最终都是一种On解决方案,其中n是字段数

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


你可能会走一些捷径,但我很难理解你在读什么和写什么,以及什么时候读什么。

大约150个表单对象,一定是很棒的用户体验,哈?哈,我同意,但不能拍摄messenger。我认为Antoni不想将所有值分配给同一个字段实体。patientUnderMdTreatment。我将进一步研究并尝试此方法out@Antoni我已经用了很多年了,这是一个很好的解决方案。
entity.patientUnderMdTreatment = IsDbNull<string>(reader["question"], null);