【问题标题】:How can I implement Query Interception in a LINQ to Entities query? (c#)如何在 LINQ to Entities 查询中实现查询拦截? (C#)
【发布时间】:2011-07-12 02:12:00
【问题描述】:

我正在尝试在 EF4 中实现加密列,并使用 CTP5 功能允许简单地使用 POCO 来查询数据库。对不起,这是很多话,但我希望下面的内容足以说明需求和问题!

所以,一些背景知识,以及我目前的进展:

目的是如果您在不使用我们的 DAL 的情况下查询表,那么数据就是垃圾,但我不希望开发人员担心数据是否/何时/如何加密。

为简单起见,在这个阶段,我正在假设任何字符串列都将被加密。

现在,我已经成功实现了这一点,使用 Objectmaterialized 事件返回数据,并使用 SavingChanges 事件提交数据。

所以给定以下类:

public class Thing
{

    public int ID { get; set; }
    [Required]
    public string Name { get; set; }
    public DateTime Date { get; set; }
    public string OtherString { get; set; }
}

以下查询返回所有必需的值,并且物化的 POCO 中有明确的数据。

var things = from t in myDbContext.Things
             select t;

其中 myDbContext.Things 是 DbSet<Thing>

同样,将Thing 的实例传递给Things.Add()
(在 Name 和/或 OtherString 值中包含明确的字符串数据)
然后调用myDbContext.SaveChanges() 在字符串到达​​数据存储之前对其进行加密。

现在,我遇到的问题出在这个查询中:

var things = from t in myDbContext.Things
             where t.Name == "Hairbrush"
             select t;

这会导致将未加密的值与数据库中的加密值进行比较。显然我不想从数据库中获取所有记录,将它们具体化,然后根据提供的任何 Where 子句过滤结果......所以我需要做的是:拦截该查询并将其重写为加密 Where 子句中的任何字符串。 所以我看过:

  • 编写查询提供程序,但这似乎不是正确的解决方案...(是吗?)
  • 为 DbSet 编写我自己的 IQueryable 包装器,它将捕获表达式,使用表达式树访问器运行它,然后将新表达式转发到 DbSet...

两种尝试都让我有些失落!我更喜欢我认为的第二种解决方案,因为它感觉更整洁,并且将来可能对其他开发人员更清晰。但我很乐意选择一个或另一个更好的选项!!

我正在努力解决的主要问题是何时/如何将 LINQ 表达式应用于对象...我想我对表达式在 IQueryable 对象中的执行位置有点困惑,因此我不是确定我需要在包装器中实现哪种方法,然后抓取和操作传入的表达式......

我确定我在这里遗漏了一些相当明显的东西,我正在等待那个灯泡时刻......但它不会到来!

我们将非常感激任何帮助!

【问题讨论】:

  • 使用 SQL Server 2008 及其透明数据加密怎么样?

标签: c# linq entity-framework-4 iqueryable ef-code-first


【解决方案1】:

您应该使用QueryInterceptor 属性,在 SO 或 google 中搜索此处,您会找到有关如何使用它的示例。

一个sn-p:

[QueryInterceptor("Orders")]
public Expression<Func<Order, bool>> FilterOrders() 
{
    return o => o.Customer.Name == /* Current principal name. */;
} 

// Insures that the user accessing the customer(s) has the appropriate
// rights as defined in the QueryRules object to access the customer
// resource(s).

[QueryInterceptor ("Customers")]
public Expression<Func<Customer, bool>> FilterCustomers() 
{
  return c => c.Name == /* Current principal name. */ &&
              this.CurrentDataSource.QueryRules.Contains(
                rule => rule.Name == c.Name &&
                        rule.CustomerAllowedToQuery == true
              );
}

【讨论】:

  • 嗨,Davide,我确实看过QueryInterceptor,但它似乎只在使用 WCF 数据服务时相关。如果实现数据服务是唯一的选择,那么我可以这样做,但如果可能的话,我宁愿避免它,否则我看不到实现 QueryInceptor 的方法..?
  • 这是WCF数据服务的特性。
【解决方案2】:

我想我会让你知道我的最终解决方案是什么。 最后,我使用了一个实现 Where 方法的包装类,但没有完全实现 IQueryable。 LINQ 仍将针对该类执行(至少在我想要/需要的程度上),并将使用来自 LINQ 的表达式调用 Where 方法。

然后,在将新表达式树转发到内部 DbSet 之前,我会遍历此 ExpressionTree 并用加密值替换我的字符串。然后返回结果。

它相当粗糙,并且有其局限性,但适用于我们的特定情况没有问题。

谢谢, 本

【讨论】:

    【解决方案3】:

    您可以使用 David Fowler 的查询拦截器:

    https://github.com/davidfowl/QueryInterceptor

    一个使用示例:

    IQueryable q = ...; IQueryable modifed = q.InterceptWith(new MyInterceptor());

    在 MyInterceptor 类上:

    受保护的覆盖表达式 VisitBinary(BinaryExpression 节点) { if (node.NodeType == ExpressionType.Equal) { // 将 == 更改为 != 返回 Expression.NotEqual(node.Left, node.Right); } 返回 base.VisitBinary(node); }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多