/// <summary>获取提供者工厂</summary> /// <param name="assemblyFile"></param> /// <param name="className"></param> /// <returns></returns> protected static DbProviderFactory GetProviderFactory(String assemblyFile, String className) { var name = Path.GetFileNameWithoutExtension(assemblyFile); var linkName = name; if (Runtime.Is64BitProcess) { linkName += "64"; } var ver = Environment.Version; if (ver.Major >= 4) { linkName += "Fx" + ver.Major + ver.Minor; } // 有些数据库驱动不区分x86/x64,并且逐步以Fx4为主,所以来一个默认 linkName += ";" + name; var type = PluginHelper.LoadPlugin(className, null, assemblyFile, linkName); // 反射实现获取数据库工厂 var file = assemblyFile; file = NewLife.Setting.Current.GetPluginPath().CombinePath(file); // 如果还没有,就写异常 if (type == null && !File.Exists(file)) { throw new FileNotFoundException("缺少文件" + file + "!", file); } if (type == null) { XTrace.WriteLine("驱动文件{0}无效或不适用于当前环境,准备删除后重新下载!", assemblyFile); try { File.Delete(file); } catch (UnauthorizedAccessException) { } catch (Exception ex) { XTrace.Log.Error(ex.ToString()); } type = PluginHelper.LoadPlugin(className, null, file, linkName); // 如果还没有,就写异常 if (!File.Exists(file)) { throw new FileNotFoundException("缺少文件" + file + "!", file); } } if (type == null) { return(null); } var asm = type.Assembly; if (DAL.Debug) { DAL.WriteLog("{2}驱动{0} 版本v{1}", asm.Location, asm.GetName().Version, className.TrimEnd("Client", "Factory")); } var field = type.GetFieldEx("Instance"); if (field == null) { return(Activator.CreateInstance(type) as DbProviderFactory); } return(Reflect.GetValue(null, field) as DbProviderFactory); }
/// <summary>获取提供者工厂</summary> /// <param name="assemblyFile"></param> /// <param name="className"></param> /// <param name="ignoreError"></param> /// <returns></returns> public static DbProviderFactory GetProviderFactory(String assemblyFile, String className, Boolean ignoreError = false) { try { var links = new List <String>(); var name = Path.GetFileNameWithoutExtension(assemblyFile); if (!name.IsNullOrEmpty()) { var linkName = name; #if __CORE__ if (Runtime.Linux) { linkName += Environment.Is64BitProcess ? ".linux-x64" : ".linux-x86"; links.Add(linkName); links.Add(name + ".linux"); } else { linkName += Environment.Is64BitProcess ? ".win-x64" : ".win-x86"; links.Add(linkName); links.Add(name + ".win"); } linkName = name + ".st"; #else if (Environment.Is64BitProcess) { linkName += "64"; } var ver = Environment.Version; if (ver.Major >= 4) { linkName += "Fx" + ver.Major + ver.Minor; } #endif links.Add(linkName); // 有些数据库驱动不区分x86/x64,并且逐步以Fx4为主,所以来一个默认 if (!links.Contains(name)) { links.Add(name); } } var type = PluginHelper.LoadPlugin(className, null, assemblyFile, links.Join(",")); // 反射实现获取数据库工厂 var file = assemblyFile; var plugin = NewLife.Setting.Current.GetPluginPath(); file = plugin.CombinePath(file); // 如果还没有,就写异常 if (type == null) { if (assemblyFile.IsNullOrEmpty()) { return(null); } if (!File.Exists(file)) { throw new FileNotFoundException("缺少文件" + file + "!", file); } } if (type == null) { XTrace.WriteLine("驱动文件{0}无效或不适用于当前环境,准备删除后重新下载!", assemblyFile); try { File.Delete(file); } catch (UnauthorizedAccessException) { } catch (Exception ex) { XTrace.Log.Error(ex.ToString()); } type = PluginHelper.LoadPlugin(className, null, file, links.Join(",")); // 如果还没有,就写异常 if (!File.Exists(file)) { throw new FileNotFoundException("缺少文件" + file + "!", file); } } if (type == null) { return(null); } var asm = type.Assembly; if (DAL.Debug) { DAL.WriteLog("{2}驱动{0} 版本v{1}", asm.Location, asm.GetName().Version, name ?? className.TrimEnd("Client", "Factory")); } var field = type.GetFieldEx("Instance"); if (field == null) { return(Activator.CreateInstance(type) as DbProviderFactory); } return(Reflect.GetValue(null, field) as DbProviderFactory); } catch { if (ignoreError) { return(null); } throw; } }
protected override void OnSetConnectionString(ConnectionStringBuilder builder) { base.OnSetConnectionString(builder); var flag = Factory != null && Factory.GetType().FullName.StartsWith("System.Data"); if (flag) { //// 正常情况下INSERT, UPDATE和DELETE语句不返回数据。 当开启count-changes,以上语句返回一行含一个整数值的数据——该语句插入,修改或删除的行数。 //if (!builder.ContainsKey("count_changes")) builder["count_changes"] = "1"; // 优化SQLite,如果原始字符串里面没有这些参数,就设置这些参数 //builder.TryAdd("Pooling", "true"); //if (!builder.ContainsKey("Cache Size")) builder["Cache Size"] = "5000"; builder.TryAdd("Cache Size", (512 * 1024 * 1024 / -1024) + ""); // 加大Page Size会导致磁盘IO大大加大,性能反而有所下降 //if (!builder.ContainsKey("Page Size")) builder["Page Size"] = "32768"; // 这两个设置可以让SQLite拥有数十倍的极限性能,但同时又加大了风险,如果系统遭遇突然断电,数据库会出错,而导致系统无法自动恢复 if (!Readonly) { builder.TryAdd("Synchronous", "Off"); } // Journal Mode的内存设置太激进了,容易出事,关闭 //if (!builder.ContainsKey("Journal Mode")) builder["Journal Mode"] = "Memory"; // 数据库中一种高效的日志算法,对于非内存数据库而言,磁盘I/O操作是数据库效率的一大瓶颈。 // 在相同的数据量下,采用WAL日志的数据库系统在事务提交时,磁盘写操作只有传统的回滚日志的一半左右,大大提高了数据库磁盘I/O操作的效率,从而提高了数据库的性能。 if (!Readonly) { builder.TryAdd("Journal Mode", "WAL"); } // 绝大多数情况下,都是小型应用,发生数据损坏的几率微乎其微,而多出来的问题让人觉得很烦,所以还是采用内存设置 // 将来可以增加自动恢复数据的功能 //if (!builder.ContainsKey("Journal Mode")) builder["Journal Mode"] = "Memory"; if (Readonly) { builder.TryAdd("Read Only", "true"); } // 自动清理数据 if (builder.TryGetAndRemove("autoVacuum", out var vac)) { AutoVacuum = vac.ToBoolean(); } } //else // SupportSchema = false; // 默认超时时间 //if (!builder.ContainsKey("Default Timeout")) builder["Default Timeout"] = 5 + ""; // 繁忙超时 //var busy = Setting.Current.CommandTimeout; //if (busy > 0) { // SQLite内部和.Net驱动都有Busy重试机制,多次重试仍然失败,则会出现dabase is locked。通过加大重试次数,减少高峰期出现locked的几率 // 繁忙超时时间。出现Busy时,SQLite内部会在该超时时间内多次尝试 //if (!builder.ContainsKey("BusyTimeout")) builder["BusyTimeout"] = 50 + ""; // 重试次数。SQLite.Net驱动在遇到Busy时会多次尝试,每次随机等待1~150ms //if (!builder.ContainsKey("PrepareRetries")) builder["PrepareRetries"] = 10 + ""; } DAL.WriteLog(builder.ToString()); }
/// <summary>输出日志</summary> /// <param name="format"></param> /// <param name="args"></param> public static void WriteLog(String format, params Object[] args) => DAL.WriteLog(format, args);
/// <summary>根据数据行取得数据表</summary> /// <param name="rows">数据行</param> /// <returns></returns> protected List <IDataTable> GetTables(DataRow[] rows) { //if (_columns == null) _columns = GetSchema(_.Columns, null); //if (_indexes == null) _indexes = GetSchema(_.Indexes, null); //if (_indexColumns == null) _indexColumns = GetSchema(_.IndexColumns, null); if (_columns == null) { try { _columns = GetSchema(_.Columns, null); } catch (Exception ex) { DAL.WriteDebugLog(ex.ToString()); } } if (_indexes == null) { try { _indexes = GetSchema(_.Indexes, null); } catch (Exception ex) { DAL.WriteDebugLog(ex.ToString()); } } if (_indexColumns == null) { try { _indexColumns = GetSchema(_.IndexColumns, null); } catch (Exception ex) { DAL.WriteDebugLog(ex.ToString()); } } try { DAL.WriteDebugLog("GetTables(Rows)- Foreach Start"); List <IDataTable> list = new List <IDataTable>(); foreach (DataRow dr in rows) { #region 基本属性 IDataTable table = DAL.CreateTable(); table.Name = GetDataRowValue <String>(dr, _.TalbeName); // 顺序、编号 Int32 id = 0; if (TryGetDataRowValue <Int32>(dr, "TABLE_ID", out id)) { table.ID = id; } else { table.ID = list.Count + 1; } // 描述 table.Description = GetDataRowValue <String>(dr, "DESCRIPTION"); // 拥有者 table.Owner = GetDataRowValue <String>(dr, "OWNER"); // 是否视图 table.IsView = String.Equals("View", GetDataRowValue <String>(dr, "TABLE_TYPE"), StringComparison.OrdinalIgnoreCase); table.DbType = Database.DbType; #endregion #region 字段及修正 // 字段的获取可能有异常,但不应该影响整体架构的获取 try { var columns = GetFields(table); if (columns != null && columns.Count > 0) { table.Columns.AddRange(columns); } var indexes = GetIndexes(table); if (indexes != null && indexes.Count > 0) { table.Indexes.AddRange(indexes); } // 先修正一次关系数据 table.Fix(); } catch (Exception ex) { if (DAL.Debug) { DAL.WriteLog(ex.ToString()); } } FixTable(table, dr); list.Add(table); #endregion } DAL.WriteDebugLog("GetTables(Rows)- Foreach End"); #region 表间关系处理 //// 某字段名,为另一个表的(表名+单主键名)形式时,作为关联字段处理 //foreach (var table in list) //{ // foreach (var rtable in list) // { // if (table != rtable) table.Connect(rtable); // } //} ModelHelper.Connect(list); //// 因为可能修改了表间关系,再修正一次 //foreach (var table in list) //{ // table.Fix(); //} #endregion return(list); // 不要把这些清空。因为,多线程同时操作的时候,前面的线程有可能把后面线程的数据给清空了 } finally { _columns = null; _indexes = null; _indexColumns = null; } }
/// <summary>输出日志</summary> /// <param name="msg"></param> public static void WriteLog(String msg) => DAL.WriteLog(msg);
/// <summary>获取索引</summary> /// <param name="table"></param> /// <param name="indexes">索引</param> /// <param name="indexColumns">索引列</param> /// <returns></returns> protected virtual List <IDataIndex> GetIndexes(IDataTable table, DataTable indexes, DataTable indexColumns) { if (indexes == null) { return(null); } var drs = indexes.Select(String.Format("{0}='{1}'", _.TalbeName, table.TableName)); if (drs == null || drs.Length < 1) { return(null); } var list = new List <IDataIndex>(); foreach (var dr in drs) { if (!TryGetDataRowValue(dr, _.IndexName, out String name)) { continue; } var di = table.CreateIndex(); di.Name = name; if (TryGetDataRowValue(dr, _.ColumnName, out name) && !String.IsNullOrEmpty(name)) { di.Columns = name.Split(","); } else if (indexColumns != null) { String orderby = null; // Oracle数据库用ColumnPosition,其它数据库用OrdinalPosition if (indexColumns.Columns.Contains(_.OrdinalPosition)) { orderby = _.OrdinalPosition; } else if (indexColumns.Columns.Contains(_.ColumnPosition)) { orderby = _.ColumnPosition; } var dics = indexColumns.Select(String.Format("{0}='{1}' And {2}='{3}'", _.TalbeName, table.TableName, _.IndexName, di.Name), orderby); if (dics != null && dics.Length > 0) { var ns = new List <String>(); foreach (var item in dics) { if (TryGetDataRowValue(item, _.ColumnName, out String dcname) && !dcname.IsNullOrEmpty() && !ns.Contains(dcname)) { ns.Add(dcname); } } if (ns.Count < 1) { DAL.WriteLog("表{0}的索引{1}无法取得字段列表!", table, di.Name); } di.Columns = ns.ToArray(); } } if (TryGetDataRowValue(dr, "UNIQUE", out Boolean b)) { di.Unique = b; } if (TryGetDataRowValue(dr, "PRIMARY", out b)) { di.PrimaryKey = b; } else if (TryGetDataRowValue(dr, "PRIMARY_KEY", out b)) { di.PrimaryKey = b; } FixIndex(di, dr); list.Add(di); } return(list != null && list.Count > 0 ? list : null); }
DataTable GetSchemaInternal(String key, String collectionName, String[] restrictionValues) { QueryTimes++; //// 如果启用了事务保护,这里要新开一个连接,否则MSSQL里面报错,SQLite不报错,其它数据库未测试 //var isTrans = Transaction != null; //DbConnection conn = null; //if (isTrans) //{ // conn = Factory.CreateConnection(); // CheckConnStr(); // conn.ConnectionString = ConnectionString; // conn.Open(); //} //else //{ // if (!Opened) Open(); // conn = Conn; //} //// 连接未打开 //if (conn.State == ConnectionState.Closed) return null; using (var pi = Database.Pool.AcquireItem()) { var conn = pi.Value; //try //{ DataTable dt = null; var sw = Stopwatch.StartNew(); if (restrictionValues == null || restrictionValues.Length < 1) { if (String.IsNullOrEmpty(collectionName)) { WriteSQL("[" + Database.ConnName + "]GetSchema"); dt = conn.GetSchema(); } else { WriteSQL("[" + Database.ConnName + "]GetSchema(\"" + collectionName + "\")"); dt = conn.GetSchema(collectionName); } } else { var sb = new StringBuilder(); foreach (var item in restrictionValues) { sb.Append(", "); if (item == null) { sb.Append("null"); } else { sb.AppendFormat("\"{0}\"", item); } } WriteSQL("[" + Database.ConnName + "]GetSchema(\"" + collectionName + "\"" + sb + ")"); dt = conn.GetSchema(collectionName, restrictionValues); } sw.Stop(); // 耗时超过多少秒输出错误日志 if (sw.ElapsedMilliseconds > 1000) { DAL.WriteLog("GetSchema耗时 {0:n0}ms", sw.ElapsedMilliseconds); } return(dt); //} //catch (DbException ex) //{ // throw new XDbSessionException(this, "取得所有表构架出错!", ex); //} //finally //{ // if (isTrans) // conn.Close(); // else // AutoClose(); //} } }
DataTable GetSchemaInternal(String key, String collectionName, String[] restrictionValues) { QueryTimes++; // 如果启用了事务保护,这里要新开一个连接,否则MSSQL里面报错,SQLite不报错,其它数据库未测试 var isTrans = TransactionCount > 0; DbConnection conn = null; if (isTrans) { conn = Factory.CreateConnection(); checkConnStr(); conn.ConnectionString = ConnectionString; conn.Open(); } else { if (!Opened) { Open(); } conn = Conn; } try { DataTable dt; var sw = new Stopwatch(); sw.Start(); if (restrictionValues == null || restrictionValues.Length < 1) { if (String.IsNullOrEmpty(collectionName)) { WriteSQL("[" + Database.ConnName + "]GetSchema"); if (conn.State != ConnectionState.Closed) //ahuang 2013。06。25 当数据库连接字符串有误 { dt = conn.GetSchema(); } else { dt = null; } } else { WriteSQL("[" + Database.ConnName + "]GetSchema(\"" + collectionName + "\")"); if (conn.State != ConnectionState.Closed) { dt = conn.GetSchema(collectionName); } else { dt = null; } } } else { var sb = new StringBuilder(); foreach (var item in restrictionValues) { sb.Append(", "); if (item == null) { sb.Append("null"); } else { sb.AppendFormat("\"{0}\"", item); } } WriteSQL("[" + Database.ConnName + "]GetSchema(\"" + collectionName + "\"" + sb + ")"); if (conn.State != ConnectionState.Closed) { dt = conn.GetSchema(collectionName, restrictionValues); } else { dt = null; } } sw.Stop(); // 耗时超过多少秒输出错误日志 if (sw.ElapsedMilliseconds > 1000) { DAL.WriteLog("耗时 {0:n0}ms", sw.ElapsedMilliseconds); } return(dt); } catch (DbException ex) { throw new XDbSessionException(this, "取得所有表构架出错!", ex); } finally { if (isTrans) { conn.Close(); } else { AutoClose(); } } }
DataTable GetSchemaInternal(String key, String collectionName, String[] restrictionValues) { QueryTimes++; // 如果启用了事务保护,这里要新开一个连接,否则MSSQL里面报错,SQLite不报错,其它数据库未测试 var isTrans = TransactionCount > 0; DbConnection conn; if (isTrans) { try { conn = Factory.CreateConnection(); conn.ConnectionString = ConnectionString; conn.Open(); } catch (DbException ex) { DAL.WriteLog("错误的连接字符串:{0}", ConnectionString); throw new XDbSessionException(this, "取得所有表构架出错!连接字符串有问题,请查看日志!", ex); } } else { if (!Opened) { Open(); } conn = Conn; } try { DataTable dt; if (restrictionValues == null || restrictionValues.Length < 1) { if (String.IsNullOrEmpty(collectionName)) { WriteSQL("GetSchema"); dt = conn.GetSchema(); } else { WriteSQL("GetSchema(\"" + collectionName + "\")"); dt = conn.GetSchema(collectionName); } } else { var sb = new StringBuilder(); foreach (var item in restrictionValues) { sb.Append(", "); if (item == null) { sb.Append("null"); } else { sb.AppendFormat("\"{0}\"", item); } } WriteSQL("GetSchema(\"" + collectionName + "\"" + sb + ")"); dt = conn.GetSchema(collectionName, restrictionValues); } return(dt); } catch (DbException ex) { throw new XDbSessionException(this, "取得所有表构架出错!", ex); } finally { if (isTrans) { conn.Close(); } else { AutoClose(); } } }