DepartmentProject/DepartmentPortal/Security/SecurityDatabaseImplementation/Implementations/BackupJsonContractService.cs

201 lines
6.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using DatabaseCore;
using ModuleTools.Attributes;
using ModuleTools.Extensions;
using ModuleTools.Interfaces;
using ModuleTools.Models;
using SecurityBusinessLogic.BindingModels;
using SecurityBusinessLogic.Interfaces;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Json;
namespace SecurityDatabaseImplementation.Implementations
{
/// <summary>
/// Реализация IBackupService для сохранения в JSON через JsonContract
/// </summary>
public class BackupJsonContractService : IBackupService
{
public OperationResultModel CreateBackUp(BackupBindingModel model)
{
try
{
var asm = typeof(DatabaseManager).Assembly;
MethodInfo method = GetType().GetTypeInfo().GetDeclaredMethod("SaveToFile");
foreach (var t in asm.GetExportedTypes())
{
if (t.IsClass && t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntitySecurityExtenstion<>)) &&
t.GetCustomAttribute<EntityDescriptionAttribute>() != null)
{
MethodInfo generic = method.MakeGenericMethod(t);
generic.Invoke(this, new object[] { model.FolderName, model.FullData, t });
}
}
if (model.CreateArchive)
{
var fileName = $"{model.FolderName}.zip";
if (File.Exists(fileName))
{
File.Delete($"{model.FolderName}.zip");
}
ZipFile.CreateFromDirectory(model.FolderName, fileName);
}
}
catch (Exception ex)
{
return OperationResultModel.Error(ex);
}
return OperationResultModel.Success(null);
}
public OperationResultModel RestoreBackUp(BackupBindingModel model)
{
try
{
if (model.ArchiveFileName.IsNotEmpty())
{
if(model.FolderName.IsEmpty())
{
model.FolderName = $"{Path.GetDirectoryName(model.ArchiveFileName)}{Path.GetFileNameWithoutExtension(model.ArchiveFileName)}";
}
ZipFile.ExtractToDirectory(model.ArchiveFileName, model.FolderName);
}
var asm = typeof(DatabaseManager).Assembly;
#region вытаскиваем все типы-сущности (они должны быть унаследованы от IEntitySecurityExtenstion и иметь атрибут EntityDescription)
List<Type> types = new();
foreach (var t in asm.GetExportedTypes())
{
if (t.IsClass && t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntitySecurityExtenstion<>)) &&
t.GetCustomAttribute<EntityDescriptionAttribute>() != null)
{
types.Add(t);
}
}
#endregion
#region формиурем зависимости (в каком порядке загружать данные)
Dictionary<Type, int> typesWithLevel = new();
while (types.Count > 0)
{
for (int i = 0; i < types.Count; ++i)
{
var depends = types[i].GetCustomAttributes<EntityDependencyAttribute>();
if ((depends == null || !depends.Any()) && !typesWithLevel.ContainsKey(types[i]))
{
typesWithLevel.Add(types[i], 0);
types.RemoveAt(i--);
continue;
}
int? level = null;
foreach (var depend in depends)
{
var type = typesWithLevel.Keys.FirstOrDefault(x => x.Name == depend.ClassName);
if (type != null)
{
if (!level.HasValue)
{
level = typesWithLevel[type];
}
else if (level < typesWithLevel[type])
{
level = typesWithLevel[type];
}
}
else
{
level = null;
break;
}
}
if (level.HasValue)
{
typesWithLevel.Add(types[i], level.Value + 1);
types.RemoveAt(i--);
continue;
}
}
}
#endregion
#region Удаляем записи сначала из тех, на которые никкто не ссылается и в последнюю оередь, те, на которые все ссылаются
var deleteOrder = typesWithLevel.OrderByDescending(x => x.Value);
MethodInfo delMethod = GetType().GetTypeInfo().GetDeclaredMethod("DeleteFromDB");
foreach (var delElem in deleteOrder)
{
if (File.Exists(string.Format("{0}/{1}.json", model.FolderName, delElem.Key.Name)))
{
MethodInfo generic = delMethod.MakeGenericMethod(delElem.Key);
generic.Invoke(this, null);
}
}
#endregion
#region Заполняем в порядке - сначала те, у которых нет родителей, потом их потомство
MethodInfo method = GetType().GetTypeInfo().GetDeclaredMethod("LoadFromFile");
foreach (var delElem in typesWithLevel.OrderBy(x => x.Value))
{
MethodInfo generic = method.MakeGenericMethod(delElem.Key);
generic.Invoke(this, new object[] { model.FolderName, delElem.Key });
}
#endregion
}
catch (Exception ex)
{
return OperationResultModel.Error(ex);
}
return OperationResultModel.Success(null);
}
/// <summary>
/// Сохранение списка сущности из БД в файл (вызывается через рефлексию)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="folderName"></param>
/// <param name="allowFullData"></param>
/// <param name="t"></param>
private void SaveToFile<T>(string folderName, bool allowFullData, Type t) where T : class, IEntitySecurityExtenstion<T>, new()
{
using var context = DatabaseManager.GetContext;
var records = context.Set<T>().Select(x => x.SecurityCheck(x, allowFullData));
DataContractJsonSerializer jsonFormatter = new(typeof(List<T>));
using FileStream fs = new(string.Format("{0}/{1}.json", folderName, t.Name), FileMode.OpenOrCreate);
jsonFormatter.WriteObject(fs, records);
}
/// <summary>
/// Отчистка записей сущности в БД (вызывается через рефлексию)
/// </summary>
/// <typeparam name="T"></typeparam>
private void DeleteFromDB<T>() where T : class, new()
{
using var context = DatabaseManager.GetContext;
context.Set<T>().RemoveRange(context.Set<T>());
context.SaveChanges();
}
/// <summary>
/// Загрузка списка сущности из файла в БД (вызывается через рефлексию)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="folderName"></param>
/// <param name="t"></param>
private void LoadFromFile<T>(string folderName, Type t) where T : class, new()
{
using var context = DatabaseManager.GetContext;
if (File.Exists(string.Format("{0}/{1}.json", folderName, t.Name)))
{
DataContractJsonSerializer jsonFormatter = new(typeof(List<T>));
using FileStream fs = new(string.Format("{0}/{1}.json", folderName, t.Name), FileMode.Open);
List<T> records = (List<T>)jsonFormatter.ReadObject(fs);
context.Set<T>().AddRange(records);
context.SaveChanges();
}
}
}
}