检索插入的行计算数据。 SQL Server、.NET 表适配器,而不是插入

问题描述 投票:0回答:1

我是一名非开发人员,正在尝试使用 SQL Server 和 .NET 框架构建一些自定义业务软件。我在服务器中有一些表格,这些表格可以自我监控,以确保使用插入标题而不是插入标题来遵循数据规则。该过程检查是否存在任何冲突以及用户是否有权进行特定更改,然后插入行或拒绝事务。

好吧,我只是从 .net 方面开始,尝试插入数据,一切都很好,除了当我查看插入的行时,我的 ID,即身份、bigint、真零(-9123... ) 不反映插入的 ID,而是显示 -1、-2、-3... 等等

instead of insert 操作是否会阻止 SQL Server 返回更新的行?我在这里迷路了。我有大约 20 张这样的桌子,而且完成时间有限。任何帮助将不胜感激。

SQL Server 中的表公司

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Companies]
(
    [ID] [bigint] IDENTITY(-9223372036854775808,1) NOT NULL,
    [Name] [nvarchar](200) NULL,
    [MainPhone] [nvarchar](200) NULL,
    [AltPhone] [nvarchar](200) NULL,
    [BillingAddress] [nvarchar](500) NULL,
    [ShippingAddress] [nvarchar](500) NULL,
    [ModifiedBy] [bigint] NULL,
    [LastModified] [datetime2](7) NULL,

    CONSTRAINT [PK_Companies] 
        PRIMARY KEY CLUSTERED ([ID] ASC)
                WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                      IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                      ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Companies] 
    ADD CONSTRAINT [DF_Companies_CompanyName]  
        DEFAULT (N'Not provided') FOR [Name]
GO

ALTER TABLE [dbo].[Companies] 
    ADD CONSTRAINT [DF_Companies_MainPhone]  
        DEFAULT (N'Not provided') FOR [MainPhone]
GO

ALTER TABLE [dbo].[Companies] 
    ADD CONSTRAINT [DF_Companies_AltPhone]  
        DEFAULT (N'Not provided') FOR [AltPhone]
GO

ALTER TABLE [dbo].[Companies] 
    ADD CONSTRAINT [DF_Companies_BillingAddress]  
        DEFAULT (N'Not provided') FOR [BillingAddress]
GO

ALTER TABLE [dbo].[Companies] 
    ADD CONSTRAINT [DF_Companies_ShippingAddress]  
        DEFAULT (N'Not provided') FOR [ShippingAddress]
GO

ALTER TABLE [dbo].[Companies] 
    ADD CONSTRAINT [DF_Companies_Editor]  
        DEFAULT ((0)) FOR [ModifiedBy]
GO

而不是在

Companies
表 SQL Server 上插入触发器:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER TRIGGER [dbo].[Trig_Company_BeforeInsert]
ON [dbo].[Companies]
INSTEAD OF INSERT
AS 
BEGIN
    SET NOCOUNT ON;

    --Check for duplicates entries in the rows being inserted
    DECLARE @int1 int;

    SELECT @int1 = COUNT(*) 
                   FROM 
                       (SELECT inserted.Name, COUNT(*) AS Duplicates 
                        FROM inserted 
                        GROUP BY Name 
                        HAVING COUNT(*) > 1) AS sq;

    IF (@int1 > 0)
    BEGIN;
        THROW 51000, 'Duplicate entries detected in rows to be inserted. Transaction was canceled.', 10;
        ROLLBACK
    END;

    -- Make sure the new records don't already exist.
    SELECT @int1 = COUNT(*) 
    FROM
        (SELECT * 
         FROM Companies 
         WHERE Name IN (SELECT Name FROM inserted)) AS sq;

    IF (@int1 > 0)
    BEGIN;
        THROW 51000, 'One or more of the new entries already exist. Transaction was canceled', 10;
        ROLLBACK
    END;

    --Check if the current user exists.
    IF (dbo.USER_CurrentUserIsRegistered() = 0)
    BEGIN;
        THROW 51000, 'Current user not registered. Transaction canceled.', 10;
        ROLLBACK
    END;

    --Check if the current user is allowed to Make new companies
    DECLARE @userid bigint
    SET @userid = dbo.USER_GetCurrent()

    DECLARE @canedit bit

    SELECT @canedit = Users.EditCompanies 
    FROM Users 
    WHERE ID = @userid

    IF @canedit = 0
    BEGIN;
        THROW 51000, 'Current user does not have permission.', 10;
        ROLLBACK
    END;

    --if it passed all the checks then go ahead and record it - being sure to mark the current moment in time and user.
    INSERT INTO Companies (AltPhone, BillingAddress, LastModified, MainPhone, ModifiedBy, [Name], ShippingAddress)
        SELECT 
            AltPhone, BillingAddress, GETDATE(), MainPhone, @userid, [Name], ShippingAddress 
        FROM
            inserted;
END

用于跟踪导入数据中新旧 ID 的类:

Private Class ComboEntry
    Property OldID As Integer
    Property NewEntry As Object

    Sub New()

    End Sub

    Sub New(_Oldid As Integer, _NewEntry As Object)
        OldID = _Oldid
        NewEntry = _NewEntry
    End Sub
End Class

'comboentry objects for keeping track of old ID and new rows'
Dim ClientComboEntries As New List(Of ComboEntry)

