/// <summary>使用指定的实体对象创建实体操作接口,主要用于Entity内部调用,避免反射带来的损耗</summary> /// <param name="type">类型</param> /// <param name="entity"></param> /// <returns></returns> public static IEntityOperate Register(Type type, IEntityOperate entity) { if (entity == null) return CreateOperate(type); // 重新使用判断,减少锁争夺 var eop = entity; if (op_cache.TryGetValue(type, out eop) && eop != null) { var opType = eop.GetType(); var enType = entity.GetType(); // 如果类型相同,或者opType从enType继承,则直接返回,保证缓存使用末端实体操作者opType if (opType == enType || enType.IsAssignableFrom(opType)) return eop; } lock (op_cache) // op_cache曾经是两次非常严重的死锁的核心所在 // 事实上,不管怎么样处理,只要这里还锁定op_cache,那么实体类静态构造函数和CreateOperate方法,就有可能导致死锁产生 //lock ("op_cache" + type.FullName) { if (op_cache.TryGetValue(type, out eop) && eop != null) { var opType = eop.GetType(); var enType = entity.GetType(); // 如果类型相同,或者opType从enType继承,则直接返回,保证缓存使用末端实体操作者opType if (opType == enType || enType.IsAssignableFrom(opType)) return eop; } op_cache[type] = entity; return entity; } }
/// <summary>实体=>外部,从实体对象读取信息并写入外部</summary> /// <param name="entity">实体对象</param> /// <param name="eop">实体操作。为空时由内部构建,但可在遍历调用访问器时由外部构造一次传入,以提高性能。</param> public override void Write(IEntity entity, IEntityOperate eop = null) { writer = GetWriter(); writer.Stream = Stream; writer.Settings.Encoding = Encoding; try { if (AllFields) writer.WriteObject(entity, null, null); else base.Write(entity, eop); } finally { writer.Flush(); //writer.Dispose(); writer = null; } }
/// <summary>把一个实体对象持久化到数据库</summary> /// <param name="factory">实体工厂</param> /// <param name="names">更新属性列表</param> /// <param name="values">更新值列表</param> /// <returns>返回受影响的行数</returns> public virtual Int32 Insert(IEntityOperate factory, String[] names, Object[] values) { if (names == null) { throw new ArgumentNullException(nameof(names), "属性列表和值列表不能为空"); } if (values == null) { throw new ArgumentNullException(nameof(values), "属性列表和值列表不能为空"); } if (names.Length != values.Length) { throw new ArgumentException("属性列表必须和值列表一一对应"); } var fs = new Dictionary <String, FieldItem>(StringComparer.OrdinalIgnoreCase); foreach (var fi in factory.Fields) { fs.Add(fi.Name, fi); } var sbn = new StringBuilder(); var sbv = new StringBuilder(); for (var i = 0; i < names.Length; i++) { if (!fs.ContainsKey(names[i])) { throw new ArgumentException("类[" + factory.EntityType.FullName + "]中不存在[" + names[i] + "]属性"); } // 同时构造SQL语句。names是属性列表,必须转换成对应的字段列表 if (i > 0) { sbn.Append(", "); sbv.Append(", "); } sbn.Append(factory.FormatName(fs[names[i]].Name)); //sbv.Append(SqlDataFormat(values[i], fs[names[i]])); sbv.Append(factory.FormatValue(names[i], values[i])); } return(factory.Session.Execute(String.Format("Insert Into {2}({0}) values({1})", sbn.ToString(), sbv.ToString(), factory.FormatedTableName))); }
/// <summary>获取脏数据列</summary> /// <param name="fact"></param> /// <param name="list"></param> /// <returns></returns> private static String[] GetDirtyColumns(IEntityOperate fact, IEnumerable <IEntity> list) { //var fact = list.FirstOrDefault().GetType().AsFactory(); // 获取所有带有脏数据的字段 var ns = new List <String>(); foreach (var entity in list) { foreach (var fi in fact.Fields) { if (!ns.Contains(fi.Name) && entity.Dirtys[fi.Name]) { ns.Add(fi.Name); } } } return(ns.ToArray()); }
protected void Page_Load(object sender, EventArgs e) { Type type = CommonManageProvider.Provider.LogType; ods.TypeName = type.FullName; ods.DataObjectTypeName = type.FullName; odsCategory.TypeName = type.FullName; odsCategory.DataObjectTypeName = type.FullName; if (!IsPostBack) { IEntityOperate eop = EntityFactory.CreateOperate(CommonManageProvider.Provider.AdminstratorType); if (eop != null) { // 管理员选项最多只要50个 ddlAdmin.DataSource = eop.FindAll(null, null, null, 0, 50); ddlAdmin.DataBind(); } } }
void DoBatch(String action, Func <IAdministrator, Boolean> callback) { Int32[] vs = gvExt.SelectedIntValues; if (vs == null || vs.Length < 1) { return; } Int32 n = 0; IEntityOperate eop = EntityFactory.CreateOperate(EntityType); eop.BeginTransaction(); try { foreach (Int32 item in vs) { IEntity entity = eop.FindByKey(item); IAdministrator admin = entity as IAdministrator; if (admin != null && callback(admin)) { entity.Save(); n++; } } eop.Commit(); WebHelper.Alert("成功" + action + n + "个管理员!"); } catch (Exception ex) { eop.Rollback(); WebHelper.Alert("操作失败!" + ex.Message); } if (n > 0) { gv.DataBind(); } }
/// <summary>外部=>实体,从外部读取信息并写入到实体对象</summary> /// <param name="entity">实体对象</param> /// <param name="eop">实体操作。为空时由内部构建,但可在遍历调用访问器时由外部构造一次传入,以提高性能。</param> public override void Read(IEntity entity, IEntityOperate eop = null) { reader = GetReader(); reader.Stream = Stream; reader.Settings.Encoding = Encoding; try { if (AllFields) { Object obj = entity; reader.ReadObject(null, ref obj, null); } else base.Read(entity, eop); } finally { //reader.Dispose(); reader = null; } }
static Boolean CheckIdentity(FieldItem fi, Object value, IEntityOperate op, StringBuilder sbNames, StringBuilder sbValues) { if (!fi.IsIdentity) return false; // 有些时候需要向自增字段插入数据,这里特殊处理 String idv = null; if (op.AllowInsertIdentity) idv = "" + value; //else // idv = DAL.Create(op.ConnName).Db.FormatIdentity(fi.Field, value); //if (String.IsNullOrEmpty(idv)) continue; // 允许返回String.Empty作为插入空 if (idv == null) return true; sbNames.Separate(", ").Append(op.FormatName(fi.ColumnName)); sbValues.Separate(", "); sbValues.Append(idv); return true; }
static void SetGuidField(IEntityOperate op, IEntity entity) { var fi = op.AutoSetGuidField; if (fi != null) { // 判断是否设置了数据 if (!entity.Dirtys[fi.Name]) { // 如果没有设置,这里给它设置 if (fi.Type == typeof(Guid)) { entity.SetItem(fi.Name, Guid.NewGuid()); } else { entity.SetItem(fi.Name, Guid.NewGuid().ToString()); } } } }
void DoBatch(String action, Func <IRole, Boolean> callback) { Int32[] vs = gvExt.SelectedIntValues; if (vs == null || vs.Length < 1) { return; } Int32 n = 0; IEntityOperate eop = Factory; eop.BeginTransaction(); try { foreach (Int32 item in vs) { IRole entity = FindByRoleID(item); if (entity != null && callback(entity)) { entity.Save(); n++; } } eop.Commit(); WebHelper.Alert("成功为" + n + "个部门" + action + "!"); } catch (Exception ex) { eop.Rollback(); WebHelper.Alert("操作失败!" + ex.Message); } if (n > 0) { gv.DataBind(); } }
/// <summary>把整个集合从数据库中删除</summary> /// <param name="useTransition">是否使用事务保护</param> /// <returns></returns> public Int32 Delete(Boolean useTransition) { if (Count < 1) { return(0); } Int32 count = 0; if (useTransition) { IEntityOperate dal = Factory; dal.BeginTransaction(); try { foreach (T item in this) { count += item.Delete(); } dal.Commit(); } catch { dal.Rollback(); throw; } } else { foreach (T item in this) { count += item.Delete(); } } return(count); }
/// <summary> /// 默认条件。 /// 若有标识列,则使用一个标识列作为条件; /// 如有主键,则使用全部主键作为条件。 /// </summary> /// <param name="entity">实体对象</param> /// <returns>条件</returns> static String DefaultCondition(IEntity entity) { IEntityOperate op = EntityFactory.CreateOperate(entity.GetType()); // 标识列作为查询关键字 FieldItem fi = op.Table.Identity; if (fi != null) { return(op.MakeCondition(fi, entity[fi.Name], "=")); } // 主键作为查询关键字 FieldItem[] ps = op.Table.PrimaryKeys; // 没有标识列和主键,返回取所有数据的语句 if (ps == null || ps.Length < 1) { if (DAL.Debug) { throw new XCodeException("因为没有主键,无法给实体类构造默认条件!"); } return(null); } StringBuilder sb = new StringBuilder(); foreach (FieldItem item in ps) { if (sb.Length > 0) { sb.Append(" And "); } sb.Append(op.FormatName(item.ColumnName)); sb.Append("="); sb.Append(op.FormatValue(item, entity[item.Name])); } return(sb.ToString()); }
/// <summary>外部=>实体,从外部读取信息并写入到实体对象</summary> /// <param name="entity">实体对象</param> /// <param name="eop">实体操作。为空时由内部构建,但可在遍历调用访问器时由外部构造一次传入,以提高性能。</param> public override void Read(IEntity entity, IEntityOperate eop = null) { reader = GetReader(); reader.Stream = Stream; reader.Settings.Encoding = Encoding; try { if (AllFields) { Object obj = entity; reader.ReadObject(null, ref obj, null); } else { base.Read(entity, eop); } } finally { //reader.Dispose(); reader = null; } }
/// <summary>实体=>外部,从实体对象读取信息并写入外部</summary> /// <param name="entity">实体对象</param> /// <param name="eop">实体操作。为空时由内部构建,但可在遍历调用访问器时由外部构造一次传入,以提高性能。</param> public override void Write(IEntity entity, IEntityOperate eop = null) { writer = GetWriter(); writer.Stream = Stream; writer.Settings.Encoding = Encoding; try { if (AllFields) { writer.WriteObject(entity, null, null); } else { base.Write(entity, eop); } } finally { writer.Flush(); //writer.Dispose(); writer = null; } }
static Object FormatParamValue(FieldItem fi, Object value, IEntityOperate eop) { if (value != null) return value; if (fi.IsNullable) return DBNull.Value; switch (Type.GetTypeCode(fi.Type)) { case TypeCode.Boolean: return false; case TypeCode.DBNull: case TypeCode.Empty: return DBNull.Value; case TypeCode.DateTime: return DateTime.MinValue; case TypeCode.Byte: case TypeCode.Char: case TypeCode.Decimal: case TypeCode.Double: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.SByte: case TypeCode.Single: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: return 0; case TypeCode.String: return String.Empty; default: break; } return DBNull.Value; }
/// <summary>外部=>实体,从外部读取信息并写入到实体对象</summary> /// <param name="entity">实体对象</param> /// <param name="eop">实体操作。为空时由内部构建,但可在遍历调用访问器时由外部构造一次传入,以提高性能。</param> public virtual void Read(IEntity entity, IEntityOperate eop = null) { if (!CanRead) return; if (entity == null) throw new ArgumentNullException("entity"); if (eop == null) eop = EntityFactory.CreateOperate(entity.GetType()); foreach (FieldItem item in GetFields(eop)) { try { ReadItem(entity, item); if (OnReadItem != null) OnReadItem(this, new EntityAccessorEventArgs { Entity = entity, Field = item }); } catch (Exception ex) { if (OnError != null) OnError(this, new EntityAccessorEventArgs { Entity = entity, Field = item, Error = ex }); else throw new XCodeException("读取" + item.Name + "的数据时出错!" + ex.Message, ex); } } }
/// <summary>更新一批实体数据</summary> /// <param name="factory">实体工厂</param> /// <param name="setNames">更新属性列表</param> /// <param name="setValues">更新值列表</param> /// <param name="whereNames">条件属性列表</param> /// <param name="whereValues">条件值列表</param> /// <returns>返回受影响的行数</returns> public virtual Int32 Update(IEntityOperate factory, String[] setNames, Object[] setValues, String[] whereNames, Object[] whereValues) { var sc = Join(factory, setNames, setValues, ", "); var wc = Join(factory, whereNames, whereValues, " And "); return Update(factory, sc, wc); }
/// <summary>获取需要访问的字段</summary> /// <param name="eop"></param> /// <returns></returns> protected virtual IEnumerable <FieldItem> GetFields(IEntityOperate eop) { return(AllFields ? eop.AllFields : eop.Fields); }
/// <summary>使用工厂实例化一个字段集合</summary> /// <param name="factory"></param> public FieldCollection(IEntityOperate factory) { Factory = factory; AddRange(Factory.Fields); }
/// <summary>从数据库中删除指定属性列表和值列表所限定的实体对象。</summary> /// <param name="entityType">实体类</param> /// <param name="names">属性列表</param> /// <param name="values">值列表</param> /// <returns></returns> public virtual Int32 Delete(Type entityType, String[] names, Object[] values) { IEntityOperate op = EntityFactory.CreateOperate(entityType); return(Delete(entityType, op.MakeCondition(names, values, "And"))); }
/// <summary> /// 初始化其他属性 /// </summary> protected virtual void Initial() { this.winPage.PageSize = ControlParams.PageSize;//设置每页数目 if (ControlParams.EntityType != null) { this.EntityOper = EntityFactory.CreateOperate(ControlParams.EntityType); } this.winPage.Visible = ControlParams.IsEnablePaging; if (!ControlParams.IsEnablePaging ) { //不分页,这隐藏掉分页控件 this.splitContainer1.SplitterDistance = this.Size.Height - stausInfoShow1.Height; } this.cutSql = ""; }
/// <summary>把一个表的数据全部导入到另一个表</summary> /// <param name="eop">实体操作者。</param> /// <param name="count">要迁移的记录数,默认0表示全部</param> /// <param name="isDesc">是否降序。默认升序</param> /// <param name="getData">用于获取数据的委托</param> /// <returns></returns> public Int32 TransformTable(IEntityOperate eop, Int32 count = 0, Boolean? isDesc = null, Func<Int32, Int32, IEntityList> getData = null) { //var oldInitData = Config.GetConfig<Boolean>("XCode.InitData", true); //Config.SetConfig("XCode.InitData", false); var set = Setting.Current; var oldInitData = set.InitData; set.InitData = false; var name = eop.TableName; eop.ConnName = SrcConn; if (count <= 0) count = eop.Count; if (getData == null) { var order = ""; if (isDesc != null) { var fi = eop.Unique; if (fi != null) order = isDesc.Value ? fi.Desc() : fi.Asc(); } getData = (start, max) => eop.FindAll(null, order, null, start, max); } // 在目标链接上启用事务保护 eop.ConnName = DesConn; // 提取实体会话,避免事务保护作用在错误的连接上 var session = eop.Session; session.BeginTrans(); try { XTrace.WriteLine("{0} 共 {1}", name, count); if (OnlyTransformToEmptyTable && session.Count > 0) { XTrace.WriteLine("{0} 非空,跳过", name); session.Rollback(); return 0; } // 允许插入自增 var oldII = eop.AllowInsertIdentity; if (AllowInsertIdentity) eop.AllowInsertIdentity = true; // 关闭SQL日志 var oldShowSql = DAL.ShowSQL; DAL.ShowSQL = ShowSQL; var total = 0; var index = 0; while (true) { var size = Math.Min(BatchSize, count - index); if (size <= 0) break; eop.ConnName = SrcConn; var list = getData(index, size); if (list == null || list.Count < 1) break; index += list.Count; // 处理事件,外部可以修改实体数据 if (OnTransformEntity != null) { var e = new EventArgs<IEntity>(null); foreach (var entity in list) { e.Arg = entity; OnTransformEntity(this, e); } } eop.ConnName = DesConn; //var rs = list.Insert(true); // 为了避免干扰,必须越过Valid var rs = 0; foreach (var item in list) { rs += session.Insert(item); } XTrace.WriteLine("{0} 导入 {1}/{2} {3:p}", name, index, count, (Double)index / count); total += rs; } DAL.ShowSQL = oldShowSql; // 关闭插入自增 if (AllowInsertIdentity) eop.AllowInsertIdentity = oldII; // 在目标链接上启用事务保护 eop.ConnName = DesConn; session.Commit(); //Config.SetConfig("XCode.InitData", oldInitData); set.InitData = oldInitData; return total; } catch (Exception ex) { XTrace.WriteLine("{0} 错误 {1}", name, ex.ToString()); // 在目标链接上启用事务保护 eop.ConnName = DesConn; session.Rollback(); throw; } }
/// <summary>使用实体工厂构造</summary> /// <param name="factory"></param> public EntityGrid(IEntityOperate factory) { Factory = factory; Init(); }
/// <summary></summary> /// <param name="sender"></param> /// <param name="e"></param> protected virtual void OnPreLoad(object sender, EventArgs e) { IEntity entity = null; try { entity = Entity; } catch (XCodeException ex) { // 由下面自行处理,而不是抛出这个异常 if (!ex.Message.Contains("参数错误!无法取得编号为")) { throw; } } // 判断实体 if (entity == null) { String msg = null; Object eid = EntityID; if (IsNew) { msg = String.Format("参数错误!无法取得编号为{0}的{2}({1})!可能未设置自增主键!", eid, Factory.TableName, Factory.Table.Description); } else { msg = String.Format("参数错误!无法取得编号为{0}的{2}({1})!", eid, Factory.TableName, Factory.Table.Description); } WebHelper.Alert(msg); Response.Write(msg); Response.End(); return; } Control btn = SaveButton; Control btncopy = CopyButton; if (!Page.IsPostBack) { if (ManagePage != null && ManagePage.Container != null && ManagePage.ValidatePermission) { CanSave = entity.IsNullKey && ManagePage.Acquire(PermissionFlags.Insert) || ManagePage.Acquire(PermissionFlags.Update); // 复制只需要新增权限 if (btncopy != null) { btncopy.Visible = ManagePage.Acquire(PermissionFlags.Insert); } } // 新增数据时,不显示复制按钮 if (IsNew && btncopy != null) { btncopy.Visible = false; } if (btn != null) { btn.Visible = CanSave; if (btn is IButtonControl) { (btn as IButtonControl).Text = entity.IsNullKey ? "新增" : "更新"; } } //利用js控制按钮点击状态 //2013-1-14 @宁波-小董,注释下面2句: //原因:这里在XCode默认网站后台没有问题,但在其他网站后台,如果利用js对表单进行验证,就会出现错误, //验证不通过,这里也会执行js代码,“正在提交”,然后页面就死掉了 //不知道要怎么修改才能使得页面验证不通过时,这个就不执行。 //RegButtonOnClientClick(btn); //RegButtonOnClientClick(btncopy); SetForm(); } else { // 如果外部设置了按钮事件,则这里不再设置 if (btn != null && btn is IButtonControl && ControlHelper.FindEventHandler(btn, "Click") == null) { (btn as IButtonControl).Click += delegate { GetForm(); if (ValidForm()) { SaveFormWithTrans(); } } } ; // 这里还不能保存表单,因为使用者习惯性在Load事件里面写业务代码,所以只能在Load完成后保存 //else if (Page.AutoPostBackControl == null) //{ // GetForm(); // if (ValidForm()) SaveFormWithTrans(); //} if (btncopy != null && btncopy is IButtonControl && ControlHelper.FindEventHandler(btncopy, "Click") == null) { (btncopy as IButtonControl).Click += delegate { GetForm(); // 清空主键,变成新增 IEntityOperate eop = EntityFactory.CreateOperate(Entity.GetType()); foreach (var item in eop.Fields) { if (item.PrimaryKey || item.IsIdentity) { Entity[item.Name] = null; } } if (ValidForm()) { SaveFormWithTrans(); } } } ; } }
static Object FormatParamValue(FieldItem fi, Object value, IEntityOperate eop) { if (value != null) return value; if (fi.IsNullable) return DBNull.Value; switch (Type.GetTypeCode(fi.Type)) { case TypeCode.Boolean: return false; case TypeCode.DBNull: case TypeCode.Empty: return DBNull.Value; case TypeCode.DateTime: return DAL.Create(eop.ConnName).Db.DateTimeMin; case TypeCode.Byte: case TypeCode.Char: case TypeCode.Decimal: case TypeCode.Double: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.SByte: case TypeCode.Single: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: return 0; case TypeCode.String: return String.Empty; default: break; } return DBNull.Value; }
/// <summary>从数据库中删除指定条件的实体对象。</summary> /// <param name="factory">实体工厂</param> /// <param name="whereClause">限制条件</param> /// <returns></returns> public virtual Int32 Delete(IEntityOperate factory, String whereClause) { var sql = String.Format("Delete From {0}", factory.FormatedTableName); if (!whereClause.IsNullOrEmpty()) sql += " Where " + whereClause; return factory.Session.Execute(sql); }
/// <summary>把一个表的数据全部导入到另一个表</summary> /// <param name="eop">实体操作者。</param> /// <param name="count">要迁移的记录数,默认0表示全部</param> /// <param name="isDesc">是否降序。默认升序</param> /// <param name="getData">用于获取数据的委托</param> /// <returns></returns> public Int32 TransformTable(IEntityOperate eop, Int32 count = 0, Boolean? isDesc = null, Func<Int32, Int32, IEntityList> getData = null) { var name = eop.TableName; if (count <= 0) count = eop.Count; if (getData == null) { var order = ""; if (isDesc != null) { var fi = eop.Unique; if (fi != null) order = isDesc.Value ? fi.Desc() : fi.Asc(); } getData = (start, max) => eop.FindAll(null, order, null, start, max); } // 在目标链接上启用事务保护 eop.ConnName = DesConn; eop.BeginTransaction(); try { XTrace.WriteLine("{0} 共 {1}", name, count); if (OnlyTransformToEmptyTable && eop.Count > 0) { XTrace.WriteLine("{0} 非空,跳过", name); eop.Rollback(); return 0; } // 允许插入自增 var oldII = eop.AllowInsertIdentity; if (AllowInsertIdentity) eop.AllowInsertIdentity = true; // 关闭SQL日志 var oldShowSql = DAL.ShowSQL; DAL.ShowSQL = false; var total = 0; var index = 0; while (true) { var size = Math.Min(BatchSize, count - index); if (size <= 0) break; eop.ConnName = SrcConn; var list = getData(index, size); if (list == null || list.Count < 1) break; index += list.Count; // 处理事件,外部可以修改实体数据 if (OnTransformEntity != null) { var e = new EventArgs<IEntity>(null); foreach (var entity in list) { e.Arg = entity; OnTransformEntity(this, e); } } eop.ConnName = DesConn; var rs = list.Insert(true); XTrace.WriteLine("{0} 导入 {1}/{2} {3:p}", name, index, count, (Double)index / count); total += rs; } DAL.ShowSQL = oldShowSql; // 关闭插入自增 if (AllowInsertIdentity) eop.AllowInsertIdentity = oldII; // 在目标链接上启用事务保护 eop.ConnName = DesConn; eop.Commit(); return total; } catch (Exception ex) { XTrace.WriteLine("{0} 错误 {1}", name, ex.Message); // 在目标链接上启用事务保护 eop.ConnName = DesConn; eop.Rollback(); throw; } }
/// <summary> /// 初始化其他属性 /// </summary> protected virtual void Initial() { this.winPage.PageSize = ControlParams.PageSize;//设置每页数目 if (ControlParams.EntityType != null) { this.EntityOper = EntityFactory.CreateOperate(ControlParams.EntityType); TableName = EntityOper.TableName; } this.winPage.Visible = ControlParams.IsEnablePaging; if (!ControlParams.IsEnablePaging ) { //不分页,这隐藏掉分页控件 this.splitContainer1.SplitterDistance = this.Size.Height - toolStrip1.Height - stausInfoShow1.Height; } this.cutSql = ""; this.toolAdd.Enabled = ControlParams.IsEnableAddBtn; this.toolStripSetting.Enabled = ControlParams.IsEnableSettingBtn; this.toolPrint.Enabled = ControlParams.IsEnablePrintBtn; }
/// <summary>把SQL模版格式化为SQL语句</summary> /// <param name="entity">实体对象</param> /// <param name="methodType"></param> /// <param name="parameters"></param> /// <returns>SQL字符串</returns> String SQL(IEntity entity, DataObjectMethodType methodType, ref DbParameter[] parameters) { IEntityOperate op = EntityFactory.CreateOperate(entity.GetType()); String sql; StringBuilder sbNames; StringBuilder sbValues; // sbParams用于存储参数化操作时格式化的参数名,参数化和非参数化同时使用,如果存在大字段是,才使用参数化 //StringBuilder sbParams; List <DbParameter> dps; //Boolean hasBigField = false; Boolean isFirst = true; switch (methodType) { case DataObjectMethodType.Fill: return(String.Format("Select * From {0}", op.FormatName(op.TableName))); case DataObjectMethodType.Select: sql = DefaultCondition(entity); // 没有标识列和主键,返回取所有数据的语句 if (String.IsNullOrEmpty(sql)) { throw new XCodeException("实体类缺少主键!"); } return(String.Format("Select * From {0} Where {1}", op.FormatName(op.TableName), sql)); case DataObjectMethodType.Insert: #region Insert sbNames = new StringBuilder(); sbValues = new StringBuilder(); //sbParams = new StringBuilder(); dps = new List <DbParameter>(); // 只读列没有插入操作 foreach (var fi in op.Fields) { // 标识列不需要插入,别的类型都需要 String idv = null; if (fi.IsIdentity) { if (op.AllowInsertIdentity) { idv = "" + entity[fi.Name]; } else { idv = DAL.Create(op.ConnName).Db.FormatIdentity(fi.Field, entity[fi.Name]); } //if (String.IsNullOrEmpty(idv)) continue; // 允许返回String.Empty作为插入空 if (idv == null) { continue; } } // 有默认值,并且没有设置值时,不参与插入操作 // 20120509增加,同时还得判断是否相同数据库或者数据库默认值,比如MSSQL数据库默认值不是GetDate,那么其它数据库是不可能使用的 if (!String.IsNullOrEmpty(fi.DefaultValue) && !entity.Dirtys[fi.Name] && CanUseDefault(fi, op)) { continue; } if (!isFirst) { sbNames.Append(", "); } var name = op.FormatName(fi.ColumnName); sbNames.Append(name); if (!isFirst) { sbValues.Append(", "); } else { isFirst = false; } //// 可空类型插入空 //if (!obj.Dirtys[fi.Name] && fi.DataObjectField.IsNullable) // sbValues.Append("null"); //else //sbValues.Append(SqlDataFormat(obj[fi.Name], fi)); // 数据 if (!fi.IsIdentity) { if (!UseParam(fi)) { sbValues.Append(op.FormatValue(fi, entity[fi.Name])); } else { var paraname = op.FormatParameterName(fi.ColumnName); sbValues.Append(paraname); var dp = op.CreateParameter(); dp.ParameterName = paraname; //dp.Value = entity[fi.Name] ?? DBNull.Value; dp.Value = FormatParamValue(fi, entity[fi.Name], op); dp.IsNullable = fi.IsNullable; dps.Add(dp); } } else { sbValues.Append(idv); } } if (sbNames.Length <= 0) { return(null); } if (dps.Count > 0) { parameters = dps.ToArray(); } return(String.Format("Insert Into {0}({1}) Values({2})", op.FormatName(op.TableName), sbNames, sbValues)); #endregion case DataObjectMethodType.Update: #region Update sbNames = new StringBuilder(); //sbParams = new StringBuilder(); dps = new List <DbParameter>(); // 只读列没有更新操作 foreach (FieldItem fi in op.Fields) { if (fi.IsIdentity) { continue; } //脏数据判断 if (!entity.Dirtys[fi.Name]) { continue; } if (!isFirst) { sbNames.Append(", "); // 加逗号 } else { isFirst = false; } var name = op.FormatName(fi.ColumnName); sbNames.Append(name); sbNames.Append("="); //sbNames.Append(SqlDataFormat(obj[fi.Name], fi)); // 数据 if (!UseParam(fi)) { // 检查累加 Object addvalue = null; Boolean sign; if (entity.TryGetAdditionalValue(fi.Name, out addvalue, out sign)) { if (sign) { sbNames.AppendFormat("{0}+{1}", name, addvalue); } else { sbNames.AppendFormat("{0}-{1}", name, addvalue); } } else { sbNames.Append(op.FormatValue(fi, entity[fi.Name])); // 数据 } } else { var paraname = op.FormatParameterName(fi.ColumnName); sbNames.Append(paraname); var dp = op.CreateParameter(); dp.ParameterName = paraname; dp.Value = FormatParamValue(fi, entity[fi.Name], op); dp.IsNullable = fi.IsNullable; dps.Add(dp); } } if (sbNames.Length <= 0) { return(null); } sql = DefaultCondition(entity); if (String.IsNullOrEmpty(sql)) { return(null); } if (dps.Count > 0) { parameters = dps.ToArray(); } return(String.Format("Update {0} Set {1} Where {2}", op.FormatName(op.TableName), sbNames, sql)); #endregion case DataObjectMethodType.Delete: // 标识列作为删除关键字 sql = DefaultCondition(entity); if (String.IsNullOrEmpty(sql)) { return(null); } return(String.Format("Delete From {0} Where {1}", op.FormatName(op.TableName), sql)); } return(null); }
/// <summary>获取需要访问的字段</summary> /// <param name="eop"></param> /// <returns></returns> protected virtual IEnumerable<FieldItem> GetFields(IEntityOperate eop) { return AllFields ? eop.AllFields : eop.Fields; }
/// <summary>从数据库中删除指定属性列表和值列表所限定的实体对象。</summary> /// <param name="factory">实体工厂</param> /// <param name="names">属性列表</param> /// <param name="values">值列表</param> /// <returns></returns> public virtual Int32 Delete(IEntityOperate factory, String[] names, Object[] values) => Delete(factory, Join(factory, names, values, "And"));
/// <summary>使用指定的实体对象创建实体操作接口,主要用于Entity内部调用,避免反射带来的损耗</summary> /// <param name="type"></param> /// <param name="entity"></param> /// <returns></returns> internal static IEntityOperate Register(Type type, IEntityOperate entity) { if (entity == null) return CreateOperate(type); // 重新使用判断,减少锁争夺 var oc = op_cache; if (oc.ContainsKey(type)) return oc[type]; //lock (op_cache) // op_cache曾经是两次非常严重的死锁的核心所在 // 事实上,不管怎么样处理,只要这里还锁定op_cache,那么实体类静态构造函数和CreateOperate方法,就有可能导致死锁产生 lock ("op_cache" + type.FullName) { if (oc.ContainsKey(type)) return oc[type]; oc[type] = entity; return entity; } }
/// <summary>把一个表的数据全部导入到另一个表</summary> /// <param name="eop">实体操作者。</param> /// <param name="count">要迁移的记录数,默认0表示全部</param> /// <param name="isDesc">是否降序。默认升序</param> /// <param name="getData">用于获取数据的委托</param> /// <returns></returns> public Int32 TransformTable(IEntityOperate eop, Int32 count = 0, Boolean?isDesc = null, Func <Int32, Int32, IEntityList> getData = null) { var name = eop.TableName; if (count <= 0) { count = eop.Count; } if (getData == null) { var order = ""; if (isDesc != null) { var fi = eop.Unique; if (fi != null) { order = isDesc.Value ? fi.Desc() : fi.Asc(); } } getData = (start, max) => eop.FindAll(null, order, null, start, max); } // 在目标链接上启用事务保护 eop.ConnName = DesConn; eop.BeginTransaction(); try { XTrace.WriteLine("{0} 共 {1}", name, count); if (OnlyTransformToEmptyTable && eop.Count > 0) { XTrace.WriteLine("{0} 非空,跳过", name); eop.Rollback(); return(0); } // 允许插入自增 var oldII = eop.AllowInsertIdentity; if (AllowInsertIdentity) { eop.AllowInsertIdentity = true; } // 关闭SQL日志 var oldShowSql = DAL.ShowSQL; DAL.ShowSQL = false; var total = 0; var index = 0; while (true) { var size = Math.Min(BatchSize, count - index); if (size <= 0) { break; } eop.ConnName = SrcConn; var list = getData(index, size); if (list == null || list.Count < 1) { break; } index += list.Count; // 处理事件,外部可以修改实体数据 if (OnTransformEntity != null) { var e = new EventArgs <IEntity>(null); foreach (var entity in list) { e.Arg = entity; OnTransformEntity(this, e); } } eop.ConnName = DesConn; var rs = list.Insert(true); XTrace.WriteLine("{0} 导入 {1}/{2} {3:p}", name, index, count, (Double)index / count); total += rs; } DAL.ShowSQL = oldShowSql; // 关闭插入自增 if (AllowInsertIdentity) { eop.AllowInsertIdentity = oldII; } // 在目标链接上启用事务保护 eop.ConnName = DesConn; eop.Commit(); return(total); } catch (Exception ex) { XTrace.WriteLine("{0} 错误 {1}", name, ex.Message); // 在目标链接上启用事务保护 eop.ConnName = DesConn; eop.Rollback(); throw; } }
/// <summary>把一个表的数据全部导入到另一个表</summary> /// <param name="eop">实体操作者。</param> /// <param name="count">要迁移的记录数,默认0表示全部</param> /// <param name="isDesc">是否降序。默认升序</param> /// <param name="getData">用于获取数据的委托</param> /// <returns></returns> public Int32 TransformTable(IEntityOperate eop, Int32 count = 0, Boolean?isDesc = null, Func <Int32, Int32, IList <IEntity> > getData = null) { var set = Setting.Current; //var oldInitData = set.InitData; //set.InitData = false; var name = eop.TableName; eop.ConnName = SrcConn; if (count <= 0) { count = eop.Count; } if (getData == null) { var order = ""; if (isDesc != null) { var fi = eop.Unique; if (fi != null) { order = isDesc.Value ? fi.Desc() : fi.Asc(); } } getData = (start, max) => eop.FindAll("", order, null, start, max); } // 在目标链接上启用事务保护 eop.ConnName = DesConn; // 提取实体会话,避免事务保护作用在错误的连接上 var session = eop.Session; session.BeginTrans(); try { XTrace.WriteLine("{0} 共 {1}", name, count); if (OnlyTransformToEmptyTable && session.LongCount > 0) { XTrace.WriteLine("{0} 非空,跳过", name); session.Rollback(); return(0); } // 允许插入自增 var oldII = eop.AllowInsertIdentity; if (AllowInsertIdentity) { eop.AllowInsertIdentity = true; } // 关闭SQL日志 var ss = session.Dal.Session; var oldShowSql = ss.ShowSQL; ss.ShowSQL = ShowSQL; var total = 0; var index = 0; while (true) { var size = Math.Min(BatchSize, count - index); if (size <= 0) { break; } eop.ConnName = SrcConn; var list = getData(index, size); if (list == null || list.Count < 1) { break; } index += list.Count; // 处理事件,外部可以修改实体数据 if (OnTransformEntity != null) { var e = new EventArgs <IEntity>(null); foreach (var entity in list) { e.Arg = entity; OnTransformEntity(this, e); } } eop.ConnName = DesConn; //var rs = list.Insert(true); // 为了避免干扰,必须越过Valid var rs = 0; foreach (var item in list) { rs += session.Insert(item); } XTrace.WriteLine("{0} 导入 {1}/{2} {3:p}", name, index, count, (Double)index / count); total += rs; } ss.ShowSQL = oldShowSql; // 关闭插入自增 if (AllowInsertIdentity) { eop.AllowInsertIdentity = oldII; } // 在目标链接上启用事务保护 eop.ConnName = DesConn; session.Commit(); //set.InitData = oldInitData; return(total); } catch (Exception ex) { XTrace.WriteLine("{0} 错误 {1}", name, ex.ToString()); // 在目标链接上启用事务保护 eop.ConnName = DesConn; session.Rollback(); throw; } }
static Boolean CanUseDefault(FieldItem fi, IEntityOperate eop) { var dbType = fi.Table.Table.DbType; var dal = DAL.Create(eop.ConnName); if (dbType == dal.DbType) return true; // 原始数据库类型 var db = DbFactory.Create(dbType); if (db == null) return false; var tc = Type.GetTypeCode(fi.Type); // 特殊处理时间 if (tc == TypeCode.DateTime) { if (String.Equals(db.DateTimeNow, fi.DefaultValue, StringComparison.OrdinalIgnoreCase)) return true; } return false; }