我是一名非开发人员,正在尝试使用 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 时引用了错误的属性。
你得到负数的原因是因为你的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
会自动为你做。