当前位置: 首页 > 面试题库 >

CONTEXT_INFO在执行Entity Framework .SaveChanges(重载)时丢失

闾丘玮
2023-03-14
问题内容

解决方案:

如您所见:在这里

  • 如果操作之前对象上下文尚未打开,则它将打开该连接。如果对象上下文在操作期间打开连接,则在操作完成后它将始终关闭连接。
  • 如果您手动打开连接,则对象上下文不会关闭它。调用“关闭”或“处置”将关闭连接。

问题在于EF将打开和关闭SetUserContext的连接,因此我将松散CONTEXT_INFO。为了保持它,我需要手动打开连接,并在SaveChanges之后关闭它

public int SaveChanges(string modifierId)
{
        Database.Connection.Open();
        SetUserContext(modifierId);
        var changes = base.SaveChanges();
        Database.Connection.Close();
        return changes;            
 }

问题 :

该系统在数据仓库上工作。数据库必须知道谁对其进行了修改,并将所有更改保存在“审核”表中。

为了达到这个结果,我主要依靠触发器和过程:

此函数 将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
request进行测试时,一切似乎都正常运行,并且所有工作正常。问题是我需要使用实体框架在WCF服务中调用它们。现在这就是麻烦开始的地方。我使用重载方法
通过实体设置了CONTEXT_INFO

 public int SaveChanges(string modifierId)
    {
        SetUserContext(modifierId);
        return base.SaveChanges();
    }

但是当base.SaveChanges(); 接到电话,我得到:

无法将值NULL插入表’dbo.Audit_Users’的列’ModifierId’中;列不允许为空。INSERT失败。该语句已终止。

提示我丢失了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;
}

问题答案:

根据文档 CONTEXT_INFO

返回使用SET CONTEXT_INFO语句为当前会话或批处理设置的context_info值。

“会话或批处理”或多或少与.NET托管连接相对应。在这里,对EF连接管理有所了解会有所帮助。

EF的默认行为是相当自由地打开和关闭数据库连接,因为.NET连接池使此连接相当有效。在您的情况下,这意味着您的初始存储过程调用与后续的EF保存操作以不同的“会话或批处理”发生。

这很容易解决:您只需要对数据库连接进行显式控制。您可以通过为上下文对象提供一个向基DbContext类提供打开连接的构造函数重载,或者通过在存储过程调用之前手动打开该连接来实现此目的。

这个可以吗?

[您能建议一个更漂亮的方法吗?

使用EntityFramework的全部目的是避免必须管理SQL连接。我觉得某处有问题。

将EF代码从底层实现中抽象出来通常是不现实的。我不确定这是否特别理想。通常,使用工作层的存储库/单元可以更好地实现这种抽象。

恕我直言,EF的“重点”是避免在数据库的原始数据和该数据的.NET对象表示之间进行大量的样板代码转换。

(不过,有趣的是,EF 7可能会更容易保持ORM抽象的“纯净”,甚至提供适用于自动化测试的内存提供程序。)



 类似资料:
  • 我试图用TheNewBoston的教程制作一个蛇游戏,因为我是一名中学生,在Python方面没有太多经验。代码是: 但是,当我执行、播放、丢失并按C重试时,会出现此错误。当我想退出时,Q可以正常工作,但C只是退出,并打印此错误: C:\Python34\python。exe“C:/Users/Ded/PycharmProjects/PyGame/PyGame Tutorial.py”回溯(上次调用

  • 问题内容: 我只是想知道如何显示指示异步请求正在运行的图像。我使用以下代码执行异步请求: 有任何想法吗? 问题答案: 当然,您可以在发出请求之前显示它,并在请求完成后隐藏它: 我通常更喜欢将其绑定到全局ajaxStart和ajaxStop事件的更通用的解决方案,这样它就可以显示在所有ajax事件中:

  • 我已经建立了一个AWS帐户,并正在尝试将我的第一个编程输入到S3中。我用控制台创建了一个桶,并把东西放在那里。我还创建了一个子目录(myFolder)并将其公开。我创建了我的。aws/credentials文件,并尝试使用示例代码,但出现以下错误: 在上执行“PutObject”时出错https://s3.amazonaws.com/gps-photo.org/mykey.txt“AWS HTTP

  • 我有一个扩展Person类的学生类。我的超级类中没有equals方法,只有我的子类中的两个,如图所示。我正在尝试理解我的第二、第三和第四个print语句的运行时行为。语句1调用了接受学生参数的equals方法,这是有意义的,因为要比较的两个对象都是声明类型的学生。但是,语句2调用了接受人参数的equals方法,而最后两个语句调用了Object类中的equals方法。有人能解释一下为什么Java是动

  • 我正在尝试使用Typescript重载一个方法。Java或C#中通常的重载方式似乎不适用于Typescript。我不能这样做: 我四处搜索,发现我必须这样做: 对我来说,这个方法似乎很不整洁,很难维护,因为我把所有东西都乱七八糟地放在一个方法中,并使用if/ther语句来划分逻辑。 有没有更好的方法可以在Typescript中进行方法重载?

  • 我有2个jsp页面。在第一个jsp页面中,我使用选择主题的组合框,几个单选按钮用于操作。在这个页面上,我收到了请求。getParameter(“subjectID”)。 最好显示servlet和jsp 在这个页面中,我从组合框中选择主题。然后选择“添加测试”。在我进入servlet之后 在那里,我可以根据请求获得主题的值。getParameter(“主题”) near-转到下一个jsp 在jsp中