iotgateway/WalkingTec.Mvvm/WalkingTec.Mvvm.Core/BaseBatchVM.cs
2021-12-14 14:10:44 +08:00

420 lines
16 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 Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Text.Json.Serialization;
using WalkingTec.Mvvm.Core.Extensions;
using WalkingTec.Mvvm.Core.Support.FileHandlers;
namespace WalkingTec.Mvvm.Core
{
/// <summary>
/// 批量操作VM接口
/// </summary>
/// <typeparam name="TEditModel">批量修改的VM</typeparam>
public interface IBaseBatchVM<out TEditModel>
where TEditModel : BaseVM
{
/// <summary>
/// 批量修改的VM
/// </summary>
TEditModel LinkedVM { get; }
/// <summary>
/// 批量列表VM
/// </summary>
IBasePagedListVM<TopBasePoco, ISearcher> ListVM { get; }
/// <summary>
/// 列表数据的Id数组
/// </summary>
//IEnumerable<Guid> Ids { get; set; }
string[] Ids { get; set; }
/// <summary>
/// 批量操作的错误
/// </summary>
Dictionary<string, string> ErrorMessage { get; set; }
}
/// <summary>
/// 批量操作的基础VM所有批量操作的VM应继承本类
/// </summary>
/// <typeparam name="TModel">批量修改的VM</typeparam>
/// <typeparam name="TLinkModel">批量列表VM</typeparam>
public class BaseBatchVM<TModel, TLinkModel> : BaseVM, IBaseBatchVM<TLinkModel> where TModel : TopBasePoco,new() where TLinkModel : BaseVM
{
/// <summary>
/// 批量修改的VM
/// </summary>
public TLinkModel LinkedVM { get; set; }
/// <summary>
/// 批量列表VM
/// </summary>
[JsonIgnore]
public IBasePagedListVM<TopBasePoco, ISearcher> ListVM { get; set; }
/// <summary>
/// 批量操作的错误
/// </summary>
[JsonIgnore]
public Dictionary<string, string> ErrorMessage { get; set; }
/// <summary>
/// 列表数据的Id数组
/// </summary>
public string[] Ids { get; set; }
/// <summary>
/// 构造函数
/// </summary>
public BaseBatchVM()
{
//this.Ids = new List<Guid>();
ErrorMessage = new Dictionary<string, string>();
}
/// <summary>
/// 添加错误信息
/// </summary>
/// <param name="e">错误</param>
/// <param name="id">数据Id</param>
protected void SetExceptionMessage(Exception e, string id)
{
if (id != null)
{
ErrorMessage.Add(id, e.Message);
}
}
/// <summary>
/// 检查是否可以删除,当进行批量删除操作时会调用本函数。子类如果有特殊判断应重载本函数
/// </summary>
/// <param name="id">数据Id</param>
/// <param name="errorMessage">错误信息</param>
/// <returns>true代表可以删除false代表不能删除</returns>
protected virtual bool CheckIfCanDelete(object id, out string errorMessage)
{
errorMessage = null;
return true;
}
/// <summary>
/// 批量删除默认对Ids中包含的主键的数据进行删除。子类如果有特殊判断应重载本函数
/// </summary>
/// <returns>true代表成功false代表失败</returns>
public virtual bool DoBatchDelete()
{
bool rv = true;
//循环所有数据Id
List<string> idsData = Ids.ToList();
var modelType = typeof(TModel);
var pros = modelType.GetAllProperties();
//如果包含附件,则先删除附件
List<Guid> fileids = new List<Guid>();
var fa = pros.Where(x => x.PropertyType == typeof(FileAttachment) || typeof(TopBasePoco).IsAssignableFrom(x.PropertyType)).ToList();
var isPersist =typeof(IPersistPoco).IsAssignableFrom(modelType);
var isBasePoco = typeof(IBasePoco).IsAssignableFrom(modelType);
var query = DC.Set<TModel>().AsQueryable();
var fas = pros.Where(x => typeof(IEnumerable<ISubFile>).IsAssignableFrom(x.PropertyType)).ToList();
foreach (var f in fas)
{
query = query.Include(f.Name);
}
query = query.AsNoTracking().CheckIDs(idsData);
var entityList = query.ToList();
for (int i = 0; i < entityList.Count; i++)
{
string checkErro = null;
//检查是否可以删除,如不能删除则直接跳过
if (CheckIfCanDelete(idsData[i], out checkErro) == false)
{
ErrorMessage.Add(idsData[i], checkErro);
rv = false;
break;
}
//进行删除
try
{
var Entity = entityList[i];
if (isPersist)
{
(Entity as IPersistPoco).IsValid = false;
DC.UpdateProperty(Entity, "IsValid");
if (isBasePoco)
{
(Entity as IBasePoco).UpdateTime = DateTime.Now;
(Entity as IBasePoco).UpdateBy = LoginUserInfo.ITCode;
DC.UpdateProperty(Entity, "UpdateTime");
DC.UpdateProperty(Entity, "UpdateBy");
}
}
else
{
foreach (var f in fa)
{
if (f.PropertyType == typeof(FileAttachment))
{
string fidfield = DC.GetFKName2(modelType, f.Name);
var fidpro = pros.Where(x => x.Name == fidfield).FirstOrDefault();
var idresult = fidpro.GetValue(Entity);
if(idresult != null)
{
Guid fid = Guid.Empty;
if(Guid.TryParse(idresult.ToString(), out fid) == true)
{
fileids.Add(fid);
}
}
}
f.SetValue(Entity, null);
}
foreach (var f in fas)
{
var subs = f.GetValue(Entity) as IEnumerable<ISubFile>;
if (subs != null)
{
foreach (var sub in subs)
{
fileids.Add(sub.FileId);
}
f.SetValue(Entity, null);
}
else
{
}
}
if (typeof(TModel) != typeof(FileAttachment))
{
foreach (var pro in pros)
{
if (pro.PropertyType.GetTypeInfo().IsSubclassOf(typeof(TopBasePoco)))
{
pro.SetValue(Entity, null);
}
}
}
DC.DeleteEntity(Entity);
}
}
catch (Exception e)
{
SetExceptionMessage(e, idsData[i]);
rv = false;
}
}
//进行数据库的删除操作
if (rv == true)
{
try
{
DC.SaveChanges();
var fp = Wtm.ServiceProvider.GetRequiredService<WtmFileProvider>();
foreach (var item in fileids)
{
fp.DeleteFile(item.ToString(), DC.ReCreate());
}
}
catch (Exception e)
{
SetExceptionMessage(e, null);
rv = false;
}
}
//如果失败,添加错误信息
if (rv == false)
{
if (ErrorMessage.Count > 0)
{
foreach (var id in idsData)
{
if (!ErrorMessage.ContainsKey(id))
{
ErrorMessage.Add(id, CoreProgram._localizer?["Sys.Rollback"]);
}
}
}
ListVM?.DoSearch();
if (ListVM != null)
{
foreach (var item in ListVM?.GetEntityList())
{
item.BatchError = ErrorMessage.Where(x => x.Key == item.GetID().ToString()).Select(x => x.Value).FirstOrDefault();
}
}
MSD.AddModelError("", CoreProgram._localizer?["Sys.DataCannotDelete"]);
}
return rv;
}
/// <summary>
/// 批量修改默认对Ids中包含的数据进行修改子类如果有特殊判断应重载本函数
/// </summary>
/// <returns>true代表成功false代表失败</returns>
public virtual bool DoBatchEdit()
{
//获取批量修改VM的所有属性
var pros = LinkedVM.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly);
bool rv = true;
List<string> idsData = Ids.ToList();
string currentvmname = this.GetType().Name;
Type vmtype = null;
//找到对应的BaseCRUDVM并初始化
if (currentvmname.ToLower().Contains("apibatchvm"))
{
vmtype = this.GetType().Assembly.GetExportedTypes().Where(x => x.IsSubclassOf(typeof(BaseCRUDVM<TModel>)) && x.Name.ToLower().Contains("apivm") == true).FirstOrDefault();
}
else
{
vmtype = this.GetType().Assembly.GetExportedTypes().Where(x => x.IsSubclassOf(typeof(BaseCRUDVM<TModel>)) && x.Name.ToLower().Contains("apivm") == false).FirstOrDefault();
}
IBaseCRUDVM<TModel> vm = null;
if (vmtype != null)
{
vm = vmtype.GetConstructor(System.Type.EmptyTypes).Invoke(null) as IBaseCRUDVM<TModel>;
vm.CopyContext(this);
}
var entityList = DC.Set<TModel>().CheckIDs(idsData).ToList();
//循环所有数据
for (int i = 0; i < entityList.Count; i++)
{
try
{
//如果找不到对应数据,则输出错误
TModel entity = entityList[i];
if (vm != null)
{
vm.SetEntity(entity);
}
if (entity == null)
{
ErrorMessage.Add(idsData[i], CoreProgram._localizer?["Sys.DataNotExist"]);
rv = false;
break;
}
//如果能找到则循环LinkedVM中的属性给entity中同名属性赋值
foreach (var pro in pros)
{
var proToSet = entity.GetType().GetSingleProperty(pro.Name);
var val = FC.ContainsKey("LinkedVM." + pro.Name) ? FC["LinkedVM." + pro.Name] : null;
if(val == null && FC.ContainsKey("LinkedVM." + pro.Name + "[]"))
{
val = FC["LinkedVM." + pro.Name + "[]"];
}
if (proToSet != null && val != null)
{
var hasvalue = true;
if ( val is StringValues sv && StringValues.IsNullOrEmpty(sv) == true)
{
hasvalue = false;
}
if (hasvalue)
{
proToSet.SetValue(entity, pro.GetValue(LinkedVM));
}
}
}
//调用controller方法验证model
//try
//{
// Controller.GetType().GetMethod("RedoValidation").Invoke(Controller, new object[] { entity });
//}
//catch { }
//如果有对应的BaseCRUDVM则使用其进行数据验证
if (vm != null)
{
vm.Validate();
var errors = vm.MSD;
if (errors != null && errors.Count > 0)
{
var error = "";
foreach (var key in errors.Keys)
{
if (errors[key].Count > 0)
{
error += errors[key].Select(x => x.ErrorMessage).ToSepratedString();
}
}
if (error != "")
{
ErrorMessage.Add(idsData[i], error);
rv = false;
break;
}
}
}
if (typeof(IBasePoco).IsAssignableFrom( typeof(TModel)))
{
IBasePoco ent = entity as IBasePoco;
if (ent.UpdateTime == null)
{
ent.UpdateTime = DateTime.Now;
}
if (string.IsNullOrEmpty(ent.UpdateBy))
{
ent.UpdateBy = LoginUserInfo?.ITCode;
}
}
DC.UpdateEntity(entity);
}
catch (Exception e)
{
SetExceptionMessage(e, idsData[i]);
rv = false;
}
}
//进行数据库的修改操作
if (rv == true)
{
try
{
DC.SaveChanges();
}
catch (Exception e)
{
SetExceptionMessage(e, null);
rv = false;
}
}
//如果有错误,输出错误信息
if (rv == false)
{
if (ErrorMessage.Count > 0)
{
foreach (var id in idsData)
{
if (!ErrorMessage.ContainsKey(id))
{
ErrorMessage.Add(id, CoreProgram._localizer?["Sys.Rollback"]);
}
}
}
RefreshErrorList();
}
return rv;
}
protected void RefreshErrorList()
{
ListVM.DoSearch();
foreach (var item in ListVM.GetEntityList())
{
item.BatchError = ErrorMessage.Where(x => x.Key == item.GetID().ToString()).Select(x => x.Value).FirstOrDefault();
}
}
}
}