如何优雅地处理Access表单中的NOT NULL SQL Server列?

时间:2019-03-02 00:37:38

标签: sql-server vba ms-access access-vba

我有一个链接到SQL Server数据库的MS Access前端。

如果需要某些列,那么自然要做的就是在该列的定义中(在数据库级别)包括NOT NULL。但这似乎在访问方面造成了问题。当您将表单绑定到该表时,绑定到该列的字段最终变得非常不友好。如果用户从该字段中删除了文本,他们将无法离开该字段,直到他们输入内容。每次他们尝试离开该字段为空白时,都会收到此错误:

  

您试图将Null值分配给不是Variant数据类型的变量。

这是一条非常可怕的错误消息-即使对于开发人员,更不用说可怜的用户了。幸运的是,我可以将其静音或用类似以下代码的更好的消息代替它:

Private Sub Form_Error(DataErr As Integer, Response As Integer)
    If DataErr = 3162 Then
        Response = acDataErrContinue
        <check which field is blank>
        MsgBox "<some useful message>"
    End If
End Sub

但这只是部分修复。用户为什么不能离开该字段?没有像样的现代UI会像这样限制焦点(想想网站,电话应用程序,桌面程序-一切,实际上)。关于必填字段,我们如何解决Access的这种行为?

我将发布我找到的两个变通办法作为答案,但我希望有被我忽略的更好的方法。

3 个答案:

答案 0 :(得分:0)

而不是更改后端表定义或尝试通过不同步的链接表定义来“欺骗”访问,而只是将任何“ NOT NULL”列的控件从绑定更改为未绑定字段(即清除ControlSource属性并更改控件名称(例如,通过添加前缀),以避免与基础字段名称的冲突)。 / p>

此解决方案肯定不会那么“脆弱”,但是将需要您手动将绑定代码添加到许多其他Form事件中。为了提供与其他Access控件和表单一样的一致体验,我至少应实现Form_AfterInsert(), Form_AfterUpdate(), Form_BeforeInsert(), Form_BeforeUpdate(), Form_Current(), Form_Error(), Form_Undo()


P.S。尽管我不记得以前曾看到过这样的措辞不佳的错误消息,但是对于带有Required = True的Access表列,所描述的总体行为是相同的,它等同于NOT NULL列条件的Access UI。

答案 1 :(得分:0)

我建议您是否可以简单地更改sql server上的所有表以允许这些文本列为空。对于位,数字列默认为0 sql服务器端。尽管我们的行业倾向于建议避免使用null,但许多开发人员还希望避免使用null,因此他们取消了SQL Server端允许null的选择。问题是您永远也无法逃脱,并且无论如何都要避免大量的空值。简单查询一下说客户及其最近的发票编号+发票总额。但是,当然很常见的是将没有购买任何东西的客户包括进去(没有象牙的客户,或者没有子记录的不计其数的情况的客户。我发现大约80%或在典型应用程序中,我需要更多的信息是LEFT联接。这意味着没有子记录的任何父记录都将所有这些子列返回为空。您将要处理并看到要处理大量的应用程序中的空值,即使您的表设计也不允许空值,您也无法避免-您根本无法逃避那些讨厌的空值。

由于人们将在代码和任何sql查询(那些非常常见的左联接)中看到很多空值,所以到目前为止,最好的解决方案是简单地允许并设置所有文本列为允许空值。我还可以指出,如果应用程序设计者不放下脚步并做出始终选择使用null的明智选择,那么NULLS和ZLS数据的蔓延将是一个更糟糕的问题。

如果一个人没有控制权或一个人无法做出选择,那么问题就变得非常棘手和痛苦。

最终,Access根本无法与SQL Server一起使用,并且无法选择允许ZLS列。

对于向sql服务器的迁移(我已经做了10多年了),毫无疑问,在这里,所有文本列都将为null是迄今为止最简单的选择。

因此,我建议您不要尝试围绕此问题进行编码,而只需将所有sql表更改为默认值即可,并允许空列为空。

上面的结果可能需要对应用程序进行一些小的修改,但是与在SQL Server上使用ZLS列的访问支持不佳(实际上不支持)时尝试进行修复或编码相比,所需要的工作和精力要少得多。 。

我还将注意到,此建议不是一个很好的建议,但鉴于Access如何与SQL Server一起工作的局限性,它只是最好的建议。某些数据库系统(oracle)确实有一个总体设置,该设置表明每个null都将转换为ZLS,因此您不必在意以下内容:

select * from tblCustomers where (City is null) or (City is = "")

如上所示,在您的应用程序中同时允许ZLS和null的那一瞬间就是您创建了一个巨大的怪物混乱的瞬间。关于未定义null的学术辩论只是另一天的辩论。

如果使用Access + SQL Server开发,则需要采用一种标准方法-我建议该方法只是将所有文本列都设置为允许空值和日期列。对于数字和位列,将它们默认设置为0。

这可以减少痛苦和工作量。 尝试对应用程序进行一些重大修改,然后说取消绑定文本列(这可能需要大量工作)。

只需假设并设置所有文本列以允许为空。在这种情况下,它是邪恶的出租人,必须符合交给您的工具袋。

因此,我没有解决方法,但是只有采取这种方法和路线才能带来最少的工作量和痛苦。那条最痛苦的路是允许空值。当然,只有在可以做出这一选择的情况下,这一建议才会起作用。

答案 2 :(得分:-1)

我想出的两种解决方法是:

  1. 不要创建数据库列NOT NULL,而要完全依靠Access表单而不是数据库来保证数据完整性。该表的读者将负担不明确的列,实际上该列将不包含空值(只要形式验证代码正确),但由于在数据库中定义该列的方式,理论上可能包含空值。没有100%的保证会很麻烦,但实际上可能就足够了。

      

    判决:简单但草率-谨慎行事

  2. 滥用这样的事实,即Access到外部表的链接必须手动刷新。在SQL Server中创建列NULL,在Access中刷新链接,然后在SQL Server中再次创建列NOT NULL-但这次,不要刷新Access中的链接。

    其结果是Access不会意识到该字段为NOT NULL,因此将使用户独自一人。他们可以根据需要移动表格,而不会出现神秘错误3162或限制焦点。如果他们尝试在字段仍为空白的情况下保存表单,则他们将收到源自基础数据库的ODBC错误。尽管不希望这样做,但可以通过检查Form_BeforeUpdate()中的空白字段并改为向用户提供可理解的错误消息来避免这种情况。

      

    判决:不仅可以提高数据完整性,而且还带来维护上的麻烦,有点骇人听闻的/令人惊讶的和脆弱的,因为如果有人刷新表链接,则将返回可怕的错误/焦点限制-再说一次,最坏的情况不是灾难性的,因为后果仅仅是用户的烦恼,而不是数据完整性问题或应用程序崩溃