【问题标题】:Replication Custom resolver changes empty strings to NULLs复制自定义解析器将空字符串更改为 NULL
【发布时间】:2009-10-02 12:18:36
【问题描述】:

我们有一个 C# 应用程序,它发布到一个数据库,该数据库被复制到另一个数据库(使用合并复制),并且有一个自定义解析器,它是一个存储过程。

这在 SQL Server 2000 下运行良好,但在 SQL Server 2005 下测试时,自定义解析器试图将任何空的 varchar 列更改为空值(失败,因为该特定列不允许空值)。

请注意,这些 varchar 字段不是导致冲突的字段,因为它们在两个数据库上都是空的并且没有被更改并且存储过程不会更改它们(它所做的只是尝试设置另一个的值钱栏)。

有没有人遇到过这个问题,或者有一个存储过程的例子,它会留下空字符串?

实际的存储过程相当简单,并在发生冲突时重新计算客户余额。

ALTER procedure [dbo].[ReCalculateCustomerBalance]
    @tableowner sysname,
    @tablename sysname,
    @rowguid varchar(36),
    @subscriber sysname,
    @subscriber_db sysname,
    @log_conflict INT OUTPUT,
    @conflict_message nvarchar(512) OUTPUT
AS
    set nocount on
DECLARE
    @CustomerID  bigint,
    @SysBalance money,
    @CurBalance money,
    @SQL_TEXT nvarchar(2000)

    Select @CustomerID = customer.id from customer where rowguid=  @rowguid

    Select @SysBalance = Sum(SystemTotal), @CurBalance = Sum(CurrencyTotal)  From CustomerTransaction Where CustomerTransaction.CustomerID = @CustomerID

    Update Customer Set SystemBalance = IsNull(@SysBalance, 0), CurrencyBalance = IsNull(@CurBalance, 0) Where id = @CustomerID

    Select * From Customer Where rowguid= @rowguid

    Select @log_conflict =0
    Select @conflict_message ='successful'
    Return(0)

【问题讨论】:

  • 你能发布你的存储过程的问题部分吗?这听起来并不熟悉,但如果我们看到您的存储过程,可能会突出显示 2000 或 2005 的问题。
  • 我已经包含了整个存储过程,因为它相当短。但是,如果我删除前两个选择并将更新替换为类似的内容,则会发生相同的错误 - Update Customer Set SystemBalance=0 where rowguid= @rowguid
  • 抛出的错误究竟是什么?是 SQL 错误,还是在 C# 中的某个地方?什么是“问题”领域?除了通过 Select * 语句之外,我没有看到任何可以通过任何方式返回空值的情况。我能想到的唯一方法是,如果记录不存在。您能否尝试命名选择中的列,或者让您在哪里 id=@customerId?
  • “错误消息”是在存储过程作为复制过程的一部分运行之后出现的,例如,无法将值 NULL 插入“PostCode”列。问题列是任何包含空字符串的 varchar 类型。全部替换为空值。如果我将表定义更改为允许空值,则复制将继续进行而不会出错,但会将数据更改为不正确的空值。记录必须存在(否则不会发生冲突),如果没有冲突(即仅在一侧发生更改),复制也可以正常工作
  • 我看不出错误来自哪里。邮政编码?不在此 SP...

标签: sql-server-2005 merge-replication resolver


【解决方案1】:

这里有几个选项,根据我的研究似乎表明 SQL Server 存在问题,每个选项都是一种解决方法。

1- 更改此语句:Select * From Customer Where rowguid= @rowguid 以明确提及每一列,并对违规字段使用“isNull”

2- 更改表中的列以添加“”的默认约束。这会做什么,如果你尝试插入一个'null',它会用空字符串替换它

3- 添加一个“插入前”触发器,该触发器将在插入之前更改数据,不再包含“空”

PS:您确定复制系统将该列标记为“必需”吗?我认为如果不需要,如果不存在数据,它将插入'null'。

【讨论】:

  • 感谢您的建议。我可能需要一段时间才能完成所有工作。我尝试了 2 的变体,我实际上将默认约束设置为字母 a(以便更容易看到它何时被应用)。在这种情况下,空字符串仍被替换为 null。我不确定我是否理解所需列的含义。它肯定包含在复制中。如果这不是您的意思,我该如何检查“必需”状态?
  • 我不确定,我在搜索 SQL 复制时注意到了它。显然,有一些设置可以让你说出是否需要。
  • 建议 1 没有任何区别。在执行存储过程的阶段,任何地方都没有空值。 3号似乎更有希望。尽管这是 Microsoft Sql,但(据我所知)没有“插入前”之类的东西。我将不得不阅读更多关于“代替”触发器(我以前没有使用过)的内容。但是暂时允许空值并添加更新后触发器确实允许我将空字符串放回原处。这是否有效取决于是否有任何列允许空值但将它们视为与空字符串不同的含义。
  • 我尝试创建一个“代替”触发器,一切似乎都运行正常,只是为了在我删除触发器时确认它,复制错误开始重新发生。有一个适当的修复会很好,但至少这是一种解决方法,所以非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2018-03-31
  • 1970-01-01
  • 1970-01-01
  • 2019-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多