简体   繁体   English

C#中的NHibernate不同的数据库备份

[英]NHibernate different database backup in C#

Situation: I've made a application update program. 情况:我已经制作了应用程序更新程序。 The problem is that the database used by the updated application can differ. 问题是更新的应用程序使用的数据库可能不同。

I've searched for a .dll that can make a backup dump and restore that dump for the different database types single-handily. 我已经搜索了一个可以进行备份转储的.dll,并且可以单独地为不同的数据库类型恢复该转储。 But sadly none were available. 但遗憾的是没有一个可用。

My first idea was to make a use case for every DatabaseType and use the correct one specified by a config.txt file. 我的第一个想法是为每个DatabaseType创建一个用例,并使用config.txt文件指定的正确用例。 But my boss didn't like that solution. 但我的老板不喜欢这个解决方案。 So I tried to see if I could NHibernate (which is also used to send over the update files) to make a database backup. 所以我试着看看我是否可以NHibernate(它也用于发送更新文件)来进行数据库备份。 Sadly while this is possible it's not feasible. 可悲的是,尽管这是可能的,但这是不可行的。 Since that generates too much overhead. 因为这会产生太多的开销。 I've also taken a look at Rhino.ETL but sadly there isn't enough documentation available for it for me to use it. 我还看了一下Rhino.ETL,但很遗憾没有足够的文档供我使用。

So I would like to ask if anyone knows of anything else that might work. 所以我想问一下是否有人知道其他可能有用的东西。 Or am I resigned to go against my boss his wishes and use a per use case approach? 还是我辞职了,反对我的老板他的意愿,并使用每个用例的方法?

i used NHibernate to make the backup and restore. 我使用NHibernate进行备份和恢复。 The order of the entities in Export and Import is important 导出和导入中的实体顺序很重要

ExportData(config, config.BuildSessionFactory(), dataFile, config.ClassMappings.Select(m => m.EntityName));

public void ExportData(Configuration config, ISessionFactory factory, string dataFile, IEnumerable<string> entitiesToExport)
{
    File.Delete(dataFile);
    using (var zip = new ZipFile(dataFile) { CompressionMethod = CompressionMethod.Deflate, CompressionLevel = CompressionLevel.BestCompression })
    using (var session = factory.OpenStatelessSession())
    using (var tx = session.BeginTransaction())
    {
        foreach (var name in entitiesToExport)
        {
            // copy for closure
            var entityName = name;
            zip.AddEntry(entityName + ".csv", (tablename, outstream) =>
            {
                using (var writer = new StreamWriter(outstream))
                {
                    // mapping der Klasse
                    var entityMap = config.GetClassMapping(entityName);
                    // only properties, no Collections (toMany)
                    var properties = entityMap.PropertyClosureIterator.Where(prop => prop.ColumnSpan > 0).ToArray();

                    // write csv(tsv) header
                    writer.WriteLine(string.Join(SEPERATOR, ToPropertyNames(properties)));

                    var classMetaData = factory.GetClassMetadata(entityName);

                    const int pagesize = 10000;
                    int page = 0;
                    IList<object> objects;
                    do
                    {
                        objects = session.CreateCriteria(entityName)
                            .SetFirstResult(page * pagesize)
                            .SetMaxResults(pagesize)
                            .AddOrder(Order.Asc(Projections.Id()))
                            .List<object>();

                        foreach (var obj in objects)
                        {
                            // get property values as string
                            var values = ToPropertyValues(factory, classMetaData, properties, string.Empty, obj).Select(Serialize);

                            writer.WriteLine(string.Join(SEPERATOR, values));
                        }

                        page++;
                    } while (objects.Count > 0);
                }
            });
        }
        zip.Save(dataFile);
    }
}

and import 和进口

