Entity framework EF Code First模型,具有保存加密数据的属性

Entity framework EF Code First模型,具有保存加密数据的属性,entity-framework,entity-framework-6,Entity Framework,Entity Framework 6,我维护的数据库中的一个表中有一些加密代码。这大约是2012年,因此没有“始终开启”加密。3列包含加密数据 如果我对EF域进行反向工程,则为该表创建的模型包含类型为byte[]的列的属性。这是意料之中的,因为列是varbinary。所以,看起来是这样的: class Person { public byte[] FirstName { get; set; } // FirstName } public class PersonMap : EntityTypeConfiguration<

我维护的数据库中的一个表中有一些加密代码。这大约是2012年,因此没有“始终开启”加密。3列包含加密数据

如果我对EF域进行反向工程,则为该表创建的模型包含类型为
byte[]
的列的属性。这是意料之中的,因为列是
varbinary
。所以,看起来是这样的:

class Person 
{
  public byte[] FirstName { get; set; } // FirstName
}
public class PersonMap : EntityTypeConfiguration<Person>
{
    public PersonConfiguration(string schema)
    {
        ToTable("v_Person", schema); // note we map to the View
        HasKey(x => x.SomeId);  

        // ... other properties elided for brevity

        Property(x => x.FirstName)
            .HasColumnName(@"FirstName")
            .HasColumnType("nvarchar")
            .IsOptional()
            .HasMaxLength(50);
        Property(x => x.LastName)
            .HasColumnName(@"LastName")
            .HasColumnType("nvarchar")
            .IsOptional()
            .HasMaxLength(50);

        // Foreign keys
        HasRequired(a => a.LogbookEntry)
            .WithOptional(b => b.Person)
            .WillCascadeOnDelete(false);

        MapToStoredProcedures(p =>
            p.Insert(i => i.HasName("Insert_Person"))
                .Update(u => u.HasName("Update_Person"))
                .Delete(d => d.HasName("Delete_Person")));

    }
}
是否有一种优雅的方法来进行某种EF映射/配置,使得FirstName类具有一种
string
类型,并由框架自动解密?我意识到我可以使用
sql
实例化一个Person对象,但是最好将这个过程转移到框架中

我见过两种解决方案中的一种,人们基本上对每个属性都使用sql查询。它们用一个Encrypt属性装饰属性,并迭代每个属性的属性。但是,对于列表中每个对象的每个属性,都使用sql查询,这并不能精确地进行缩放

以前有人“解决”过这个问题吗

注意:要检索数据,首先需要发送类似以下内容的sql语句:

OPEN SYMMETRIC KEY SomeKey DECRYPTION BY CERTIFICATE SomeCertificate

谢谢

在这个答案中,我将列出处理EF中加密列所需的操作。因此,相关列的类型将为
VARBINARY(MAX)
。假设您的桌子看起来像这样:

CREATE TABLE dbo.Person
(
    SomeId int NOT NULL,
    CreatedByUserId uniqueidentifier NULL,
    CreatedUtcDate datetimeoffset(7) NULL,
    Rowversion timestamp NULL,
    FirstName varbinary(MAX) NULL,
    LastName varbinary(MAX) NULL
)
CREATE VIEW [dbo].[v_Person]
AS
SELECT [SomeId]
      ,[CreatedByUserId]
      ,[CreatedUtcDate]
      ,[RowVersion]
      ,CONVERT(NVARCHAR(50),DECRYPTBYKEY([FirstName])) [FirstName]
      ,CONVERT(NVARCHAR(50),DECRYPTBYKEY([LastName])) [LastName]
FROM [dbo].[Person]
步骤1-创建一个返回解密列的视图。视图基本上应该与表相同,但是对于包含加密数据的列,它应该返回解密的数据。看起来是这样的:

CREATE TABLE dbo.Person
(
    SomeId int NOT NULL,
    CreatedByUserId uniqueidentifier NULL,
    CreatedUtcDate datetimeoffset(7) NULL,
    Rowversion timestamp NULL,
    FirstName varbinary(MAX) NULL,
    LastName varbinary(MAX) NULL
)
CREATE VIEW [dbo].[v_Person]
AS
SELECT [SomeId]
      ,[CreatedByUserId]
      ,[CreatedUtcDate]
      ,[RowVersion]
      ,CONVERT(NVARCHAR(50),DECRYPTBYKEY([FirstName])) [FirstName]
      ,CONVERT(NVARCHAR(50),DECRYPTBYKEY([LastName])) [LastName]
FROM [dbo].[Person]
步骤2-创建域模型Person类,将
字符串
作为相关属性类型,而不是
字节[]
(请注意上面
视图
中的
选择
语句,我们已将解密列转换为
NVARCHAR

步骤3-我们需要为该域类设置映射。(我在这里介绍的解决方案是针对EF6的。我知道EF Core还不支持单独的映射文件,所以这需要在DbContext的OnModelCreating事件中完成)。为域对象创建一个映射类,如下所示:

class Person 
{
  public byte[] FirstName { get; set; } // FirstName
}
public class PersonMap : EntityTypeConfiguration<Person>
{
    public PersonConfiguration(string schema)
    {
        ToTable("v_Person", schema); // note we map to the View
        HasKey(x => x.SomeId);  

        // ... other properties elided for brevity

        Property(x => x.FirstName)
            .HasColumnName(@"FirstName")
            .HasColumnType("nvarchar")
            .IsOptional()
            .HasMaxLength(50);
        Property(x => x.LastName)
            .HasColumnName(@"LastName")
            .HasColumnType("nvarchar")
            .IsOptional()
            .HasMaxLength(50);

        // Foreign keys
        HasRequired(a => a.LogbookEntry)
            .WithOptional(b => b.Person)
            .WillCascadeOnDelete(false);

        MapToStoredProcedures(p =>
            p.Insert(i => i.HasName("Insert_Person"))
                .Update(u => u.HasName("Update_Person"))
                .Delete(d => d.HasName("Delete_Person")));

    }
}
如果您有更好的方法,请随时发表评论。

干杯

在这个答案中,我将列出处理EF中的加密列需要做的事情。因此,相关列的类型将为
VARBINARY(MAX)
。假设您的桌子看起来像这样:

CREATE TABLE dbo.Person
(
    SomeId int NOT NULL,
    CreatedByUserId uniqueidentifier NULL,
    CreatedUtcDate datetimeoffset(7) NULL,
    Rowversion timestamp NULL,
    FirstName varbinary(MAX) NULL,
    LastName varbinary(MAX) NULL
)
CREATE VIEW [dbo].[v_Person]
AS
SELECT [SomeId]
      ,[CreatedByUserId]
      ,[CreatedUtcDate]
      ,[RowVersion]
      ,CONVERT(NVARCHAR(50),DECRYPTBYKEY([FirstName])) [FirstName]
      ,CONVERT(NVARCHAR(50),DECRYPTBYKEY([LastName])) [LastName]
FROM [dbo].[Person]
步骤1-创建一个返回解密列的视图。视图基本上应该与表相同,但是对于包含加密数据的列,它应该返回解密的数据。看起来是这样的:

CREATE TABLE dbo.Person
(
    SomeId int NOT NULL,
    CreatedByUserId uniqueidentifier NULL,
    CreatedUtcDate datetimeoffset(7) NULL,
    Rowversion timestamp NULL,
    FirstName varbinary(MAX) NULL,
    LastName varbinary(MAX) NULL
)
CREATE VIEW [dbo].[v_Person]
AS
SELECT [SomeId]
      ,[CreatedByUserId]
      ,[CreatedUtcDate]
      ,[RowVersion]
      ,CONVERT(NVARCHAR(50),DECRYPTBYKEY([FirstName])) [FirstName]
      ,CONVERT(NVARCHAR(50),DECRYPTBYKEY([LastName])) [LastName]
FROM [dbo].[Person]
步骤2-创建域模型Person类,将
字符串
作为相关属性类型,而不是
字节[]
(请注意上面
视图
中的
选择
语句,我们已将解密列转换为
NVARCHAR

步骤3-我们需要为该域类设置映射。(我在这里介绍的解决方案是针对EF6的。我知道EF Core还不支持单独的映射文件,所以这需要在DbContext的OnModelCreating事件中完成)。为域对象创建一个映射类,如下所示:

class Person 
{
  public byte[] FirstName { get; set; } // FirstName
}
public class PersonMap : EntityTypeConfiguration<Person>
{
    public PersonConfiguration(string schema)
    {
        ToTable("v_Person", schema); // note we map to the View
        HasKey(x => x.SomeId);  

        // ... other properties elided for brevity

        Property(x => x.FirstName)
            .HasColumnName(@"FirstName")
            .HasColumnType("nvarchar")
            .IsOptional()
            .HasMaxLength(50);
        Property(x => x.LastName)
            .HasColumnName(@"LastName")
            .HasColumnType("nvarchar")
            .IsOptional()
            .HasMaxLength(50);

        // Foreign keys
        HasRequired(a => a.LogbookEntry)
            .WithOptional(b => b.Person)
            .WillCascadeOnDelete(false);

        MapToStoredProcedures(p =>
            p.Insert(i => i.HasName("Insert_Person"))
                .Update(u => u.HasName("Update_Person"))
                .Delete(d => d.HasName("Delete_Person")));

    }
}
如果您有更好的方法,请随时发表评论。

干杯

我们创建了一个解密字段的SQL视图并映射到该视图。@SteveGreene实际上我自己也找到了解决方案。谢谢你核实。如果您将其作为答案提交,我将很高兴地将其标记为“答案”。这必须是实现这一目标的唯一途径。再次感谢Steve。如果你愿意,你可以写下答案。我们创建了一个解密字段的SQL视图并映射到该视图。@SteveGreene实际上我自己也找到了这个解决方案。谢谢你核实。如果您将其作为答案提交,我将很高兴地将其标记为“答案”。这必须是实现这一目标的唯一途径。再次感谢史蒂夫。如果你愿意,你可以写答案。