实体框架执行时,CONTEXT_INFO丢失。SaveChanges(overload)解决方案:你可以发现:这里的问题是EF会打开和关闭SetUserContext连接,所以我会松开CONTEXT_INFO。为了保留它,我需要手动打开连接并在SaveChanges之后关闭它publicintSaveChanges(stringmodifierId){Database.Connection.Open();SetUserContext(modifierId);varchanges=base.SaveChanges();数据库.Connection.Close();返回更改;问题:这个系统适用于数据仓库。数据库必须知道谁修改了它并将任何更改保存在审计表中。为了达到这个结果,我主要依靠触发器和过程:这个函数将userId保存在CONTEXT_INFO中:CREATEPROCEDURE[dbo].[SetUserContext]@userIdNVARCHAR(64)ASBEGINSETNOCOUNTON;DECLARE@contextVARBINARY(128)SET@context=CONVERT(VARBINARY(128),@userId)SETCONTEXT_INFO@contextEND这可以在任何地方使用来获取userId:CREATEFUNCTION[dbo].[GetUserContext]()RETURNSNVARCHAR(64)ASBEGINRETURNCONVERT(NVARCHAR(64),CONTEXT_INFO())END例如,在我的触发器中我有:CREATETRIGGERUpdateUserON[dbo].[Users]FORUPDATEASBEGININSERTINTO[Audit_Users]SELECT*,dbo.GetUserContext(),GETUTCDATE(),0FROMinsertedENDGOCREATETABLE[dbo].[Users]([Id]NVARCHAR(64)NOTNULL,[FirstName]NVARCHAR(255)NOTNULL,[LastName]NVARCHAR(255)NOTNULL,[BirthDate]DATENOTNULL,[Type]INTNOTNULL,[Status]INTNOTNULL,[CreatorId]NVARCHAR(64)NOTNULL,PRIMARYKEYCLUSTERED([Id]ASC),CONSTRAINT[FK_Users_ToStatus]外键([Status])REFERENCES[dbo].[StatusUsers]([Id]),CONSTRAINT[FK_Users_ToCreator]FOREIGNKEY([CreatorId])REFERENCES[dbo].[Users]([Id]),CONSTRAINT[FK_Users_ToType]FOREIGNKEY([Type])REFERENCES[dbo].[TypeUsers]([Id]));TABLE[dbo].[Audit_Users]([Id]INTIDENTITY(1,1)NOTNULL,[UserId]NVARCHAR(64)NOTNULL,[FirstName]NVARCHAR(255)NOTNULL,[LastName]NVARCHAR(255)NOTNULL,[BirthDate]DATENOTNULL,[Type]INTNOTNULL,[Status]INTNOTNULL,[CreatorId]NVARCHAR(64)NOTNULL,[ModifierId]NVARCHAR(64)NOTNULL,[Date]DATETIMENOTNULL,[已删除]INTNOTNULL,PRIMARYKEYCLUSTERED([Id]ASC));当我使用sql请求进行测试并且一切正常时,一切似乎都工作正常问题是我需要使用实体框架在我的WCF服务中调用它们。现在这就是麻烦的开始。我使用重载方法通过实体设置CONTEXT_INFO:publicintSaveChanges(stringmodifierId){SetUserContext(modifierId);返回base.SaveChanges();但是当base.SaveChanges();被调用,我得到:无法插入值NULL列'ModifierId',表'dbo.Audit_Users';列不允许空值。插入失败。该语句已终止。这表明我缺少CONTEXT_INFO。我调试了(添加表并修改setContext过程并使用正确的值调用该过程)。感谢您的帮助,我不是数据库专家,它可能很简单,但我被困在这里..根据要求:publicpartialclassEntities:DbContext{publicEntities():base("name=Entities"){}protectedoverridevoidOnModelCreating(DbModelBuildermodelBuilder){thrownewUnintentionalCodeFirstException();}publicvirtualDbSetAddresses{get;放;}publicvirtualDbSetContacts{get;放;}publicvirtualDbSetEmails{get;放;}公共虚拟获取;文件{设置;}公共虚拟DbSetStatusUsers{get;放;}publicvirtualDbSetTypeCommons{get;放;}publicvirtualDbSetTypeFiles{get;放;}publicvirtualDbSetTypeUsers{get;放;}publicvirtualDbSetUsers{get;放;}publicvirtualDbSetWorkflows{get;放;}publicvirtualintSetUserContext(stringuserId){varuserIdParameter=userId!=null?newObjectParameter("userId",userId):newObjectParameter("userId",typeof(string));返回((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("SetUserContext",user标识参数);}}创建用户:publicUserDtoCreate(stringid,stringfirstName,stringlastName,DateTimebirthdaydate,stringtype,stringmodifierId){varuserToReturn=newUserDto{Id=id,FirstName=firstName,LastName=lastName,Birthday=birthdate,CreatorId=modifierId,Status="Created",Type=type};使用(vardb=ContextFactory.GetEntities()){varuser=Mapper.地图(用户返回);using(vartransaction=newTransactionScope())//这将创建一个新事务{db.Users.Add(user);db.SetUserContext(modifierId);如果(db.SaveChanges()==1){userToReturn=Mapper.Map(user);userToReturn.Type=类型;userToReturn.Status="已创建";交易完成();}}}返回userToReturn;根据文档CONTEXT_INFO,使用SETCONTEXT_INFO语句为当前会话或批处理设置的context_info值“sessionorbatch”或多或少对应于.NETManagedConnections。这是理解EF连接管理有点帮助的地方。默认的EF行为是非常安全地打开和关闭数据库连接,因为.NET连接池使这非常有效。在您的情况下,这意味着您的初始存储过程调用发生在与后续EF保存操作不同的“会话或批处理”中。修复这很容易修复:您只需要显式控制数据库连接。您可以通过为上下文对象提供构造函数重载来提供到DbContext基类的打开连接,或者在调用存储过程之前手动打开连接。这个可以吗?[你能]建议一个更漂亮的方法吗?使用EntityFramework的全部意义在于避免必须管理SQL连接。我觉得有些不对劲。从底层实现中抽象出EF代码通常是不切实际的。我不确定它是否特别令人满意。对于工作层的存储库/单元,这种抽象通常更好。恕我直言,EF的“要点”是避免在数据库的原始数据和该数据的.NET对象表示之间进行大量样板代码转换。(不过,有趣的是,EF7可能更容易使ORM抽象“更纯粹”,甚至提供适合在自动化测试中使用的内存中提供程序。)Context_Info()为null的原因是因为存储过程在以下情况下被调用你打电话给他们后立即执行。在执行dataContext.SaveChanges()时不会调用它们。您所做的是在与dataContext.SaveChanges()相同的事务中调用存储过程。为此,您的代码应如下所示。publicpartialclassMyDbContext:DbContext{//...publicvirtualintSetUserContext(stringmodifierId){return((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("SetUserContext",modifierId);}}publicclassUserService{privateMyDbContextm_dataContext;publicUserService(MyDbContextdataContext){m_dataContext=dataContext;{publicUserCreateUser(stringfirstName,stringlastName,DateTimebirthDate,intmodifiedId)//在此处列出其他参数{using(vartransaction=newTransactionScope())//这将创建一个新事务{m_dataContext.Users.Add(newUser(){//...});//而不是将修改后的id传递到保存更改中,您可以在这里调用您的存储过程m_dataContext.SetUserContext(modifiedId);//然后调用常规保存更改m_dataContext.SaveChanges();交易完成();//这会提交事务}}}请注意,此处呈现的最终解决方案的体系结构目前并不是那么好。我建议实施存储库模式,而不是让服务访问数据上下文。以上是C#学习教程:实体框架执行时,CONTEXT_INFO丢失。SaveChanges(重载)共享所有内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多加关注——本文来自网络收集,不代表立场,如涉及侵权,请点击有权联系管理员删除。如需转载请注明出处:
