首页 > 解决方案 > EF Core 压缩解压栏

问题描述

以一个简单的 poco 为例,它带有一个ID和一个名为data的字符串属性。

在使用EF CoreCOMPRESS(data)保存实体并调用加载它之前,最好的调用方式是什么。数据库列当然是 VARBINARY。DECOMPRESS(data)

详细的:

编写自定义 SQL 来实现这一点(基于上面的示例)如下所示:

SELECT Id, DECOMPRESS(@Data) as [Data]
FROM table

用于选择并像这样插入实体:

INSERT INTO table
VALUES(@Id, COMPRESS(@Data))

笔记:

它是 SQL 服务器。

当前的字符串长度可以达到几千,因为NVARCHAR在 DB 端使用 PAGE 或 ROW 压缩的固定长度不是一个选项。

标签: c#sql-serverentity-framework-core

解决方案


使用转换似乎是最好的方法。因为越早压缩数据,生成的网络 I/O 就越少。此外,压缩会消耗宝贵的 SQL Server CPU 周期,并可能影响 SQL Server 的性能。

public class YourEntityTypeConfigruation : IEntityTypeConfiguration<YourEntity>
{
    public void Configure(EntityTypeBuilder<YourEntity> builder)
    {
        builder.Property(e => e.Data)
            .HasConversion(
                v => Zip(v),
                v => Unzip(v));
    }
    
    public static void CopyTo(Stream src, Stream dest) {
        byte[] bytes = new byte[4096];

        int cnt;

        while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0) {
            dest.Write(bytes, 0, cnt);
        }
    }

    public static byte[] Zip(string str) {
        var bytes = Encoding.UTF8.GetBytes(str);

        using (var msi = new MemoryStream(bytes))
        using (var mso = new MemoryStream()) {
            using (var gs = new GZipStream(mso, CompressionMode.Compress)) {
                //msi.CopyTo(gs);
                CopyTo(msi, gs);
            }

            return mso.ToArray();
        }
    }

    public static string Unzip(byte[] bytes) {
        using (var msi = new MemoryStream(bytes))
        using (var mso = new MemoryStream()) {
            using (var gs = new GZipStream(msi, CompressionMode.Decompress)) {
                //gs.CopyTo(mso);
                CopyTo(gs, mso);
            }

            return Encoding.UTF8.GetString(mso.ToArray());
        }
    }
}

当您创建类似的视图时,可以使用 SQL 服务器方法

CREATE VIEW MyView
AS
SELECT Id, DECOMPRESS(Data) as [Data]
FROM table

并将其映射到 EF 上下文中

对于插入/更新,您需要存储过程来压缩数据。打破使用实体框架跟踪实体更改的目的。


推荐阅读