始终加密,LINQ及其包含位置

时间:2019-05-23 17:32:21

标签: sql-server linq always-encrypted

通常,这样做是为了返回与列表匹配的数据集:

string[] ssn = { "123456789", "987654321" };

var result_set = db.employee.Where(w => ssn.Contains(w.SSN)).ToList();

但是,当通过“始终加密”对SSN列进行加密时,会发生此错误:

  

SqlException:使用加密的数据类型varchar(9)   (encryption_type ='DETERMINISTIC',encryption_algorithm_name =   'AEAD_AES_256_CBC_HMAC_SHA_256',column_encryption_key_name =   'CEK_SSN',column_encryption_key_database_name ='MyCompany')   collat​​ion_name ='Latin1_General_BIN2'和varchar在以下版本中不兼容   等于运算符。

一般情况下,由于单个值有效,因此设置正确:

string ssn = "123456789";

var result_set = db.employee.Where(w => w.SSN == ssn).ToList();

我正在寻找实现此客户端的最佳方法。我知道这种解决方法是可行的,但它需要整个表都可以实现:

var result_set = db.employee.ToList().Where(w => ssn.Contains(w.SSN));

我已经看到一些示例(与.NET的较早版本相关,不一定与“始终加密”有关),其中存在一些花哨的扩展名,它们创建了一堆“或”。我还知道,使用表变量,我可以使用存储过程做一些棘手的事情。但是我确实在寻找一种优雅的方式来实现此目的,最好是通过LINQ,但至少是在客户端代码中。我正在确定“始终加密”是否会给新项目带来任何无法逾越的障碍,因此我愿意接受建议。

1 个答案:

答案 0 :(得分:1)

您可能必须生成通过or链模拟ssn.Contains(w.SSN)调用的谓词。创建起来应该很简单。

var result_set = db.employee.Where(GenerateContainsSsn(ssn)).ToList();

Expression<Func<Employee, bool>> GenerateContainsSsn<T>(IEnumerable<T> collection)
{
    var param = Expression.Parameter(typeof(Employee));
    var body = collection.Select(v =>
            Expression.Equal(Expression.Property(param, "SSN"), Expression.Constant(v))
        )
        .Aggregate((a, b) => Expression.OrElse(a, b));
    return Expression.Lambda<Func<Employee, bool>>(body, param);
}

如果可用,最好寻找一个支持始终加密功能的linq驱动程序,或者至少可以选择生成兼容的查询。