Всегда зашифровано, LINQ и где содержится - PullRequest
6 голосов
/ 23 мая 2019

Как правило, это можно сделать для возврата набора данных, соответствующего списку:

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

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

Однако, когда столбец SSN зашифрован с помощью Always Encrypted, возникает эта ошибка:

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') collation_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, не обязательно в отношении AlwaysЗашифровано), где есть какое-то необычное расширение, которое создает кучу «или».Я также знаю, что с табличными переменными я мог бы сделать некоторые хитрые вещи с помощью хранимой процедуры.Но я действительно ищу элегантный способ сделать это, предпочтительно через LINQ, но, по крайней мере, в клиентском коде.Я нахожусь в стадии определения, представляет ли Always Encrypted какие-либо неосуществимые барьеры для нового проекта, поэтому я широко открыт для предложений.

1 Ответ

1 голос
/ 23 мая 2019

Возможно, вам придется сгенерировать предикат, имитирующий вызов 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, который поддерживает всегда зашифрованную функцию или, по крайней мере, имеет возможность генерировать запросы, которые будут совместимы.

...