【问题标题】:Encoding issue when retrieving blob from SQL Server with Entity Framework使用实体框架从 SQL Server 检索 blob 时出现编码问题
【发布时间】:2011-02-28 10:17:01
【问题描述】:

在尝试将 2003 MS word 文档存储在 SQL Server blob (nvarchar(max)) 字段中,然后使用实体框架 (EF1) 检索它们然后将它们转换回文件时,我注意到了一个特殊性(然后附在电子邮件中)。

基本代码:

1) 我使用 openrowset 将文档插入到数据库中:

INSERT INTO [dbo].[Attachment]([id],[Blob])     
   SELECT 1, (SELECT BulkColumn FROM OPENROWSET(Bulk 'path_to_attachment\abc123.doc', SINGLE_BLOB) AS BLOB) 

2) 然后我使用 EF1 从数据库中检索文件(为了简洁而简化 - 绕过 repo 等):

var attachment = (from a in ctx.Attachment where a.id == 1 select a).FirstOrDefault()
var bytes = Encoding.Unicode.GetBytes(attachment.Blob);
var stream = new MemoryStream(bytes);
var fileName = "abc123.doc";
var fileToAttach = new Attachment(stream, fileName, MediaTypeNames.Application.Octet);

问题:

这可行,但我注意到在通过此过程推送文件后与文件存在一些差异,还有一些小的格式问题等。

在进行了一些更深入的挖掘(使用 VBinDiff)之后 - 看起来一些 Unicode 字符正在转换为 FDFF

00DC > FDFF

原文:

00 00 00 00 00 00 00 00 00 DC 00 00 00 00 00 00

转换:

00 00 00 00 00 00 00 00 FD FF 00 00 00 00 00 00

其他例子是:

BED9 > FDFF
CFD9 > FDFF

这看起来是从这里开始的范围内的最后一个: http://www.unicode.org/charts/PDF/UFB50.pdf

问题

1) 我是在做一些愚蠢的事情,还是 EF 在返回字符串对象 attachment.Blob 时做一些时髦的事情 - 在我尝试将其转换回字节数组之前?

2) 是否有更好的方法可以在仍然使用实体框架的同时从 blob 字段中检索确切的字节? (或者我应该使用存储过程,还是 SqlDataReader - 我真的不想这样做,以免混淆我的数据访问路径)

【问题讨论】:

    标签: sql-server entity-framework encoding c#-3.0


    【解决方案1】:

    Mitch 的回答帮助指出了我的代码中的错误。出于某种原因(我认为是习惯的力量),我将 Blob 字段设置为 nvarchar(max),正如 Mitch 所指出的,SINGLE_BLOB 将文件信息保存为 varbinary(max),这实际上是我在无论如何申请(见问题点 2)。

    解决方案:

    1. 将数据库字段从nvarchar(max) 转换为varbinary(max)
    2. 更新实体框架模型
    3. 将 EF 模型内的 blob 字段从 string 更改为二进制`

    最后,改变这个

    var attachment = (from a in ctx.Attachment where a.id == 1 select a).FirstOrDefault()
    var bytes = Encoding.Unicode.GetBytes(attachment.Blob);
    var stream = new MemoryStream(bytes);
    var fileName = "abc123.doc";
    var fileToAttach = new Attachment(stream, fileName, MediaTypeNames.Application.Octet);
    

    到这里:

    var attachment = (from a in ctx.Attachment where a.id == 1 select a).FirstOrDefault()
    var stream = new MemoryStream(attachment.Blob);
    var fileName = "abc123.doc";
    var fileToAttach = new Attachment(stream, fileName, MediaTypeNames.Application.Octet);
    

    【讨论】:

      【解决方案2】:

      使用SINGLE_BLOB 导入会将文件的内容作为varbinary(max) 类型的单行单列行集返回。

      我建议使用SINGLE_NCLOB 而不是SINGLE_BLOB,它将文件读取为nvarchar(max)

      必须使用此处显示的SINGLE_NCLOB 选项读取Unicode 文件:

      SELECT BulkColumn 
      FROM OPENROWSET (BULK 'path_to_attachment\abc123.doc', SINGLE_NCLOB) AS BLOB
      

      参考:Using OPENROWSET to read large files into SQL Server

      更新(回应评论):如果文件不是 unicode(正如您所尝试的那样),那么当您检索它们时,您不应使用 Unicode 编码来获取字节:

      var bytes = Encoding.ASCII.GetBytes(attachment.Blob);
      

      【讨论】:

      • @Mitch-Wheat:如果我尝试将参数更改为SINGLE_NCLOB,我会收到错误消息:SINGLE_NCLOB requires a UNICODE (widechar) input file. The file specified is not Unicode. - 非常感谢您的回复。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多