我有一个Result
对象表(称为Results
)。目前,该表的一列是名为ResultsData
的string
类型,表示C#对象的Json序列化(使用Json.NET)
由于这些对象的大小问题导致数据库查询超时,我想将此列更改为byte[]
,保存对象的Bson序列化。然而,当我更改类型、添加迁移并运行它时,它会崩溃,这是可以理解的,因为string
对象没有隐式转换为byte[]
。作为参考,迁移的Up()
方法如下所示:
public override void Up()
{
AlterColumn("dbo.Results", "ResultsData", c => c.Binary());
}
我应该指出,这里的任何数据丢失都是不可接受的。
现在,我可以处理将单个字符串转换为字节数组的代码,它位于我们将调用byte[] ConvertResult(string resultsData)
的方法中。我不确定的是如何在数据库的每一行调用这个方法。
我在这里能找到的最接近的答案是这个问题的第一个答案:EF5代码优先-通过迁移更改列类型。然而,这种情况下的转换代码完全是在SQL中完成的,这显然不适用于这里。
如果有人对我该怎么做有任何想法,我将不胜感激。如果有帮助的话,我运行的实体框架版本是6.1.3。
编辑
出于绝望,我尝试将实际的转换代码放入SQL方法中:没想到它能工作,但它没有工作,产生了错误Incorrect syntax near 'END'
:
public override void Up()
{
AddColumn("dbo.Results", "ResultsDataTmp", c => c.Binary());
Sql(@"
UPDATE dbo.Results
SET ResultsDataTmp = Service.ConvertOldResultsToBinary(ResultsData)
END
");
DropColumn("dbo.Results", "ResultsData");
RenameColumn("dbo.Results", "ResultsDataTmp", "ResultsData");
}
编辑2
以下是根据DrewJordan的要求实现的Serial.ConvertOldResultsToBinary
。
public byte[] ConvertOldResultsToBinary (string oldResultsData)
{
var serializer = new JsonSerializer
{
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
TypeNameHandling = TypeNameHandling.Auto,
MissingMemberHandling = MissingMemberHandling.Ignore
};
IResultsWrapper result;
using (var reader = new JsonTextReader(new StringReader(oldResultsData)))
{
try
{
result = serializer.Deserialize<ResultsWrapper>(reader);
}
catch (JsonSerializationException)
{
using (var trialReader = new JsonTextReader(new StringReader(oldResultsData)))
{
result = serializer.Deserialize<TrialResultsWrapper>(trialReader);
}
}
}
var stream = new MemoryStream();
using (var writer = new BsonWriter(stream))
{
serializer.Serialize(writer, result);
}
return stream.ToArray();
}
您的第一次编辑是正确的,您需要在SQL中转换为二进制,但是您不能在对Sql()
的调用中调用C#代码,因为您告诉它只需运行您作为SQL命令传递的字符串。
试试这样的东西:
public override void Up()
{
AddColumn("dbo.Results", "ResultsDataTmp", c => c.Binary());
Sql(@"
UPDATE dbo.Results
SET ResultsDataTmp = CAST(ResultsData AS VARBINARY(MAX))
END
");
DropColumn("dbo.Results", "ResultsData");
RenameColumn("dbo.Results", "ResultsDataTmp", "ResultsData");
}