2022-03-18 22:55:48 +04:00
|
|
|
|
using CoreDatabase;
|
2022-03-19 19:58:10 +04:00
|
|
|
|
using SecurityContract.BindingModels;
|
2022-03-19 22:48:13 +04:00
|
|
|
|
using SecurityContract.Services;
|
2021-04-02 20:04:46 +04:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.IO.Compression;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Runtime.Serialization.Json;
|
2022-03-19 19:58:10 +04:00
|
|
|
|
using ToolsModule.Attributes;
|
|
|
|
|
using ToolsModule.Extensions;
|
|
|
|
|
using ToolsModule.Interfaces;
|
|
|
|
|
using ToolsModule.Models;
|
2021-04-02 20:04:46 +04:00
|
|
|
|
|
|
|
|
|
namespace SecurityDatabaseImplementation.Implementations
|
|
|
|
|
{
|
2022-03-19 19:58:10 +04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Реализация IBackupService для сохранения в JSON через JsonContract
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class BackupJsonContractService : IBackupService
|
2021-04-02 20:04:46 +04:00
|
|
|
|
{
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|