我想使用实体框架(而不是ADO.NET)访问我的数据库,但是我有两个问题:
我在数据库中的所有表都具有TraceVersion(int)和UTimestamp(datetime)字段。我有一个AFTER UPDATE触发器,该触发器将TraceVersion递增1并将UTimestamp设置为当前日期和时间。不幸的是,DbContext.SaveChanges不会检索由触发器更新的字段,因此我的实体与数据库的值不同。有没有一种方法可以指示DbContext.SaveChanges保存到数据库后检索字段TraceVersion和UTimestamp?
我在数据库中的所有表都具有“已删除(位)”字段。如果字段Deleted = 1,则AFTER UPDATE触发器将删除记录,并将该记录插入审核表中。
对于这两个问题,以下是带有触发器的表的示例:
CREATE TABLE [dbo].[CUsers](
[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[NTUser] [varchar](50) NULL,
[FName] [varchar](20) NULL,
[LName] [varchar](50) NULL,
[Active] [bit] NULL,
[Deleted] [bit] NOT NULL,
[TraceVersion] [int] NOT NULL,
[UTimeStamp] [datetime] NOT NULL,
CONSTRAINT [IX_CUsers] UNIQUE NONCLUSTERED ([NTUser] ASC) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[CUsers_Audit](
[Id] [int] NOT NULL,
[NTUser] [varchar](50) NULL,
[FName] [varchar](20) NULL,
[LName] [varchar](50) NULL,
[Active] [bit] NULL,
[Deleted] [bit] NOT NULL,
[TraceVersion] [int] NOT NULL,
[UTimeStamp] [datetime] NOT NULL,
CONSTRAINT [PK_CUsers_Audit] PRIMARY KEY CLUSTERED ([Id] ASC, [TraceVersion] ASC) ON [PRIMARY]) ON [PRIMARY]
GO
---------- AUDIT TRIGGER SCRIPT FOR TABLE CUsers---------------
CREATE TRIGGER [dbo].[trCUsers_AUDIT_UD] ON [dbo].[CUsers]
AFTER UPDATE, DELETE
AS
/* If no rows were affected, do nothing */
IF @@ROWCOUNT=0
RETURN
SET NOCOUNT ON
BEGIN TRY
DECLARE @Counter INT, @Now DATETIME
SET @Now = GETDATE()
/* Check the action (UPDATE or DELETE) */
SELECT @Counter = COUNT(*)
FROM INSERTED
IF @Counter = 0 --> DELETE
THROW 50000, 'DELETE action is prohibited for CUsers', 1
/* Insert previous record to Audit */
INSERT INTO CUsers_Audit([Id],[NTUser],[FName],[LName],[Active],[Deleted],[TraceVersion],[UTimeStamp])
SELECT d.[Id],d.[NTUser],d.[FName],d.[LName],d.[Active],d.[Deleted],d.[TraceVersion],d.[UTimeStamp]
FROM DELETED d
/* Update master record TraceVersion, UTimeStamp */
UPDATE main
SET main.TraceVersion = d.TraceVersion + 1, main.UTimeStamp = @Now
FROM CUsers main
INNER JOIN DELETED d ON d.Id = main.Id
INNER JOIN INSERTED i ON i.Id = main.Id
/* Process deleted rows */
IF NOT EXISTS(SELECT 1 FROM INSERTED WHERE Deleted = 1)
RETURN
/* Re-insert last updated master record into Audit table where Deleted = 1 */
INSERT INTO CUsers_Audit([Id],[NTUser],[FName],[LName],[Active],[Deleted],[TraceVersion],[UTimeStamp])
SELECT d.[Id],d.[NTUser],d.[FName],d.[LName],d.[Active],d.[Deleted],d.[TraceVersion],d.[UTimeStamp]
FROM CUsers d
INNER JOIN INSERTED i ON d.Id = i.Id
WHERE i.Deleted = 1
/* Delete master record */
DELETE c
FROM CUsers c
INNER JOIN INSERTED i ON c.Id = i.Id
WHERE i.Deleted = 1
END TRY
BEGIN CATCH
THROW
END CATCH
GO
ALTER TABLE [dbo].[CUsers] ENABLE TRIGGER [trCUsers_AUDIT_UD]
GO
对于第一个问题,我知道我可以覆盖SaveChanges并按照以下代码进行重新加载:
public override int SaveChanges()
{
var entriesModified =
ChangeTracker.Entries().Where(
e => e.State == EntityState.Modified).ToList();
int rowCount = base.SaveChanges();
if (rowCount > 0)
{
entriesModified.ForEach(e=>e.Reload());
return rowCount;
}
但是这将重新加载整个记录,这很耗时。我只想重新加载TraceVersion和UTimeStamp。此外,此重新加载发生在base.SaveChanges事务之外,因此TraceVersion和UTimeStamp可能在两者之间发生了更改。
我希望SaveChanges进行更新,但是还要在同一事务中发出以下SQL语句:
SELECT TraceVersion, UTimeStamp FROM CUsers WHERE Id=@Id
这可能吗?