批量更新的方法参考批量导入的方法
- 首先是新增按钮,在
actions.txt
里面新增按钮UpdateM| 批量更新 | Update| primary
; - 这个资源是在
Utils-GetResource
中加载,一开始就加载了,启动后是不会运行这部分的。 - 添加批量更新按钮主要添加了这些部分,有没有都用到暂时不知道,直接复制批量导入的方法
我做的是工程列表的批量更新
1、由于工程列表是通过模块管理里面创建的,所以先在AutoTablePage
里面添加:
public void UpdateM() => ShowUpdateMForm();
2、ShowImportForm
方法在BaseTablePage
里面,ShowUpdateMForm
也放在里面
protected async void ShowUpdateMForm(string param = null) // 定义一个受保护的异步void方法,可以带有一个默认为null的字符串参数。
{
var type = typeof(TItem); // 获取泛型类型TItem的Type对象。
var id = $"{type.Name}UpdateM"; // 根据TItem的名称构造一个ID字符串。
if (!string.IsNullOrWhiteSpace(param)) // 如果param不为空且不是空白字符串。
id += $"{param}"; // 将param附加到ID字符串后面,前面加上下划线。
if (Table.IsDictionary) // 如果Table对象的IsDictionary属性为true。
id += $""; // 将Context.Current对象的Id属性附加到ID字符串后面。
var fileService = await CreateServiceAsync(); // 异步创建并获取IFileService接口的实例。
var info = await fileService.GetUpdateMAsync(id); // 调用fileService的GetUpdateMAsync方法,传入ID,获取导入信息。
info.Name = PageName; // 将导入信息的Name属性设置为PageName。
info.BizName = UpdateMTitle; // 将导入信息的BizName属性设置为UpdateMTitle。
var model = new DialogModel { Title = UpdateMTitle }; // 创建DialogModel对象,并设置其Title属性为UpdateMTitle。
model.Content = builder => // 设置DialogModel的Content属性,使用一个lambda表达式来构建内容。
{
builder.Component() // 使用builder来添加一个Importer组件。
.Set(c => c.Model, info) // 设置Importer组件的Model属性为info。
.Set(c => c.OnSuccess, async () => // 设置Importer组件的OnSuccess事件。
{
await model.CloseAsync(); // 当Importer组件成功时,关闭对话框。
await RefreshAsync(); // 刷新界面。
})
.Build(); // 构建Importer组件。
};
UI.ShowDialog(model); // 显示对话框,传入model对象。
}
3、在IFileService
中添加
1)Task GetUpdateMAsync(string bizId);
2)Task UpdateMFilesAsync(UploadInfo info);
同时在FileService中实现该方法逻辑: 1)
public async Task GetUpdateMAsync(string bizId) // 定义一个公共的异步方法,返回类型为UpdateMFormInfo,接收一个字符串参数bizId。
{
var user = Database.User; // 从数据库获取当前用户的信息。
var task = await Database.Query() // 使用异步方式查询SysTask表。
.Where(d => d.CompNo == user.CompNo && d.CreateBy == user.UserName && d.BizId == bizId) // 使用Where方法过滤查询结果,只保留满足条件的记录。
.OrderByDescending(d => d.CreateTime) // 使用OrderByDescending方法按创建时间降序排列查询结果。
.FirstAsync(); // 使用FirstAsync获取排序后的第一个结果。
return UpdateMHelper.GetUpdateM(Context, bizId, task); // 调用UpdateMHelper的帮助方法,传入Context、bizId和查询到的task,返回UpdateMFormInfo对象。
}
2)
public async Task UpdateMFilesAsync(UploadInfo info)
{
// 定义局部变量,用于存储导入表单的数据、任务、文件列表、当前用户等。
var form = info.Model; // 获取上传信息中的模型数据。
SysTask task = null; // 初始化任务对象,可能用于异步处理。
var sysFiles = new List(); // 创建一个用于存储系统文件对象的列表。
var user = CurrentUser; // 获取当前用户信息。
var files = info.Files.GetAttachFiles(user, "Upload", form); // 获取附件文件并根据用户和表单信息进行处理。
// 定义result变量,用于存储数据库事务的结果。
var result = await Database.TransactionAsync(Language.Upload, async db =>
{
// 在数据库事务中添加文件,并返回文件列表。
sysFiles = await AddFilesAsync(db, files, form.BizId, form.BizType);
// 如果业务类型符合特定条件,则创建任务对象。
if (form.BizType == UpdateMHelper.BizType)
{
task = UpdateMHelper.CreateTask(form);
task.Target = sysFiles[0].Id; // 设置任务的目标为第一个文件的ID。
// 如果表单指定了异步处理,则将任务保存到数据库。
if (form.IsAsync)
await db.SaveAsync(task);
}
});
// 将文件列表添加到结果数据中。
result.Data = sysFiles;
// 如果结果有效并且业务类型符合特定条件。
if (result.IsValid && form.BizType == UpdateMHelper.BizType)
{
// 如果表单指定了异步处理,则在结果消息中添加相应的提示。
if (form.IsAsync)
result.Message += Language["Import.FileImporting"];
else if (task != null)
// 如果任务对象存在,则执行导入操作,并更新结果。
result = await UpdateMHelper.ExecuteAsync(Database, task);
}
// 返回包含操作结果的对象。
return result;
}
4、在Known.Components
中新增UpdateMer
全部代码如下:
namespace Known.Components;
// 定义了一个名为Importer的类,它继承自BaseComponent,用于处理文件导入功能。
class UpdateMer : BaseComponent
{
// 私有字段,用于存储导入操作是否完成的状态。
private bool isFinished;
// 私有字段,用于存储文件信息。
private string fileInfo;
// 私有字段,用于存储错误信息。
private string error;
// 私有字段,用于存储消息信息。
private string message;
// 私有字段,用于存储文件服务接口。
private IFileService Service;
// 私有字段,用于存储文件数据信息。
private FileDataInfo file;
// 属性,用于获取错误消息,通过Language字典获取。
private string ErrorMessage => Language["Import.Error"];
// 属性,用于获取或设置导入表单信息。
[Parameter] public UpdateMFormInfo Model { get; set; }
// 属性,用于设置导入成功后的回调动作。
[Parameter] public Action OnSuccess { get; set; }
// 重写基类的OnInitAsync方法,用于异步初始化导入器。
protected override async Task OnInitAsync()
{
await base.OnInitAsync();
// 初始化isFinished、error和message字段。
isFinished = Model.IsFinished;
error = Model.Error;
message = Model.Message;
// 创建文件服务实例。
Service = await CreateServiceAsync<IFileService>();
}
// 重写基类的BuildRender方法,用于构建渲染树。
protected override void BuildRender(RenderTreeBuilder builder)
{
// 构建渲染树的逻辑,包括显示导入提示、选择文件、导入按钮、异步导入选项、下载模板链接、错误信息展示和导入消息。
builder.Div("kui-import", () =>
{
builder.Div("danger", Language["Import.Tips"]);
builder.Div("item", () =>
{
BuildInputFile(builder);
if (isFinished)
builder.Button(Language.Import, this.Callback<MouseEventArgs>(OnImportAsync), "primary");
builder.Div("async", () =>
{
UI.BuildCheckBox(builder, new InputModel<bool>
{
Placeholder = Language["Import.IsAsync"],
Value = Model.IsAsync,
ValueChanged = this.Callback<bool>(v => Model.IsAsync = v)
});
});
});
builder.Div(() =>
{
builder.Link(Language["Import.Download"], this.Callback(OnDownloadTemplateAsync));
if (!string.IsNullOrWhiteSpace(error))
builder.Link(ErrorMessage, this.Callback(OnErrorMessage));
builder.Span("size", fileInfo);
});
var style = string.IsNullOrWhiteSpace(error) ? "primary" : "danger";
builder.Div($"kui-import-message {style}", message);
});
}
// 私有方法,用于显示错误消息。
private void OnErrorMessage()
{
// 显示对话框,展示错误内容。
UI.ShowDialog(new DialogModel
{
Title = ErrorMessage,
Content = builder => builder.Markup(error)
});
}
// 私有方法,用于构建文件输入组件。
private void BuildInputFile(RenderTreeBuilder builder)
{
// 构建文件输入组件的逻辑,包括设置接受的文件类型、禁用状态和文件变更事件。
builder.OpenComponent<InputFile>(0);
builder.AddAttribute(1, "accept", "text/plain,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
builder.AddAttribute(2, "disabled", !isFinished);
builder.AddAttribute(3, "OnChange", this.Callback<InputFileChangeEventArgs>(OnInputFilesChanged));
builder.CloseComponent();
}
// 私有异步方法,用于处理文件输入变更事件。
private async void OnInputFilesChanged(InputFileChangeEventArgs e)
{
// 处理文件变更事件,更新文件信息并读取文件内容。
if (e.File == null || e.File.Size == 0)
return;
fileInfo = $"{Language["Import.Size"]}{e.File.Size / 1024}KB";
this.file = await e.File.ReadFileAsync();
}
// 私有异步方法,用于处理导入操作。
private async void OnImportAsync(MouseEventArgs e)
{
try
{
// 处理导入操作,包括检查文件、更新消息、调用文件服务进行导入,并处理导入结果。
if (file == null)
{
UI.Error(Language["Import.SelectFile"]);
return;
}
message = Language["Import.Importing"];
isFinished = false;
var info = new UploadInfo<UpdateMFormInfo>(Model);
info.Files["Upload"] = [file];
var result = await Service.UpdateMFilesAsync(info);
if (!result.IsValid)
{
message = result.Message;
isFinished = true;
return;
}
if (Model.IsAsync)
{
message = result.Message;
isFinished = false;
}
else
{
OnSuccess?.Invoke();
}
}
catch (Exception ex)
{
message = ex.Message;
}
}
// 私有异步方法,用于处理下载模板操作。
private async Task OnDownloadTemplateAsync()
{
// 处理下载模板操作,获取模板数据并触发下载。
var bytes = await Service.GetImportRuleAsync(Model.BizId);
// 检查变量 bytes 是否不为 null 且长度大于 0。
if (bytes != null && bytes.Length > 0)
{
// 将 bytes 转换为 MemoryStream 对象,MemoryStream 是一个包装了一个字节数组的流。
var stream = new MemoryStream(bytes);
// 调用 JS.DownloadFileAsync 方法,这是一个异步方法,用于下载文件。
// 该方法需要两个参数:文件名和包含文件内容的流。
// 第一个参数是文件名,这里使用 Language["Import.Template"] 作为前缀,后面跟着下划线 _ 和 Model.Name 作为文件名的主体,文件扩展名为 .xlsx。
// 第二个参数是上面创建的 MemoryStream 对象,它包含了要下载的文件内容。
await JS.DownloadFileAsync($"{Language["Import.Template"]}_{Model.Name}.xlsx", stream);
}
}
}
5、Known\Config.cs
中添加:
internal static Dictionary<string, Type> UpdateMTypes { get; } = [];
(暂时不知道有没有用到)
6、Known\FormInfos.cs
中添加UpdateMFormInfo
public class UpdateMFormInfo : FileFormInfo
{
public string Name { get; set; }
public bool IsAsync { get; set; }
public bool IsFinished { get; set; } = true;
public string Message { get; set; }
public string Error { get; set; }
public static List<string> GetUpdateMColumns(string modelType)
{
var columns = new List<string>();
var baseProperties = TypeHelper.Properties(typeof(EntityBase));
var type = Type.GetType(modelType);
var properties = TypeHelper.Properties(type);
foreach (var item in properties)
{
if (item.GetGetMethod().IsVirtual || baseProperties.Any(p => p.Name == item.Name))
continue;
var name = item.DisplayName();
if (!string.IsNullOrWhiteSpace(name))
columns.Add(name);
}
return columns;
}
}
7、Known\Helpers\UpdateMHelper.cs
中新增UpdateMHelper.cs
:
namespace Known.Helpers;
public sealed class UpdateMHelper
{
internal const string BizType = "ImportFiles";
private UpdateMHelper() { }
internal static UpdateMFormInfo GetUpdateM(Context context, string bizId, SysTask task) // 定义一个内部静态方法,返回UpdateMFormInfo对象,接收Context、bizId和SysTask task作为参数。
{
var info = new UpdateMFormInfo { BizId = bizId, BizType = BizType, IsFinished = true }; // 创建一个新的UpdateMFormInfo对象,并设置BizId、BizType和IsFinished属性。
if (task != null) // 如果传入的SysTask task对象不为null。
{
switch (task.Status) // 根据task的Status属性值进行switch语句判断。
{
case TaskStatus.Pending: // 如果状态是Pending(待处理)。
info.Message = context.Language["Import.TaskPending"]; // 设置info的Message属性为根据上下文Language获取的相应消息。
info.IsFinished = false; // 设置IsFinished属性为false,表示任务未完成。
break;
case TaskStatus.Running: // 如果状态是Running(运行中)。
info.Message = context.Language["Import.TaskRunning"]; // 设置info的Message属性为相应的消息。
info.IsFinished = false; // 设置IsFinished属性为false。
break;
case TaskStatus.Failed: // 如果状态是Failed(失败)。
info.Message = context.Language["Import.TaskFailed"]; // 设置info的Message属性为相应的消息。
info.Error = task.Note; // 设置info的Error属性为task的Note属性,可能是错误信息。
break;
case TaskStatus.Success: // 如果状态是Success(成功)。
info.Message = "更新成功"; // 清空info的Message属性,表示没有消息。
break;
}
}
return info; // 返回填充好的UpdateMFormInfo对象。
}
internal static Task<byte[]> GetDictionaryRuleAsync(Context context, SysModule module)
{
var fields = module.Form.Fields;
var excel = ExcelFactory.Create();
var sheet = excel.CreateSheet("Sheet1");
sheet.SetCellValue("A1", context.Language["Import.TemplateTips"], new StyleInfo { IsBorder = true });
sheet.MergeCells(0, 0, 1, fields.Count);
for (int i = 0; i < fields.Count; i++)
{
var field = fields[i];
var note = !string.IsNullOrWhiteSpace(field.Length) ? $"{field.Length}" : "";
sheet.SetColumnWidth(i, 13);
sheet.SetCellValue(1, i, note, new StyleInfo { IsBorder = true, IsTextWrapped = true });
var fontColor = field.Required ? System.Drawing.Color.Red : System.Drawing.Color.White;
sheet.SetCellValue(2, i, field.Name, new StyleInfo { IsBorder = true, FontColor = fontColor, BackgroundColor = Utils.FromHtml("#6D87C1") });
}
sheet.SetRowHeight(1, 30);
var stream = excel.SaveToStream();
return Task.FromResult(stream.ToArray());
}
// 定义一个异步方法,返回一个byte数组,表示生成的Excel文件的内容。
internal static Task<byte[]> GetUpdateMRuleAsync(Context context, string bizId)
{
// 创建一个导入基础对象,使用传入的上下文和业务ID。
var import = UpdateMBase.Create(new UpdateMContext { Context = context, BizId = bizId });
// 如果创建失败(import为null),则返回一个空的byte数组。
if (import == null)
return Task.FromResult(Array.Empty<byte>());
// 初始化导入对象的列信息。
import.InitColumns();
// 如果列信息为空或计数为0,同样返回一个空的byte数组。
if (import.Columns == null || import.Columns.Count == 0)
return Task.FromResult(Array.Empty<byte>());
// 创建一个Excel工作簿对象。
var excel = ExcelFactory.Create();
// 在工作簿中创建一个名为"Sheet1"的工作表。
var sheet = excel.CreateSheet("Sheet1");
// 在A1单元格设置模板提示信息,并应用边框样式。
sheet.SetCellValue("A1", context.Language["Import.TemplateTips"], new StyleInfo { IsBorder = true });
// 将A1单元格与接下来的单元格合并,数量等于导入列的数量。
sheet.MergeCells(0, 0, 1, import.Columns.Count);
// 遍历所有导入列。
for (int i = 0; i < import.Columns.Count; i++)
{
var column = import.Columns[i];
// 设置当前列的宽度为13。
sheet.SetColumnWidth(i, 13);
// 获取列的导入规则注释。
var note = column.GetImportRuleNote(context);
// 在第一行设置列的注释信息,并应用边框和文本换行样式。
sheet.SetCellValue(1, i, note, new StyleInfo { IsBorder = true, IsTextWrapped = true });
// 根据列是否必填设置字体颜色。
var fontColor = column.Required ? System.Drawing.Color.Red : System.Drawing.Color.White;
// 获取列的名称。
var columnName = context.Language.GetString(column);
// 在第二行设置列的名称,并应用边框、字体颜色和背景颜色。
sheet.SetCellValue(2, i, columnName, new StyleInfo { IsBorder = true, FontColor = fontColor, BackgroundColor = Utils.FromHtml("#6D87C1") });
}
try
{
// 设置Excel工作表中第一行的高度为30个单位。
sheet.SetRowHeight(1, 30);
// 将Excel工作簿保存到一个流(Stream)中。
var stream = excel.SaveToStream();
// 将流(Stream)中的数据转换为字节数组(byte[])。
var byteArray = stream.ToArray();
// 返回字节数组。
return Task.FromResult(byteArray);
}
catch (Exception ex)
{
// 出现异常时,记录错误日志。
Logger.Error(ex.Message);
// 返回一个空的字节数组。
return Task.FromResult(Array.Empty<byte>());
}
}
internal static SysTask CreateTask(UpdateMFormInfo form)
{
return new SysTask
{
BizId = form.BizId,
Type = form.BizType,
Name = form.BizName,
Target = "",
Status = TaskStatus.Pending
};
}
internal static async Task<Result> ExecuteAsync(Database db, SysTask task)
{
var context = new UpdateMContext
{
Database = db,
Context = db.Context,
BizId = task.BizId
};
var updatem = UpdateMBase.Create(context);
if (updatem == null)
return Result.Error("The import method is not registered and cannot be executed!");
var file = await db.QueryByIdAsync<SysFile>(task.Target);
return await updatem.ExecuteAsync(file);
}
public static Task ExecuteAsync()
{
return Task.Run(async () =>
{
await TaskHelper.RunAsync(BizType, ExecuteAsync);
});
}
public static Result ReadFile<TItem>(Context context, SysFile file, Action<UpdateMRow<TItem>> action)
{
var path = Config.GetUploadPath(file.Path);
if (!File.Exists(path))
return Result.Error(context.Language["Import.FileNotExists"]);
if (!path.EndsWith(".txt"))
return ReadExcelFile<TItem>(context, path, action);
var columns = string.IsNullOrWhiteSpace(file.Note)
? []
: UpdateMFormInfo.GetUpdateMColumns(file.Note);
return ReadTextFile<TItem>(context, path, columns, action);
}
private static Result ReadExcelFile<TItem>(Context context, string path, Action<UpdateMRow<TItem>> action)
{
var excel = ExcelFactory.Create(path);
if (excel == null)
return Result.Error(context.Language["Import.ExcelFailed"]);
var errors = new Dictionary<int, string>();
var lines = excel.SheetToDictionaries(0, 2);
if (lines == null || lines.Count == 0)
return Result.Error(context.Language["Import.DataRequired"]);
for (int i = 0; i < lines.Count; i++)
{
var item = new UpdateMRow<TItem>(context);
foreach (var line in lines[i])
{
item[line.Key] = line.Value;
}
action?.Invoke(item);
if (!string.IsNullOrWhiteSpace(item.ErrorMessage))
errors.Add(i, item.ErrorMessage);
}
return ReadResult(context, errors);
}
private static Result ReadTextFile<TItem>(Context context, string path, List<string> columns, Action<UpdateMRow<TItem>> action)
{
var errors = new Dictionary<int, string>();
var lines = File.ReadAllLines(path);
if (lines == null || lines.Length == 0)
return Result.Error(context.Language["Import.DataRequired"]);
for (int i = 0; i < lines.Length; i++)
{
var line = lines[i];
if (string.IsNullOrWhiteSpace(line))
continue;
var items = line.Split('\t');
if (items[0] == columns[0])
continue;
var item = new UpdateMRow<TItem>(context);
for (int j = 0; j < columns.Count; j++)
{
item[columns[j]] = items.Length > j ? items[j] : "";
}
action?.Invoke(item);
if (!string.IsNullOrWhiteSpace(item.ErrorMessage))
errors.Add(i, item.ErrorMessage);
}
return ReadResult(context, errors);
}
private static Result ReadResult(Context context, Dictionary<int, string> errors)
{
if (errors.Count == 0)
return Result.Success(context.Language["Import.ValidSuccess"]);
var error = string.Join(Environment.NewLine, errors.Select(e =>
{
var rowNo = context.Language["Import.RowNo"].Replace("{key}", $"{e.Key}");
return $"{rowNo}{e.Value}";
}));
return Result.Error($"{context.Language["Import.ValidFailed"]}{Environment.NewLine}{error}");
}
}
8、Known\Language.cs
中添加internal string GetUpdateMTitle(string name) => this["Title.UpdateM"].Replace("{name}", name);
;
9、Known\UpdateM.cs
添加UpdateM.cs
,代码如下:
namespace Known;
public class UpdateMContext
{
internal Context Context { get; set; }
internal Database Database { get; set; }
internal string BizId { get; set; }
public string BizParam => GetBizIdValue(1);
internal bool IsDictionary => !string.IsNullOrWhiteSpace(BizId) && BizId.StartsWith("Dictionary");
private string GetBizIdValue(int index)
{
if (string.IsNullOrWhiteSpace(BizId))
return string.Empty;
var bizIds = BizId.Split('_');
if (bizIds.Length > index)
return bizIds[index];
return string.Empty;
}
}
public abstract class UpdateMBase(UpdateMContext context)
{
internal UpdateMContext UpdateMContext { get; } = context;
public Context Context { get; } = context.Context;
public Database Database { get; } = context.Database;
public Language Language => Context?.Language;
public List Columns { get; } = [];
public virtual void InitColumns() { }
public virtual Task<Result> ExecuteAsync(SysFile file) => Result.SuccessAsync("");
internal static UpdateMBase Create(UpdateMContext context) // 定义一个内部静态方法,用于创建 ImportBase 类型的对象。
{
// 判断 context 对象的 IsDictionary 属性是否为 true。
if (context.IsDictionary)
return new DictionaryUpdateM(context); // 如果是,创建一个 DictionaryImport 类型的对象并返回。
// 尝试从 Config.ImportTypes 字典中获取与 context.BizId 对应的 Type 对象。
if (!Config.UpdateMTypes.TryGetValue(context.BizId, out Type type))
return null; // 如果没有找到对应的 Type 对象,则返回 null。
// 使用 Activator.CreateInstance 方法创建 type 类型的对象,并传入 context 作为构造函数参数。
// 将创建的对象转换为 ImportBase 类型并返回。
return Activator.CreateInstance(type, context) as UpdateMBase;
}
}
public abstract class UpdateMBase(UpdateMContext context) : UpdateMBase(context)
{
protected void AddColumn(Expression<Func<TItem, TValue>> selector)
{
var property = TypeHelper.Property(selector);
var column = new ColumnInfo(property);
Columns.Add(column);
}
}
public class UpdateMRow : Dictionary<string, string>
{
private readonly Context context;
internal UpdateMRow(Context context)
{
this.context = context;
}
public string ErrorMessage { get; set; }
public string GetValue<TValue>(Expression<Func<TItem, TValue>> selector)
{
var key = GetKey(selector);
return GetValue(key);
}
public string GetValue<TValue>(Result vr, Expression<Func<TItem, TValue>> selector, bool required)
{
var key = GetKey(selector);
return GetValue(vr, key, required);
}
public TValue GetValueT<TValue>(Expression<Func<TItem, TValue>> selector)
{
var key = GetKey(selector);
return GetValue<TValue>(key);
}
public TValue GetValueT<TValue>(Result vr, Expression<Func<TItem, TValue>> selector, bool required)
{
var key = GetKey(selector);
return GetValue<TValue>(vr, key, required);
}
public string GetValue(string key)
{
if (!ContainsKey(key))
return string.Empty;
return this[key];
}
public string GetValue(Result vr, string key, bool required)
{
var value = GetValue(key);
if (required && string.IsNullOrWhiteSpace(value))
vr.AddError(context.Language.Required(key));
return value;
}
public T GetValue<T>(string key)
{
var value = GetValue(key);
if (string.IsNullOrWhiteSpace(value))
return default;
return Utils.ConvertTo<T>(value);
}
public T GetValue<T>(Result vr, string key, bool required)
{
var value = GetValue<T>(key);
if (required && value == null)
vr.AddError(context.Language.GetString("Valid.FormatInvalid", key));
return value;
}
private string GetKey<TValue>(Expression<Func<TItem, TValue>> selector)
{
var property = TypeHelper.Property(selector);
var column = new ColumnInfo(property);
return context.Language.GetString(column);
}
}
class DictionaryUpdateM(UpdateMContext context) : UpdateMBase(context)
{
public override async Task ExecuteAsync(SysFile file)
{
var module = await Database.QueryByIdAsync(UpdateMContext.BizParam);
if (module == null)
return Result.Error(Language.Required("ModuleId"));
var entity = DataHelper.GetEntity(module.EntityData);
if (entity == null || string.IsNullOrWhiteSpace(entity.Id))
return Result.Error(Language.Required("TableName"));
var form = module.Form;
if (form == null || form.Fields == null)
return Result.Error(Language.Required("Form.Fields"));
var models = new List<Dictionary<string, object>>();
var result = UpdateMHelper.ReadFile<Dictionary<string, object>>(Context, file, item =>
{
var model = new Dictionary<string, object>();
foreach (var field in form.Fields)
{
if (field.Type == FieldType.Date || field.Type == FieldType.DateTime)
model[field.Id] = item.GetValue<DateTime?>(field.Name);
else
model[field.Id] = item.GetValue(field.Name);
}
models.Add(model);
});
if (!result.IsValid)
return result;
return await Database.TransactionAsync(Language.Import, async db =>
{
foreach (var item in models)
{
await db.UpdateMAsync(entity.Id, item);
}
});
}
}
10、Sample\Sample\Resources\Locales\zh-CN.txt
在资源中加载相应的文字资源
"Title.UpdateM": "批量更新{name}",
"UpdateM.TaskPending": "更新任务等待中...",
"UpdateM.TaskRunning": "更新任务执行中...",
"UpdateM.TaskFailed": "更新任失败"
11、重点:在Known\Data\Database.cs
中新增方法:
internal async Task UpdateMAsync(string tableName, Dictionary<string, object> data)
{
// 检查 data 是否为空或不包含任何键值对。
if (data == null || data.Count == 0)
return 0;
// 从 data 字典中获取 Id 的值。
var id = data.GetValue<string>($"{tableName}Id");
//var id = $"{tableName}Id";
// 获取用于计数的 SQL 命令信息,用于检查给定的 tableName 和 id 在数据库中是否存在。
var info = Builder.GetCountCommand(tableName, $"{tableName}Id", id);
// 执行 SQL 命令并获取结果,这里期望返回一个整数,表示记录的数量。
var count = await ScalarAsync<int>(info);
// 如果记录数量大于 0,说明存在对应的记录,进行更新操作。
if (count > 0)
{
// 从 data 字典中获取 Version 的值,并增加 1。
data[nameof(EntityBase.Version)] = data.GetValue<int>(nameof(EntityBase.Version)) + 1;
// 调用 UpdateAsync 方法更新记录。
return await UpdateAsync(tableName, $"{tableName}Id", data);
}
return 0;
}
12、重点:在Known\Data\SqlBuilder.cs
中新增方法:
public CommandInfo GetCountCommand(string tableName, string key, string id)
{
var sql = $"select count(*) from {FormatName(tableName)} where {key}=@id";
return new CommandInfo(this, sql, new { id });
}