WCF数据服务/实体框架:记录客户端用户名、身份验证、授权

3
我正在使用Entity Framework与WCF数据服务,并且我在我的数据库中有以下表格:
表格合同
- Id(整数) - 名称(varchar) - byUser(varchar) - isDeleted(位)
Entity Framework类
- Id(整数) - 名称(字符串) - byUser(字符串) - isDeleted(布尔值)
每当用户通过客户端应用程序插入/更新/删除合同时,我需要记录谁进行了操作。
因此,我创建了用于插入/更新/删除的存储过程,当执行插入/删除/更新时,将从客户端接收用户名。
问题是删除操作没有发送执行操作的用户:
        var ctx = Context;
        var contractToDelete = ctx.Contracts.Where(c => c.ContractId == 1).First();
        contractToDelete.ByUser = username;
        ctx.DeleteObject(contractToDelete);
        ctx.SaveChanges();

在服务器端,byUser参数始终为空。

问题:

1)如何确保将byUser参数发送到服务器?

2)是否有更好的处理此类场景的方法?(使用Entity Framework进行日志记录/身份验证/授权)


这是一个Windows、ASP.NET还是WPF应用程序?你如何给username变量赋值? - Eranga
这是一个 WPF 应用程序。当用户登录时,他通过登录框提供用户名和密码。 - Attilah
2个回答

2

它不总是发送null。它始终发送旧值。这是实体框架中的一些内部逻辑。对于每个被跟踪的对象,EF都保留原始值和当前值。当您删除对象时,EF不使用当前值,而是使用原始值(不要问我为什么,这就是它的工作方式)。

因此,您需要欺骗EF:

var ctx = Context;
var contractToDelete = ctx.Contracts.Where(c => c.ContractId == 1).First();
contractToDelete.ByUser = username;
ctx.Contracts.ApplyOriginalValues(contractToDelete);
ctx.DeleteObject(contractToDelete);
ctx.SaveChanges();

调用ApplyOriginalValues将强制EF使用参数中的值覆盖原始值 = 您将使用当前值覆盖原始值。

在我看来,更好的方法是将删除的记录存储在单独的表中,因为这将避免许多问题,例如在每个查询中传递isDeleted=false,其中贪婪和惰性加载也会加载已删除的记录。避免isDeleted的唯一方法是使用条件映射,但在这种情况下,即使您想要加载已删除的记录,您也无法这样做,除非您使用存储过程或直接SQL查询。


谢谢,现在我明白了。我正在使用WCF数据服务,所以在ctx.Contracts中没有ApplyOriginalValues方法。还有其他的方法可以做到这一点吗? - Attilah
使用WCF数据服务是您问题中缺少的非常重要的信息。使用数据服务,它的行为可能完全不同。 - Ladislav Mrnka
哦,对不起。我现在正在更正问题。 - Attilah

1
我处理这个问题的方式是,当我的用户登录时,我将他们的基本信息存储在会话中。然后我有一个类,它位于我的操作上下文之上。
每当我提交更改时,我都会执行相同的例程来检查发生了什么变化。我开发了根据正在处理的实体触发操作的能力(因此我可以关注诸如合同之类的事情)。然后我让用户能够登录。
[编辑]
这比我意识到的要难以澄清,但我会尝试。
我正在创建一个Web应用程序。大量使用Ninject。
当用户登录时,我将他们的信息存储在IUserSession对象中(这实际上保存在Session中,但自定义的Ninject作用域对我很方便,并且防止我将数据层暴露给Web Session)。这个用户会话对象包含用户名、用户ID等。
我创建了一个包含上下文的类,并包装了所有的SELECT、CREATE、DELETE和COMMIT调用。即SELECT;
public IQueryable<TEntity> All<TEntity>( ) {
  return Context.Set<TEntity>();
}

这个类还有一个Commit方法,这是调用SaveChanges的方法。
在调用SaveChanges之前,您可以通过Context.ChangeTracker.Entities访问更改内容。
对于每个已更改的实体,您可以测试它是添加、删除还是修改。要获取正在修改的元素类型;
Type baseEntityType = ObjectContext.GetObjectType( entity.Entity.GetType( ) );

我计划很快写一篇教程,基于我个人的经验来完成(虽然现在这并不能帮助到你)。


谢谢你的回答。但是我该如何存储会话信息?还有那个坐在操作上下文之上的类怎么办?你能提供一些代码示例吗?我真的无法理解。 - Attilah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接