【问题标题】:Best Practices for updating multiple check boxes on a web form to a database将 Web 表单上的多个复选框更新到数据库的最佳实践
【发布时间】:2009-12-20 20:58:41
【问题描述】:

一个示例案例场景 - 我有一个带有一个问题和多个答案的表单作为复选框,因此您可以选择多个。答案存储表如下:

QuestionAnswers
(
  UserID int,
  QuestionID int,
  AnswerID int
)

使用存储过程将这些答案更新到数据库的最佳方法是什么?在不同的工作中,我看到了所有范围,从简单地删除所有以前的答案和插入新的答案,到传递要删除的答案列表和要添加到存储过程的答案列表。

在我目前的项目中,性能和可扩展性非常重要,所以我想知道最好的方法是什么?

谢谢! 安德烈

【问题讨论】:

    标签: asp.net sql-server webforms crud


    【解决方案1】:

    如果我可以选择表格设计,并且以下陈述是正确的:

    • 您知道每个问题的最大选择数/
    • 每个选项都是简单的选中/未选中。
    • 每个答案都被分类为正确/错误,而不是用某种等级标记。 (大概 70% 是对的。)

    然后考虑性能,我会考虑下表而不是您提供的表:

    QuestionAnswers
    (
      UserID int,
      QuestionID int,
      Choice1 bool,
      Choice2 bool,
      ...
      ChoiceMax bool
    )
    

    是的,就规范化而言,它很丑陋,但非规范化会提高性能并简化查询——一个问题只需更新/插入一次。 (并且我会先更新并仅在受影响的行等于零时插入。)

    同时检测答案是否正确也会更加简单——使用下表:

    QuestionCorrectAnswers
    (
      QuestionID int,
      Choice1 bool,
      Choice2 bool,
      ...
      ChoiceMax bool
    )
    

    您只需在QuestionCorrectAnswers 中查找与用户回答的选项组合相同的行。

    【讨论】:

      【解决方案2】:

      如果问题始终相同,那么您永远不会删除任何内容 - 只需对所有更改的答案运行更新查询即可。

      Update QuestionAnswers
      SET AnswerID = @AnswerID
      WHERE UserID = @UserID AND QuestionID = @QuestionID
      

      如果由于某种原因您仍需要执行一些删除/插入操作 - 我会检查哪些 QuestionID 已经存在(对于给定的 UserID),因此您至少需要执行删除/插入操作。

      更新比删除快得多然后插入,而且您不会使任何标识列飙升。

      我假设您在进入页面时从数据库加载 QuestionAnswers,因此用户可以查看他/她上次给出的答案 - 如果您已经在内存中拥有必要的数据,以确定要删除、插入和更新。

      【讨论】:

        【解决方案3】:

        Andrey:如果用户 (userid=1) 为问题 1(questionid=1) 选择 a(answerid=1) & b(answerid=2) 选项,然后切换到 c (a-id=3) & d (a-id=4),您必须检查,然后删除旧的并添加新的。如果您选择采用另一种方法,您将不会检查特定记录是否存在(以便您可以更新它),您只需删除旧记录并插入新记录。无论如何,由于您没有存储任何身份列,我会采用后一种方法。

        【讨论】:

          【解决方案4】:

          这是一个简单的解决方案: 每个 [Answer] 都应具有整数值(位),并且该值对于当前问题是唯一的。 例如,您有 Question1 和四个预定义的答案:

          [答案] [位值]

          answer1 0x00001

          answer2 0x00002

          answer3 0x00004

          answer4 0x00008 ...

          因此,您的 SQL INSERT/UPDATE 将是:

          declare @checkedMask int
          set @checkedMask = 0x00009 -- answer 1 and answer 4 are checked
          declare @questionId int
          set @questionId = 1
          

          --删除

          delete
          --select r.* 
          r 
          from QuestionResult r 
              inner join QuestionAnswer a  
                  on r.QuestionId = a.QuestionId and r.AnswerId = a.AnswerId
          where r.QuestionId = @questionId
           and (a.mask & @checkedMask) = 0
          

          --插入

          insert QuestionResult (AnswerId, QuestionId)
              select
                  AnswerId,
                  QuestionId
              from QuestionAnswer a
                 where a.QuestionId = @questionId
                   and (a.mask & @checkedMask) > 0
                   and not exists(select AnswerId from QuestionResult r 
                          where r.QuestionId = @questionId and r.AnswerId = a.AnswerId)
          

          【讨论】:

            【解决方案5】:

            抱歉恢复旧线程。我原以为唯一现实的解决方案是删除该问题的所有回复,并在选中复选框的位置创建新行。就更新而言,每个答案都有一列可能是有效的,但这种方法的不灵活性并不是一种选择。您需要能够为问题添加选项,而无需重新设计数据库。

            只需删除并重新插入。这就是数据库的设计目的,存储和检索大量数据行。

            【讨论】:

              【解决方案6】:

              我不同意摄政王的答案是非规范化的。只要每个答案不依赖于另一列,并且仅依赖于键,它就处于第三范式。它与包含以下客户名称字段的表没有什么不同:

              CustomerName
              (
                  name_prefix
                  name_first
                  name_mi
                  name_last
                  name_suffix
                  city
                  state
                  zip
              )
              

              QuestionAnswers
              (
                 Q1answer1
                 Q1answer2
                 Q1answerN
              )
              

              名称的“问题”和可能填写或未填写的多项答案与表格的“问题”和可能选择或未选择的多项答案之间确实没有区别。

              【讨论】:

                猜你喜欢
                • 2014-10-13
                • 2010-10-20
                • 2010-10-11
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-09-22
                • 1970-01-01
                相关资源
                最近更新 更多