首先,我是编程新手(特别是使用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次以上,则不必添加此项。必须有办法更有效地做到这一点。
答案 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)
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是字段数。
我仍然有点不确定为什么你需要读回数据。如果您需要在表单重新加载时保留用户的输入(由于验证错误?),从请求中重新加载它们会不会更容易/更好? entity
和selectedForm
也是同一个对象类型?我假设它不是db实体(否则为什么要使用reader?)。
你可能会采取一些捷径,但我很难跟踪你的阅读和写作时间以及时间。
答案 3 :(得分:-1)
我建议使用NullableDataReader。它消除了这个问题。