'adapters'
Dim ADP_Companies As New JBADevDataSetTableAdapters.CompaniesTableAdapter
Dim TBL_Companies As New JBADevDataSet.CompaniesDataTable

我当前的进口代码。暂停执行并探索表中行的状态显示 -1 ID'

Private Sub ImportClients()
    'setup connection with old database table'
    Dim oldClientAdp As New MTGJobBook2DataSetTableAdapters.EPI_ClientsTableAdapter
    Dim OldClienttble As MTGJobBook2DataSet.EPI_ClientsDataTable = oldClientAdp.GetData()

    Console.WriteLine("")
    Console.WriteLine("Starting import")
    Console.WriteLine(OldClienttble.Count.ToString & " Clients to be added.")

    'initially fill the insert table'
    ADP_Companies.Fill(tbl_Companies)

    Dim Row_Companies As JBADevDataSet.CompaniesRow

    'loop through each old company row and insert'
    For Each r As MTGJobBook2DataSet.EPI_ClientsRow In OldClienttble.Rows
        'Add a new row to the companies table for insert'
        Row_Companies = tbl_Companies.NewCompaniesRow()


        With Row_Companies
            If r.IsPhoneNumber_AltNull Then
                .AltPhone = "PhoneNotProvided"
            Else
                .AltPhone = r.PhoneNumber_Alt
            End If
            If r.IsAddress_BillingNull Then
                .BillingAddress = "Billing address not provided"
            Else
                .BillingAddress = r.Address_Billing
            End If
            If r.IsPhoneNumber_MainNull Then
                .MainPhone = "Main Phone not provided"
            Else
                .MainPhone = r.PhoneNumber_Main
            End If
            If r.IsNameNull Then
                .Name = "Client ID " & r.ClientID.ToString
            Else
                .Name = r.Name
            End If
            If r.IsAddress_ShippingNull Then
                .ShippingAddress = "Shipping Address not provided"
            Else
                .ShippingAddress = r.Address_Shipping
            End If
        End With

        'add the row to the update table'
        tbl_Companies.AddCompaniesRow(Row_Companies)
        'Have to get the row from the table after insert in order' to retain reference to tbl_companies row object
        ClientComboEntries.Add(New ComboEntry(r.ClientID, tbl_Companies.Rows(tbl_Companies.Rows.Count - 1)))
    Next
    Dim insertedcnt As Integer
    Try
        insertedcnt = ADP_Companies.Update(tbl_Companies)
    Catch ex As Exception
        MessageBox.Show(ex.Message)
    End Try
    Console.WriteLine(insertedcnt.ToString & " rows inserted")
    If Not TBL_Companies.HasErrors Then
        MessageBox.Show("success")
        'add notes for each entry'
        'add contacts'
    Else
        Console.WriteLine("Client insert failed.")
    End If

此外,就像我说的,我不是开发人员,因此也欢迎对我在这里所做的事情提出建设性的批评。

提前感谢您的宝贵时间。

我尝试通过在线搜索找到答案,但大多数情况下,遇到此问题的人似乎在使用存储过程或在查找 ID 时引用了错误的属性。

sql .net visual-studio triggers tableadapter
1个回答
0
投票

你得到负数的原因是因为你的ID被定义为

    [ID] [bigint] IDENTITY(-9223372036854775808,1) NOT NULL,

所以它从那个数字开始。你可能想要这个

    [ID] [bigint] IDENTITY(1,1) NOT NULL,

我不确定你为什么要使用

INSTEAD OF
触发器,但这完全没有必要。
INSTEAD OF
触发器有很多有问题的副作用,你应该尽可能避免它们。

如果你想在

Name
上强制执行唯一性,只需使用适当的
UNIQUE
约束。

ALTER TABLE Companies
ADD CONSTRAINT uq_Name UNIQUE (Name);

为了加强用户权限,SQL Server 为每个用户和角色提供了一个复杂的数据库、模式、表和列级权限系统。你应该改用它。

现在,要返回插入数据的结果,不要使用

select top (1)
,因为它不可靠。而是使用
OUTPUT
。比如你有一个
IDENTITY
列,你可以这样取回来

INSERT YourTable (SomeColumn1, SomeColumn2)
OUTPUT inserted.IdColumn
VALUES (SomeVal1, SomeVal2);

如果你真的真的想要使用触发器来强制执行权限,我会建议一个

AFTER
触发器。

CREATE OR ALTER TRIGGER [dbo].[Trig_Company_BeforeInsert]
ON [dbo].[Companies]
AFTER INSERT
AS 
BEGIN
    SET NOCOUNT ON;

    --Check if the current user exists.
    IF (dbo.USER_CurrentUserIsRegistered() = 0)
    BEGIN;
        THROW 51000, 'Current user not registered. Transaction canceled.', 10;
    END;

    --Check if the current user is allowed to Make new companies
    DECLARE @userid bigint
    SET @userid = dbo.USER_GetCurrent()

    IF (
        SELECT u.EditCompanies 
        FROM Users u
        WHERE u.ID = @userid)
    BEGIN;
        THROW 51000, 'Current user does not have permission.', 10;
    END;
END

ROLLBACK
是不必要的,因为
THROW
会自动为你做。

© www.soinside.com 2019 - 2024. All rights reserved.