我有一个情景,需要在多个非常不同的系统之间同步数据。(数据本身相似,但不同系统上的表格格式却很不同。)为了协助这种同步过程,我创建了一个数据库表格,它存储了来自每个系统的对象哈希值以及相关信息和项目键。当任何一个系统中的对象哈希值发生改变时,我会更新另外一个系统中的哈希值。
我的数据库表格看起来像这样:
到目前为止一切都很好。 但是...
为了有效地计算哈希(例如我正在使用的 MD5哈希),您需要能够将其转换为字节数组。
而且...
似乎为了将对象转换为字节数组,它必须是可序列化的。(至少这就是我读到的,并且来自.NET的错误似乎表明这是真的。)
对于其中一个系统,我可以使所有数据库对象都是可序列化的,所以很棒。 哈希被生成,所有东西都同步了,世界是美好的!
对于另一个系统,情况就不那么理想了。 我从实体框架4(Code First)模型中传递了一个数据库上下文,而实体并没有进行序列化。
当我尝试使用类似以下内容的语句将其强制转换为字节时,.NET会抱怨并发生轻微的情绪激动-同时拒绝给我所请求的漂亮的小字节数组。
但是,如果对象(实体)不可序列化,这个程序将会抛出另一个(非常正常的)异常。所以......我修改了这个程序,并向方法定义中添加了一个 where 子句。
我的数据库表格看起来像这样:
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哈希),您需要能够将其转换为字节数组。
而且...
似乎为了将对象转换为字节数组,它必须是可序列化的。(至少这就是我读到的,并且来自.NET的错误似乎表明这是真的。)
对于其中一个系统,我可以使所有数据库对象都是可序列化的,所以很棒。 哈希被生成,所有东西都同步了,世界是美好的!
对于另一个系统,情况就不那么理想了。 我从实体框架4(Code First)模型中传递了一个数据库上下文,而实体并没有进行序列化。
当我尝试使用类似以下内容的语句将其强制转换为字节时,.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());
}
但是...
尽管如此,我仍然希望能够高效且正确地从一个未标记为可序列化的类的对象中创建字节数组。有什么最好的方法可以实现这一点吗?
提前感谢您!