public void ImportData(NHCfg.Configuration config, ISessionFactory factory, string dataFile)
{
    using (var zip = new ZipFile(dataFile))
    using (var session = factory.OpenSession())
    using (var tx = session.BeginTransaction())
    {
        var filesAndMaps = from file in zip.EntryFileNames
                           join map in config.ClassMappings on Path.GetFileNameWithoutExtension(file) equals map.EntityName
                           select new { Filename = file, Entitymap = map };

        foreach (var fileAndMap in filesAndMaps)
        {
            using (Stream stream = zip[fileAndMap.Filename].OpenReader())
            using (StreamReader reader = new StreamReader(stream))
            {
                // mapping der Klasse
                var classMetadata = factory.GetClassMetadata(fileAndMap.Entitymap.EntityName);

                var propertyNames = reader.ReadLine().Split(SEPERATOR[0]).Select(str => str.EndsWith("_Id") ? str.Remove(str.Length - "_Id".Length) : str).ToArray();

                // propertyNamen(/pfade) und typen aus dem mapping holen
                List<string> names = new List<string>();
                List<IType> itypes = new List<IType>();

                names.AddRange(classMetadata.PropertyNames);
                itypes.AddRange(classMetadata.PropertyTypes);
                for (int index = names.Count - 1; index >= 0; index--)
                {
                    var propertyType = itypes[index];
                    if (propertyType.IsComponentType)
                    {
                        var basename = names[index];
                        var componentType = (ComponentType)propertyType;
                        names.RemoveAt(index);
                        names.InsertRange(index, componentType.PropertyNames.Select(name => basename + "." + name));
                        itypes.RemoveAt(index);
                        itypes.InsertRange(index, componentType.Subtypes);
                        index += componentType.Subtypes.Length;
                    }
                    else if (propertyType.IsEntityType)
                    {
                        itypes[index] = factory.GetClassMetadata(((EntityType)propertyType).GetAssociatedEntityName()).IdentifierType;
                    }
                }

                // mit den namen aus der csv abgleichen um den index im array der namen und typen zu bestimmen
                int[] indices = new int[propertyNames.Length];
                for (int i = 0; i < indices.Length; i++)
                {
                    indices[i] = names.IndexOf(propertyNames[i]);
                }

                object[] deserialisedValues = new object[itypes.Count];
                object[] objectValues = new object[classMetadata.PropertyTypes.Length];

                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    string[] serialisedValues = line.Split(SEPERATOR[0]);

                    // Werte deserialisieren
                    for (int i = 0; i < serialisedValues.Length; i++)
                    {
                        // nur deserialisieren wenn es das property überhaupt noch gibt
                        if (indices[i] >= 0)
                            deserialisedValues[indices[i]] = Deserialize(serialisedValues[i], itypes[indices[i]].ReturnedClass);
                    }

                    int offset = 0;
                    for (int i = 0; i < objectValues.Length; i++)
                    {
                        var propertyType = classMetadata.PropertyTypes[i];
                        if (propertyType.IsComponentType)
                        {
                            objectValues[i] = ToComponentObject(deserialisedValues, ref offset, (ComponentType)propertyType, session);
                        }
                        else
                        {
                            objectValues[i] = (propertyType.IsEntityType && deserialisedValues[offset] != null) ?
                                session.Load(((ManyToOneType)propertyType).GetAssociatedEntityName(), deserialisedValues[offset]) :
                                deserialisedValues[offset];

                            offset++;
                        }
                    }
                    object entity = classMetadata.Instantiate(null, EntityMode.Poco);

                    classMetadata.SetPropertyValues(entity, objectValues, EntityMode.Poco);

                    session.Save(entity);
                }
            }
        }
        tx.Commit();
    }
}

the functions not present are an exercise for the reader 不存在的功能是读者的练习

Nice answer Firo, could put the code of the methods "ToPropertyNames" ,"ToPropertyValues" and "ToComponentObject"? 很好的答案Firo,可以把方法的代码“ToPropertyNames”,“ToPropertyValues”和“ToComponentObject”?

I add that to use it, the library DotNetZip is required 我添加它来使用它,库DotNetZip是必需的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM