将序列化对象迁移到新版本

发布于 2024-08-20 06:18:07 字数 640 浏览 5 评论 0原文

我想将数据库中以前序列化的对象迁移到新架构。

我以前的对象。

Public interface MyReport
{

    string Id { get; set;}

    string Name { get; set;}

    Dictionary<string, string> PropColl { get; set;}
}

但由于某些原因,我们不得不进行界面更改

Public interface IMarkme
{
}

Public interface MyReport<T> where T : Imarkme
{

    string Id { get; set;}

    string Name { get; set;}

    T ExtendedProp { get; set;}
}

Public NewProp : Imarkme
{
    /// some code here 
}

所以如您所见,我的界面已被修改,我想将基于 MyReport 序列化的序列化对象迁移到 MyReport 有人可以向我提供一些建议,告诉我应该编写哪种实用程序,这可以帮助我实现将序列化对象迁移到新的修改后的接口版本。

谢谢, 股份公司

I would like to migrate me previously serialized objects in database to new schema.

My previous object.

Public interface MyReport
{

    string Id { get; set;}

    string Name { get; set;}

    Dictionary<string, string> PropColl { get; set;}
}

But for some reasons we had to make interface changes

Public interface IMarkme
{
}

Public interface MyReport<T> where T : Imarkme
{

    string Id { get; set;}

    string Name { get; set;}

    T ExtendedProp { get; set;}
}

Public NewProp : Imarkme
{
    /// some code here 
}

So as you can see my interface has been modified and I would like to migrate my serialized objects which were serialized based on MyReport to MyReport
Can someone provide me some input as what kind of utility I should aim to write which can help me achieve migrating my serialized object to new modified interface version.

Thanks,
AG

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

稍尽春風 2024-08-27 06:18:07

我最近实际上做了类似的事情,我创建了一个简单的控制台应用程序,能够将一些序列化对象从一个版本转换为另一个版本。我只是使用了 dll 和反射的两个版本来读取和写入不同属性的值。也许你会发现这对你的灵感很有帮助;)

static void Main(string[] args)
    {
        object test;

        AppDomain.CurrentDomain.AssemblyResolve += domain_AssemblyResolve;


        using (var con = new SqlConnection(connectionString))
        {
            using (var cmd = new SqlCommand())
            {
                cmd.CommandText = "select top 1 Data_Blob from dbo.Serialized";
                cmd.CommandType = CommandType.Text;
                cmd.Connection = con;

                con.Open();
                var blob = (byte[])cmd.ExecuteScalar();

                var bf = new BinaryFormatter();
                var stream = new MemoryStream(blob);
                bf.AssemblyFormat = FormatterAssemblyStyle.Full;
                test = bf.Deserialize(stream);
            }
        }

        var objNewVersion = Activator.CreateInstance(Type.GetType("ObjectGraphLibrary.Test, ObjectGraphLibrary, Version=1.0.0.10, Culture=neutral, PublicKeyToken=33c7c38cf0d65826"));


        var oldType = test.GetType();
        var newType = objNewVersion.GetType();

        var oldName = (string) oldType.GetProperty("Name").GetValue(test, null);
        var oldAge = (int) oldType.GetProperty("Age").GetValue(test, null);

        newType.GetProperty("Name").SetValue(objNewVersion, oldName, null);
        newType.GetProperty("DateOfBirth").SetValue(objNewVersion, DateTime.Now.AddYears(-oldAge), null);


        Console.Read();
    }

    static Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        var assName = new AssemblyName(args.Name);

        var uriBuilder = new UriBuilder(Assembly.GetExecutingAssembly().CodeBase);
        var assemblyPath = Uri.UnescapeDataString(uriBuilder.Path);
        var codeBase = Path.GetDirectoryName(assemblyPath);

        var assPath = Path.Combine(codeBase, string.Format("old\\{0}.{1}.{2}.{3}\\{4}.dll", assName.Version.Major,
                                                 assName.Version.Minor, assName.Version.Build,
                                                 assName.Version.Revision, assName.Name));

        return File.Exists(assPath) ? Assembly.LoadFile(assPath) : null;
    }

