我的Web服务的一个子任务是在数据库中保存一个文件(以及一些元数据)
该Web服务基于ServiceStack及其ORMlite版本
所以我创建了一个小类,它表示数据库中的附件:
public class Attachment {
public string Description { get; set; }
public string FileName { get; set; }
public string Type { get; set; }
public byte[] Data { get; set; }
}
这是实际的文件
MemoryStream ms = new MemoryStream(webclient.DownloadData(...));
byte[] data = new byte[...];
ms.Read(data, 0, data.Length);
Attachment file = new Attachment() {
/* all the other stuff */
Data = data
};
到目前为止没有问题…:)
现在我已经拥有了将这个文件放入数据库所需的一切。所以让我们开始吧…
dbCmd.Insert<Attachment>(file);
还有一个问题。。。
SqlException: "Operand type clash: text is incompatible with image"
ORMlite将字节数组转换为base64编码的字符串
/* stripped-down example of the command string */
INSERT INTO Attachment (Data) VALUES ('CgoKCgoKCjxodG1sPgo8a...AAAA==')
我搜索了一整天,但没有找到改变ORMlite处理byte[]
数组的方式的解决方案。没有属性DatabaseField
可以用来将dataType
设置为BYTE_ARRAY
,因为这在Java中是可能的。
@DatabaseField(dataType = DataType.BYTE_ARRAY)
byte[] imageBytes;
我错过了一些重要的东西吗
有没有其他方法可以将文件放入数据库?
所以我认为您混淆了ServiceStack内部的ORMLite和Java ORM库ORMLite——它们既不相关,也不必要兼容。
您可能要问的是如何读取Java ORMLite使用C#ORMLite编写的数据。我对C#方面没有任何经验,但我可以在这里谈谈ORMLite正在做什么:
@DatabaseField(dataType = DataType.BYTE_ARRAY)
byte[] imageBytes;
在SqlServer中,这应该对应于以下字段:
"bytes" IMAGE
传递给JDBC的SQL插入命令是:
INSERT INTO "bytearray" ("bytes" ) VALUES (?)
insert arguments: [[B@34883357] (byte[])
它从具有results.getBytes(columnPos)
的结果中检索byte[]
。
你提到:
ORMlite将字节数组转换为base64编码的字符串
这是JDBC在做这件事。我很惊讶,但我想这是可能的。
希望这里有什么帮助。
在ServiceStack.OrmLite v4中,正如mythz在注释中所指定的那样,一切都应该正常工作。
在v3中,如果希望将字节数组序列化为二进制而不是基64字符串,则应该从SqliteOrmLiteDialectProvider
继承,并重写负责将CLR值从SQL值转换为SQL值的函数,以处理字节数组。
public class ByteArrayAwareSqliteOrmLiteDialectProvider
: SqliteOrmLiteDialectProvider {
public override object ConvertDbValue(object value, Type type) {
var bytes = value as byte[];
if (bytes != null && type == typeof(byte[]))
return bytes;
return base.ConvertDbValue(value, type);
}
public override string GetQuotedValue(object value, Type fieldType) {
var bytes = value as byte[];
if (bytes != null && fieldType == typeof(byte[]))
return "X'" + BitConverter.ToString(data).Replace("-", "") + "'";
return base.GetQuotedValue(value, fieldType);
}
}
然后,正确配置您的方言提供商:
OrmLiteConfig.DialectProvider = new ByteArrayAwareSqliteOrmLiteDialectProvider();
对于Oracle提供程序,我分叉了Oracle提供程序的3.9.71,因为我的项目正在做一些UDT工作,需要使用ODP.NET库(Oracle.DataAcess),并且需要OracleParameter对象上的UDTType对象。此外,我还在BLOB列中插入一个压缩的专有"类xml"字符串作为字节数组。
在我的项目中,我使用
public class OracleOrmLiteDialectProvider : OrmLiteDialectProviderBase<OracleOrmLiteDialectProvider>
...
public override string GetQuotedValue(object value, Type fieldType)
{
...
if (fieldType == typeof(byte[]))
{
var bytes = value as byte[];
return "to_blob (utl_raw.cast_to_raw('" + Encoding.UTF8.GetString(bytes)+ "'))";
}
...
}
当然,更好的解决方案是将其计划在明年的预算中,并升级到4.0。