数据库“上传文件字段”迁移至文件服务器示例代码
金蝶云社区-Running
Running
3人赞赏了该文章 856次浏览 未经作者许可,禁止转载编辑于2019年03月08日 16:24:15

上传文件字段】属于常规字段,物理文件存储于数据库表格字段下,单据中可放表头表体,用以上传并存储 UploadWhiteList 白名单允许的文件,通过设置允许多选属性可批量上传多个文件,其中这多个文件的文件名、文件大小以及文件内容等信息由 JSONArray 数组对象转 Base64 字符串后直接存储于数据库字段下,数据实体对象的属性类型为字符串类型。

当单据附件上传量过大时,容易造成数据库越来越大,现提供个简单的示例代码用以将“上传文件字段”下的附件迁移至文件服务器中。本例以采购订单单据编号为CGDD000401的单据为例(可根据实际需要自定义自己的过滤条件,建议是分批次进行迁移),对单据头上的“F_FF_FILEUPDATE 上传文件字段”进行迁移,迁移前需配置并启用文件服务器。

示例代码:
[quote]using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using Kingdee.BOS;
using Kingdee.BOS.Core.DynamicForm.PlugIn;
using Kingdee.BOS.Core.DynamicForm.PlugIn.Args;
using Kingdee.BOS.Core.Metadata;
using Kingdee.BOS.Core.SqlBuilder;
using Kingdee.BOS.JSON;
using Kingdee.BOS.Orm.DataEntity;
using Kingdee.BOS.ServiceHelper;
using Kingdee.BOS.Util;
using Kingdee.BOS.Core;
using Kingdee.BOS.FileServer.Core;
using Kingdee.BOS.FileServer.Core.Object;
using Kingdee.BOS.FileServer.Core.Object.Enum;
using Kingdee.BOS.FileServer.ProxyService;
using Kingdee.BOS.Log;

namespace Running.Sample.PlugIn.BusinessPlugIn.DynamicForm
{
///


/// “上传文件字段”迁移至文件服务器示例代码。
///

[Description("“上传文件字段”迁移至文件服务器示例代码。")]
public class P20190307TransferFileUpdateFieldPlugIn : AbstractDynamicFormPlugIn
{
private const string BillFormId = "PUR_PurchaseOrder"; //待迁移业务对象唯一标志。
private const string FilterString = "FBILLNO = 'CGDD000401'"; //待迁移单据数据筛选条件。
///
/// 待迁移单据的单据主键、单据编号以及文件上传字段的字段名。
///

private readonly string[] _selectFieldKeys = new string[] { "FID", "FBILLNO", "F_FF_FILEUPDATE" };
private FormMetadata _attachmentMetadata; //附件明细元数据对象。

public override void BarItemClick(BarItemClickEventArgs e)
{
_attachmentMetadata = MetaDataServiceHelper.Load(this.View.Context, "BOS_Attachment") as FormMetadata;
Debug.Assert(_attachmentMetadata != null, "_attachmentMetadata != null");

//根据业务对象唯一标志、筛选条件及字段列表,返回待迁移的附件数据,并逐条开始遍历迁移。
QueryBuilderParemeter queryParameter = new QueryBuilderParemeter
{
FormId = BillFormId,
SelectItems = SelectorItemInfo.CreateItems(_selectFieldKeys),
//TODO: 自行定义筛选策略,建议分批筛选进行迁移,本次以采购订单单据编号为CGDD000401的单据为例。
FilterClauseWihtKey = FilterString
};
DynamicObjectCollection billDynObjCol = QueryServiceHelper.GetDynamicObjectCollection(this.View.Context, queryParameter);
foreach (DynamicObject billDynObj in billDynObjCol)
{
try
{
//逐条遍历单据数据,进行迁移。
TransferFilesByBillDynObj(billDynObj);
}
catch (Exception ex)
{
Logger.Error("TransferFileUpdateField",
string.Format("FormId:{0}, FID:{1}的文件迁移失败。", BillFormId, billDynObj["FId"]), ex); /*untrans*/
}
}
}

///


/// 传入单据实体数据对象,对其下上传文件字段进行迁移。
///

/// 单据实体数据对象。
private void TransferFilesByBillDynObj(DynamicObject billDynObj)
{
//将文件信息由Base64字符串转为Json数组,因为一个字段值下可能同时挂多个附件,所以需对单个字段值下多个附件逐个遍历上传。
string filesInfo = ObjectUtils.Object2String(billDynObj["F_ff_FileUpdate"]);
if (filesInfo.IsNullOrEmptyOrWhiteSpace()) return;
JSONArray filesObj = SerializatonUtil.DeserializeFromBase64(filesInfo);
if (filesObj == null || filesObj.Count <= 0) return;
//逐个遍历附件,获取文件字节数组并转为内存流,逐个上传至文件服务器。
List attachmentDataList = new List();
foreach (object fileObj in filesObj)
{
JSONObject fileJsonObj = (JSONObject)fileObj;
if (fileJsonObj["FileName"].IsNullOrEmptyOrWhiteSpace() || fileJsonObj["FileContent"] == null) continue;

MemoryStream fileContentStream = new MemoryStream((byte[])fileJsonObj["FileContent"]);
TFileInfo tFileInfo = new TFileInfo()
{
CTX = this.View.Context,
FileId = string.Empty,
FileName = fileJsonObj["FileName"].ToString(),
Last = true,
Stream = fileContentStream
};
FileUploadResult uploadRes = new UpDownloadService().UploadAttachment(tFileInfo);
Logger.Info("TransferFileUpdateField",
string.Format("FFileId:{0}, Success:{1}, Msg:{2}", uploadRes.FileId, uploadRes.Success, uploadRes.Message));
if (!uploadRes.Success) continue;

//判断上传成功后,收集附件数据,准备批量保存进附件信息表。
attachmentDataList.Add(CollectAttachmentData(billDynObj, uploadRes));
}
if (attachmentDataList.Count > 0)
BusinessDataServiceHelper.Save(this.View.Context, attachmentDataList.ToArray());
//TODO: 上传成功后是否直接删除数据库文件,需自行定义策略,建议等人工确认附件迁移成功删除历史附件。
}

private DynamicObject CollectAttachmentData(DynamicObject billDynObj, FileUploadResult uploadRes)
{
DynamicObject attachmentData = new DynamicObject(_attachmentMetadata.BusinessInfo.GetDynamicObjectType());
attachmentData["BillType"] = BillFormId; //单据唯一标志。
attachmentData["InterID"] = billDynObj["FId"]; //单据主键。
attachmentData["EntryKey"] = " "; //单据体实体标志,若附件挂单据头上,此处赋值为空即可。
attachmentData["AttachmentName"] = uploadRes.FileName; //文件名。
attachmentData["BillNo"] = billDynObj["FBillNo"]; //单据编号。
attachmentData["AttachmentSize"] = Math.Round(Convert.ToDecimal(uploadRes.FileSize) / 1024, 2); //文件大小,KB为单位。
attachmentData["CreateTime"] = DateTime.Now; //创建时间。
attachmentData["FBillStatus"] = "A"; //单据状态(无效字段)。
attachmentData["CreateMen_Id"] = this.View.Context.UserId;
attachmentData["EntryInterID"] = "-1"; //单据体内码。
attachmentData["ExtName"] = Path.GetExtension(uploadRes.FileName); //文件后缀。
attachmentData["FileId"] = uploadRes.FileId; //文件内码。
attachmentData["FileStorage"] = "1"; //文件服务器存储方式。
attachmentData["IsAllowDownLoad"] = 0; //是否禁止下载。
return attachmentData;
}
}
}[/quote]