I have actually done something similar recently, where I have created a simple console application to be able to transform some serialized objects from one version to another. I have simply used both versions of dlls and reflection to read and write the values of different properties. Probably you'll find this helpful as an inspiration ;)

static void Main(string[] args)
    {
        object test;

        AppDomain.CurrentDomain.AssemblyResolve += domain_AssemblyResolve;


        using (var con = new SqlConnection(connectionString))
        {
            using (var cmd = new SqlCommand())
            {
                cmd.CommandText = "select top 1 Data_Blob from dbo.Serialized";
                cmd.CommandType = CommandType.Text;
                cmd.Connection = con;

                con.Open();
                var blob = (byte[])cmd.ExecuteScalar();

                var bf = new BinaryFormatter();
                var stream = new MemoryStream(blob);
                bf.AssemblyFormat = FormatterAssemblyStyle.Full;
                test = bf.Deserialize(stream);
            }
        }

        var objNewVersion = Activator.CreateInstance(Type.GetType("ObjectGraphLibrary.Test, ObjectGraphLibrary, Version=1.0.0.10, Culture=neutral, PublicKeyToken=33c7c38cf0d65826"));


        var oldType = test.GetType();
        var newType = objNewVersion.GetType();

        var oldName = (string) oldType.GetProperty("Name").GetValue(test, null);
        var oldAge = (int) oldType.GetProperty("Age").GetValue(test, null);

        newType.GetProperty("Name").SetValue(objNewVersion, oldName, null);
        newType.GetProperty("DateOfBirth").SetValue(objNewVersion, DateTime.Now.AddYears(-oldAge), null);


        Console.Read();
    }

    static Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        var assName = new AssemblyName(args.Name);

        var uriBuilder = new UriBuilder(Assembly.GetExecutingAssembly().CodeBase);
        var assemblyPath = Uri.UnescapeDataString(uriBuilder.Path);
        var codeBase = Path.GetDirectoryName(assemblyPath);

        var assPath = Path.Combine(codeBase, string.Format("old\\{0}.{1}.{2}.{3}\\{4}.dll", assName.Version.Major,
                                                 assName.Version.Minor, assName.Version.Build,
                                                 assName.Version.Revision, assName.Name));

        return File.Exists(assPath) ? Assembly.LoadFile(assPath) : null;
    }
夏了南城 2024-08-27 06:18:07

1) 编写一个实用程序来读取旧对象定义中的序列化对象。

2) 该实用程序以非序列化方式将对象写入数据库(即每个字段中都有一条数据,等等......)。

不要养成序列化对象并将对象存储在持久存储中的某个位置以供稍后检索的习惯。序列化不是为此而构建的。

您曾经遇到过过去 C 程序员的问题:他们会在内存中创建一个结构,并将该结构保存到文件中。然后结构体的成员会发生变化,并且他们会想知道如何读回它,因为数据的编码方式不同。

然后出现了数据库格式、INI 文件等,专门为了满足这种需求,因此以一种格式保存数据,然后能够无错误地读取它。

所以不要再犯过去的错误。创建序列化是为了促进短期二进制存储以及通过 TCP/IP 传输对象的能力。

最坏的情况是,将数据存储为 XML,而不是序列化的二进制流。另外,据我所知,MS 不保证能够从另一个版本读取来自一个版本的 .NET 的序列化数据。尽可能将您的数据转换为可读的格式。

1) Write a utility that reads the serialized objects in the old object definition.

2) The utility writes your objects into the DB in a non-serialized manner (ie, with one piece of data in every field, etc...).

Don't get into the habit of serializing objects, and storing the somewhere in persistent storage for retrieval (much) later. Serialization was not built for that.

You have run into the problem of C programmers in the old days: they would create a struct in memory, save that struct into a file. Then the struct's members would change, and they woudl wonder how to read it back, since the data was encoded differently.

then along came database formats, INI files, and so on, specifically to address this need, so saving data in one format, and then being able to read it without error.

So don't repeat errors of the past. Serialization was created to facilitate short-term binary storage and the ability to, say, transmit an object over TCP/IP.

At worst, store your data as XML, not as serialized binary stream. Also, there is no assurance that I know about from MS that says that serialized data from one version of .NET will be able to be read from another. Convert your data to a legible format while you can.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文