2011-03-09 114 views
2

我想在EF4中实现加密列并使用CTP5功能来允许简单地使用POCO来查询数据库。对不起,这是很多的话,但我希望以下给出足够的解释需要和问题!如何在LINQ to Entities查询中实现查询拦截? (c#)

这样的大背景下位,而且至今我的进步:

的意图是,如果您查询表,而不用使用我们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()
(有明确的字符串数据在名称和/或OtherString值)
,然后调用myDbContext.SaveChanges()在字符串到达​​数据存储区之前对其进行加密。现在

,我的问题是,在此查询:

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

这导致未加密的值进行比较,以在数据库加密值。显然,我不想从数据库中获取所有记录,实现它们,然后根据任何提供的Where子句过滤结果...所以我需要做的是:截取该查询并通过加密来重写它Where子句中的字符串。 所以我已经看了:

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

尝试在两者都使我有些失落!我更喜欢我认为的第二种解决方案,因为它感觉有点整洁,未来可能对其他开发人员更清楚。但我很高兴与任何一个更好选项!

我正在努力的主要事情是何时/如何将LINQ表达式应用于对象......我想我自己有点困惑,因为表达式在IQueryable对象中执行的位置因此我不知道我需要在我的包装中实现哪种方法,然后获取并操作正在传递的表达式...

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

任何帮助将非常感激地收到!

+2

如何使用SQL Server 2008及其透明数据加密? – 2011-03-09 17:29:14

回答

2

想我应该让你知道我的最终解决方案了。 最后,我去了一个实现了Where方法的包装类,但没有完全实现IQueryable的范围。 LINQ仍然会针对类执行(至少在我希望/需要的范围内),并将使用LINQ中的表达式调用Where方法。

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

它非常粗糙,有其局限性,但适用于我们的特殊情况没有问题。

感谢, 本

0

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

一个片段:

[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 
      ); 
} 
+0

嗨达维德,我确实看过'QueryInterceptor',但它似乎只有在使用WCF数据服务时才有意义。如果实现数据服务是唯一的选择,那么我可以这样做,但我希望尽可能避免它,并且我看不到以其他方式实现QueryInceptor的方式。 – Ben 2011-03-09 17:25:22

+0

这是WCF数据服务的功能。 – 2011-03-09 17:28:41

0

你可以用大卫·福勒的查询拦截:

https://github.com/davidfowl/QueryInterceptor

一个例子它的使用:

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

而且阶级MyInterceptor:

保护覆盖表达VisitBinary(BinaryExpression节点){ 如果(node.NodeType == ExpressionType.Equal){// 变化==来= 回报Expression.NotEqual( node.Left,node.Right); } return base.VisitBinary(node); }