201 lines
6.9 KiB
C#
201 lines
6.9 KiB
C#
|
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();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|