【发布时间】:2011-12-16 21:58:27
【问题描述】:
我有一个场景,我在多个非常不同的系统之间同步数据。 (数据本身是相似的,但不同系统上的表具有完全不同的格式。)为了帮助实现这种同步,我有一个数据库表,它存储来自每个系统的对象哈希以及项目键和其他相关信息。当来自任一系统的对象的哈希值发生变化时,我会更新另一个。
我的数据库表看起来像这样。
CREATE TABLE [dbo].[SyncHashes](
[SyncHashId] [int] IDENTITY(1,1) NOT NULL,
[ObjectName] [nvarchar](50) NULL,
[MappingTypeValue] [nvarchar](25) NULL,
[MappingDirectionValue] [nvarchar](25) NULL,
[SourceSystem] [nvarchar](50) NULL,
[SourceKey] [nvarchar](200) NULL,
[SourceHash] [nvarchar](50) NULL,
[TargetSystem] [nvarchar](50) NULL,
[TargetKey] [nvarchar](200) NULL,
[TargetHash] [nvarchar](50) NULL,
[UpdateNeededValue] [nvarchar](max) NULL,
[CreatedOn] [datetime] NULL,
[ModifiedOn] [datetime] NULL,
[Version] [timestamp] NOT NULL,
[IsActive] [bit] NOT NULL,
PRIMARY KEY CLUSTERED
(
[SyncHashId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
到目前为止一切顺利。但是……
为了有效地计算对象的哈希值(例如 MD5 哈希值(这是我正在使用的)),您需要能够将其转换为 byte数组。
还有……
似乎为了将对象转换为字节数组,它必须是可序列化的。 (至少这是我读到的内容,我从 .NET 得到的错误似乎表明这是真的。)
对于其中一个系统,我能够使我的所有数据库对象可序列化,这很棒。生成哈希,同步一切,世界很美!
对于另一个系统,事情没那么好。我从entity framework 4(代码优先)模型传递了一个数据库上下文,并且实体未序列化。
当我尝试使用类似以下的内容将其转换为字节时,.NET 抱怨并大发脾气——一直拒绝给我我如此礼貌地要求的漂亮的小字节数组。
foreach(var dataItem in context.TableName)
{
var byteArray = (byte[]) dataItem;
}
好的。没问题。
我自己有一个不错的小扩展方法,我认为它可以解决问题。
public static byte[] ObjectToByteArray<T>(this T obj)
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
但是哦,不!如果对象(实体)不可序列化,则此例程会抛出另一个不错的小(完全预期的)异常。
所以...我修改了例程并像这样在方法定义中添加了一个 where 子句。
public static byte[] ObjectToByteArray<T>(this T obj) where T : ISerializable
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
唯一的问题是,现在我又回到了第一个问题,我的所有对象都需要可序列化才能获得一个字节数组。
嗯。不好。
所以我整理了一个技巧来遍历对象的所有属性并生成一个字符串表示,我可以从中构建一个字节数组。它既丑陋又低效,但它确实起到了作用。
public static string ComputeMD5Hash<T>(this T input)
{
StringBuilder sb = new StringBuilder();
Type t = input.GetType();
PropertyInfo[] properties = t.GetProperties();
foreach (var property in properties)
{
sb.Append(property.Name);
sb.Append("|");
object value = property.GetValue(input, null);
if (value != null)
{
sb.Append(value);
}
sb.Append("|");
}
return MD5HashGenerator.GenerateKey(sb.ToString());
}
但是……
毕竟,我仍然真正希望能够有效且正确地从其类未标记为可序列化的对象创建字节数组。实现这一目标的最佳方法是什么?
提前谢谢你!
【问题讨论】:
-
我忘了说 MD5HashGenerator.GenerateKey(byte[] byteArray) 函数使用一个字节数组作为它的。参数。
标签: c# .net serialization bytearray hashcode