解决方案:
你可以找到:here
- 如果连接尚未打开,则对象上下文将打开该连接 在手术前。如果对象上下文在打开期间打开连接 一个操作,它将始终关闭操作时的连接 完成了。
- 如果手动打开连接,则为对象上下文 不会关闭它。调用Close或Dispose将关闭连接。
问题是EF会打开和关闭SetUserContext的连接,所以我会松开CONTEXT_INFO。为了保持它,我需要手动打开连接并在SaveChanges
之后关闭它public int SaveChanges(string modifierId)
{
Database.Connection.Open();
SetUserContext(modifierId);
var changes = base.SaveChanges();
Database.Connection.Close();
return changes;
}
问题:
系统在数据仓库上工作。数据库必须知道谁修改它并将任何更改保存在Audit表中。
为了达到这个结果,我主要依靠触发器和程序:
此功能将userId保存在CONTEXT_INFO中:
CREATE PROCEDURE [dbo].[SetUserContext]
@userId NVARCHAR (64)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @context VARBINARY(128)
SET @context = CONVERT(VARBINARY(128), @userId)
SET CONTEXT_INFO @context
END
这个可以在任何地方使用获取userId:
CREATE FUNCTION [dbo].[GetUserContext] ()
RETURNS NVARCHAR (64)
AS
BEGIN
RETURN CONVERT(NVARCHAR (64), CONTEXT_INFO())
END
例如,在我的触发器中,我有:
CREATE TRIGGER UpdateUser
ON [dbo].[Users]
FOR UPDATE
AS
BEGIN
INSERT INTO [Audit_Users]
SELECT * , dbo.GetUserContext() , GETUTCDATE() , 0 FROM inserted
END
GO
CREATE TABLE [dbo].[Users] (
[Id] NVARCHAR (64) NOT NULL,
[FirstName] NVARCHAR (255) NOT NULL,
[LastName] NVARCHAR (255) NOT NULL,
[BirthDate] DATE NOT NULL,
[Type] INT NOT NULL,
[Status] INT NOT NULL,
[CreatorId] NVARCHAR (64) NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_Users_ToStatus] FOREIGN KEY ([Status]) REFERENCES [dbo].[StatusUsers] ([Id]),
CONSTRAINT [FK_Users_ToCreator] FOREIGN KEY ([CreatorId]) REFERENCES [dbo].[Users] ([Id]),
CONSTRAINT [FK_Users_ToType] FOREIGN KEY ([Type]) REFERENCES [dbo].[TypeUsers] ([Id])
);
CREATE TABLE [dbo].[Audit_Users] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[UserId] NVARCHAR (64) NOT NULL,
[FirstName] NVARCHAR (255) NOT NULL,
[LastName] NVARCHAR (255) NOT NULL,
[BirthDate] DATE NOT NULL,
[Type] INT NOT NULL,
[Status] INT NOT NULL,
[CreatorId] NVARCHAR (64) NOT NULL,
[ModifierId] NVARCHAR (64) NOT NULL,
[Date] DATETIME NOT NULL,
[Deleted] INT NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
当我使用sql请求测试并且一切正常时,一切似乎工作正常。 问题是我需要使用Entity Framework在我的WCF服务中调用它们。现在这就是麻烦开始的地方。 我通过实体设置CONTEXT_INFO并使用重载方法:
public int SaveChanges(string modifierId)
{
SetUserContext(modifierId);
return base.SaveChanges();
}
但是当base.SaveChanges();获取调用,我得到:
无法将值NULL插入“ModifierId”列表中 'dbo.Audit_Users';列不允许空值。插入 失败。声明已经终止。
这表明我丢失了CONTEXT_INFO。我调试了(添加表并修改setContext过程,并使用正确的值调用过程)。
感谢您的帮助我不是数据库专家,这可能是非常简单的事情,但我被困在这里..
根据要求:
public partial class Entities : DbContext
{
public Entities()
: base("name=Entities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Address> Addresses { get; set; }
public virtual DbSet<Contact> Contacts { get; set; }
public virtual DbSet<Email> Emails { get; set; }
public virtual DbSet<File> Files { get; set; }
public virtual DbSet<StatusUser> StatusUsers { get; set; }
public virtual DbSet<TypeCommon> TypeCommons { get; set; }
public virtual DbSet<TypeFile> TypeFiles { get; set; }
public virtual DbSet<TypeUser> TypeUsers { get; set; }
public virtual DbSet<User> Users { get; set; }
public virtual DbSet<Workflow> Workflows { get; set; }
public virtual int SetUserContext(string userId)
{
var userIdParameter = userId != null ?
new ObjectParameter("userId", userId) :
new ObjectParameter("userId", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("SetUserContext", userIdParameter);
}
}
创建用户:
public UserDto Create(string id, string firstName, string lastName, DateTime birthdate, string type,
string modifierId)
{
var userToReturn = new UserDto
{
Id = id,
FirstName = firstName,
LastName = lastName,
Birthdate = birthdate,
CreatorId = modifierId,
Status = "Created",
Type = type
};
using (var db = ContextFactory.GetEntities())
{
var user = Mapper.Map<User>(userToReturn);
using (var transaction = new TransactionScope()) // this creates a new transaction
{
db.Users.Add(user);
db.SetUserContext(modifierId);
if (db.SaveChanges() == 1)
{
userToReturn = Mapper.Map<UserDto>(user);
userToReturn.Type = type;
userToReturn.Status = "Created";
transaction.Complete();
}
}
}
return userToReturn;
}