using CsvHelper; using CsvHelper.Configuration; using CsvHelper.TypeConversion; using Newtonsoft.Json; using System; using System.Collections; using System.Collections.Generic; using System.Data.Common; using System.Globalization; using System.IO; using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Web; using System.Xml.Linq; using System.Linq; namespace SqlSugar { /// /// QuestDb RestAPI /// public class QuestDbRestAPI { internal string url = string.Empty; internal string authorization = string.Empty; internal static Random random = new Random(); //can be modified public static int HttpPort { get; set; }= 9000; public static string UserName { get; set; } = null; public static string Password { get; set; } = null; ISqlSugarClient db; public QuestDbRestAPI(ISqlSugarClient db) { var builder = new DbConnectionStringBuilder(); builder.ConnectionString = db.CurrentConnectionConfig.ConnectionString; this.db = db; string host = String.Empty; string username = String.Empty; string password = String.Empty; QuestDbRestAPHelper.SetRestApiInfo(builder, ref host, ref username, ref password); if (!string.IsNullOrEmpty(QuestDbRestAPI.UserName)) { username = QuestDbRestAPI.UserName; } if (!string.IsNullOrEmpty(QuestDbRestAPI.Password)) { password = QuestDbRestAPI.Password; } BindHost(host, username, password); } /// /// 执行SQL异步 /// /// /// public async Task ExecuteCommandAsync(string sql) { //HTTP GET 执行SQL var result = string.Empty; var client = new HttpClient(); var url = $"{this.url}/exec?query={HttpUtility.UrlEncode(sql)}"; if (!string.IsNullOrWhiteSpace(authorization)) client.DefaultRequestHeaders.Add("Authorization", authorization); var httpResponseMessage = await client.GetAsync(url); result = await httpResponseMessage.Content.ReadAsStringAsync(); return result; } /// /// 执行SQL /// /// /// public string ExecuteCommand(string sql) { return ExecuteCommandAsync(sql).GetAwaiter().GetResult(); } public async Task BulkCopyAsync(T insertData, string dateFormat = "yyyy/M/d H:mm:ss") where T:class,new() { if (db.CurrentConnectionConfig.MoreSettings == null) db.CurrentConnectionConfig.MoreSettings = new ConnMoreSettings(); db.CurrentConnectionConfig.MoreSettings.DisableNvarchar = true; var sql= db.Insertable(insertData).ToSqlString(); var result = await ExecuteCommandAsync(sql); return result.ToUpper().Contains("OK")?1:0; } public int BulkCopy(T insertData, string dateFormat = "yyyy/M/d H:mm:ss") where T : class, new() { return BulkCopyAsync(insertData, dateFormat).GetAwaiter().GetResult(); } public QuestDbPageSizeBulkCopy PageSize(int pageSize) { QuestDbPageSizeBulkCopy result = new QuestDbPageSizeBulkCopy(this,pageSize,db); return result; } /// /// 批量快速插入异步 /// /// /// /// 导入时,时间格式 默认:yyyy/M/d H:mm:ss /// public async Task BulkCopyAsync(List insertList, string dateFormat = "yyyy/M/d H:mm:ss") where T : class,new() { if (string.IsNullOrWhiteSpace(url)) { throw new Exception("BulkCopy功能需要启用RestAPI,程序启动时执行:RestAPIExtension.UseQuestDbRestAPI(\"localhost:9000\", \"username\", \"password\")"); } var result = 0; var fileName = $"{Guid.NewGuid()}.csv"; var filePath = Path.Combine(AppContext.BaseDirectory, fileName); try { var client = new HttpClient(); var boundary = "---------------" + DateTime.Now.Ticks.ToString("x"); var list = new List(); var name = db.EntityMaintenance.GetEntityInfo().DbTableName; var key = "QuestDbBulkCopy" + typeof(T).FullName + typeof(T).GetHashCode(); var columns = new ReflectionInoCacheService().GetOrCreate(key, () => db.CopyNew().DbMaintenance.GetColumnInfosByTableName(name)); columns.ForEach(d => { if (d.DataType == "TIMESTAMP") { list.Add(new Hashtable() { { "name", d.DbColumnName }, { "type", d.DataType }, { "pattern", dateFormat} }); } else { list.Add(new Hashtable() { { "name", d.DbColumnName }, { "type", d.DataType } }); } }); var schema = JsonConvert.SerializeObject(list); //写入CSV文件 using (var writer = new StreamWriter(filePath)) using (var csv = new CsvWriter(writer, CultureInfo.CurrentCulture)) { var options = new TypeConverterOptions { Formats = new[] { GetDefaultFormat() } }; csv.Context.TypeConverterOptionsCache.AddOptions(options); CsvCreating(csv); await csv.WriteRecordsAsync(insertList); } var httpContent = new MultipartFormDataContent(boundary); if (!string.IsNullOrWhiteSpace(this.authorization)) client.DefaultRequestHeaders.Add("Authorization", this.authorization); httpContent.Add(new StringContent(schema), "schema"); httpContent.Add(new ByteArrayContent(File.ReadAllBytes(filePath)), "data"); //boundary带双引号 可能导致服务器错误情况 httpContent.Headers.Remove("Content-Type"); httpContent.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data; boundary=" + boundary); var httpResponseMessage = await Post(client, name, httpContent); var readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync(); var splitByLine = QuestDbRestAPHelper.SplitByLine(readAsStringAsync); foreach (var s in splitByLine) { if (s.Contains("Rows")) { var strings = s.Split('|'); if (strings[1].Trim() == "Rows imported") { result = Convert.ToInt32(strings[2].Trim()); } } } } catch (Exception) { throw; } finally { try { File.Delete(filePath); } catch { // ignored } } return result; } private void CsvCreating(CsvWriter csv) where T : class, new() { var entityColumns = db.EntityMaintenance.GetEntityInfo().Columns; if (entityColumns.Any(it => it.IsIgnore||it.UnderType?.IsEnum==true)) { var customMap = new DefaultClassMap(); foreach (var item in entityColumns.Where(it => !it.IsIgnore)) { var memberMap = customMap.Map(typeof(T), item.PropertyInfo).Name(item.PropertyName); if (item.UnderType?.IsEnum==true &&item.SqlParameterDbType==null &&db.CurrentConnectionConfig?.MoreSettings?.TableEnumIsString!=true) { memberMap.TypeConverter(); } } csv.Context.RegisterClassMap(customMap); } } private static string GetDefaultFormat() { return "yyyy-MM-ddTHH:mm:ss.fffffff"; } private Task Post(HttpClient client, string name, MultipartFormDataContent httpContent) { try { return client.PostAsync($"{this.url}/imp?name={name}", httpContent); } catch (Exception) { throw; } } /// /// 批量快速插入 /// /// /// /// 导入时,时间格式 默认:yyyy/M/d H:mm:ss /// public int BulkCopy(List insertList, string dateFormat = "yyyy/M/d H:mm:ss") where T : class,new() { return BulkCopyAsync(insertList, dateFormat).GetAwaiter().GetResult(); } private void BindHost(string host, string username, string password) { url = host + ":"+ HttpPort; if (url.EndsWith("/")) url = url.Remove(url.Length - 1); if (!url.ToLower().StartsWith("http")) url = $"http://{url}"; //生成TOKEN if (!string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password)) { var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}")); authorization = $"Basic {base64}"; } } } }