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
{
///
/// 批量操作VM接口
///
/// 批量修改的VM
public interface IBaseBatchVM
where TEditModel : BaseVM
{
///
/// 批量修改的VM
///
TEditModel LinkedVM { get; }
///
/// 批量列表VM
///
IBasePagedListVM ListVM { get; }
///
/// 列表数据的Id数组
///
//IEnumerable Ids { get; set; }
string[] Ids { get; set; }
///
/// 批量操作的错误
///
Dictionary ErrorMessage { get; set; }
}
///
/// 批量操作的基础VM,所有批量操作的VM应继承本类
///
/// 批量修改的VM
/// 批量列表VM
public class BaseBatchVM : BaseVM, IBaseBatchVM where TModel : TopBasePoco,new() where TLinkModel : BaseVM
{
///
/// 批量修改的VM
///
public TLinkModel LinkedVM { get; set; }
///
/// 批量列表VM
///
[JsonIgnore]
public IBasePagedListVM ListVM { get; set; }
///
/// 批量操作的错误
///
[JsonIgnore]
public Dictionary ErrorMessage { get; set; }
///
/// 列表数据的Id数组
///
public string[] Ids { get; set; }
///
/// 构造函数
///
public BaseBatchVM()
{
//this.Ids = new List();
ErrorMessage = new Dictionary();
}
///
/// 添加错误信息
///
/// 错误
/// 数据Id
protected void SetExceptionMessage(Exception e, string id)
{
if (id != null)
{
ErrorMessage.Add(id, e.Message);
}
}
///
/// 检查是否可以删除,当进行批量删除操作时会调用本函数。子类如果有特殊判断应重载本函数
///
/// 数据Id
/// 错误信息
/// true代表可以删除,false代表不能删除
protected virtual bool CheckIfCanDelete(object id, out string errorMessage)
{
errorMessage = null;
return true;
}
///
/// 批量删除,默认对Ids中包含的主键的数据进行删除。子类如果有特殊判断应重载本函数
///
/// true代表成功,false代表失败
public virtual bool DoBatchDelete()
{
bool rv = true;
//循环所有数据Id
List idsData = Ids.ToList();
var modelType = typeof(TModel);
var pros = modelType.GetAllProperties();
//如果包含附件,则先删除附件
List fileids = new List();
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().AsQueryable();
var fas = pros.Where(x => typeof(IEnumerable).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;
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();
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;
}
///
/// 批量修改,默认对Ids中包含的数据进行修改,子类如果有特殊判断应重载本函数
///
/// true代表成功,false代表失败
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 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)) && x.Name.ToLower().Contains("apivm") == true).FirstOrDefault();
}
else
{
vmtype = this.GetType().Assembly.GetExportedTypes().Where(x => x.IsSubclassOf(typeof(BaseCRUDVM)) && x.Name.ToLower().Contains("apivm") == false).FirstOrDefault();
}
IBaseCRUDVM vm = null;
if (vmtype != null)
{
vm = vmtype.GetConstructor(System.Type.EmptyTypes).Invoke(null) as IBaseCRUDVM;
vm.CopyContext(this);
}
var entityList = DC.Set().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 + "[]"];
}
var valuetoset = pro.GetValue(LinkedVM);
if (proToSet != null && val != null && valuetoset != null)
{
var hasvalue = true;
if ( val is StringValues sv && StringValues.IsNullOrEmpty(sv) == true)
{
hasvalue = false;
}
if (hasvalue)
{
proToSet.SetValue(entity, valuetoset);
}
}
}
//调用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();
}
}
}
}