diff --git a/Src/Asp.NetCore2/DuckDBTest/1_CodeFirst.cs b/Src/Asp.NetCore2/DuckDBTest/1_CodeFirst.cs new file mode 100644 index 000000000..14f37a858 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/1_CodeFirst.cs @@ -0,0 +1,134 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrmTest +{ + /// + /// Class for demonstrating CodeFirst initialization operations + /// 用于展示 CodeFirst 初始化操作的类 + /// + public class _1_CodeFirst + { + + public static void Init() + { + // Get a new database instance + // 获取新的数据库实例 + var db = DbHelper.GetNewDb(); + + // Create the database if it doesn't exist + // 如果数据库不存在,则创建数据库 + db.DbMaintenance.CreateDatabase(); + + // Initialize tables based on UserInfo001 entity class + // 根据 UserInfo001 实体类初始化表 + db.CodeFirst.InitTables(); + + //Table structure and class are different + //表结构和类存在差异 初始化表 + db.CodeFirst.InitTables(); + + //Insert + //插入 + var id=db.Insertable(new UserInfo001() + { + Context = "Context", + Email="dfafa@qq.com", + Price=Convert.ToDecimal(1.1), + UserName="admin", + RegistrationDate=DateTime.Now, + + }).ExecuteReturnIdentity(); + + //Query + //查询 + var userInfo=db.Queryable().InSingle(id); + + //Update + //更新 + db.Updateable(userInfo).ExecuteCommand(); + + //Delete + //删除 + db.Deleteable(userInfo).ExecuteCommand(); + } + + /// + /// User information entity class + /// 用户信息实体类 + /// + public class UserInfo001 + { + /// + /// User ID (Primary Key) + /// 用户ID(主键) + /// + [SugarColumn(IsIdentity = true, IsPrimaryKey = true)] + public int UserId { get; set; } + + /// + /// User name + /// 用户名 + /// + [SugarColumn(Length = 50, IsNullable = false)] + public string UserName { get; set; } + + /// + /// User email + /// 用户邮箱 + /// + [SugarColumn(IsNullable = true)] + public string Email { get; set; } + + + /// + /// Product price + /// 产品价格 + /// + public decimal Price { get; set; } + + /// + /// User context + /// 用户内容 + /// + [SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string Context { get; set; } + + /// + /// User registration date + /// 用户注册日期 + /// + [SugarColumn(IsNullable = true)] + public DateTime? RegistrationDate { get; set; } + } + + + /// + /// User information entity class + /// 用户信息实体类 + /// + [SugarTable("UserInfoAAA01")] + public class UserInfo002 + { + /// + /// User ID (Primary Key) + /// 用户ID(主键) + /// + [SugarColumn(IsIdentity = true,ColumnName ="Id", IsPrimaryKey = true)] + public int UserId { get; set; } + + /// + /// User name + /// 用户名 + /// + [SugarColumn(Length = 50,ColumnName ="Name", IsNullable = false)] + public string UserName { get; set; } + + + } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/2_DbFirst.cs b/Src/Asp.NetCore2/DuckDBTest/2_DbFirst.cs new file mode 100644 index 000000000..a4ba49fc0 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/2_DbFirst.cs @@ -0,0 +1,136 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrmTest +{ + internal class _2_DbFirst + { + /// + /// 初始化方法,包含各种DbFirst操作的演示 + /// Initialization method containing demonstrations of various DbFirst operations + /// + public static void Init() + { + var db = DbHelper.GetNewDb(); + + // 生成干净的实体类文件 + // Generate clean entity class files + Demo1(db); + + // 生成带有SqlSugar特性的实体类文件 + // Generate entity class files with SqlSugar attributes + Demo2(db); + + // 支持字符串类型的Nullable特性 + // Support String Nullable attribute + Demo3(db); + + // 格式化类名、属性名和文件名 + // Format class names, property names, and file names + Demo4(db); + + // 条件过滤生成实体类文件 + // Generate entity class files with condition filtering + Demo5(db); + + // 修改模版生成实体类文件(禁用IsCreateAttribute,避免冲突) + // Generate entity class files with modified templates (disable IsCreateAttribute to avoid conflicts) + Demo6(db); + } + + /// + /// 生成干净的实体类文件 + /// Generate clean entity class files + /// + private static void Demo1(SqlSugarClient db) + { + db.DbFirst.CreateClassFile("c:\\Demo\\1", "Models"); + } + + /// + /// 生成带有SqlSugar特性的实体类文件 + /// Generate entity class files with SqlSugar attributes + /// + private static void Demo2(SqlSugarClient db) + { + db.DbFirst.IsCreateAttribute().CreateClassFile("c:\\Demo\\2", "Models"); + } + + /// + /// 支持字符串类型的Nullable特性 + /// Support String Nullable attribute + /// + private static void Demo3(SqlSugarClient db) + { + db.DbFirst.IsCreateAttribute().StringNullable().CreateClassFile("c:\\Demo\\3", "Models"); + } + + /// + /// 格式化类名、属性名和文件名 + /// Format class names, property names, and file names + /// + private static void Demo4(SqlSugarClient db) + { + db.DbFirst + .IsCreateAttribute() + .FormatFileName(it => "File_" + it) + .FormatClassName(it => "Class_" + it) + .FormatPropertyName(it => "Property_" + it) + .CreateClassFile("c:\\Demo\\4", "Models"); + } + + /// + /// 条件过滤生成实体类文件 + /// Generate entity class files with condition filtering + /// + private static void Demo5(SqlSugarClient db) + { + db.DbFirst.IsCreateAttribute().Where(it => it.ToLower() == "userinfo001").CreateClassFile("c:\\Demo\\5", "Models"); + } + + /// + /// 修改模版生成实体类文件(禁用IsCreateAttribute,避免冲突) + /// Generate entity class files with modified templates (disable IsCreateAttribute to avoid conflicts) + /// + private static void Demo6(SqlSugarClient db) + { + db.DbFirst + // 类 + .SettingClassTemplate(old => { return old;/* 修改old值替换 */ }) + // 类构造函数 + .SettingConstructorTemplate(old => { return old;/* 修改old值替换 */ }) + .SettingNamespaceTemplate(old => + { + return old + "\r\nusing SqlSugar;"; // 追加引用SqlSugar + }) + // 属性备注 + .SettingPropertyDescriptionTemplate(old => { return old;/* 修改old值替换 */}) + + // 属性:新重载 完全自定义用配置 + .SettingPropertyTemplate((columns, temp, type) => + { + + var columnattribute = "\r\n [SugarColumn({0})]"; + List attributes = new List(); + if (columns.IsPrimarykey) + attributes.Add("IsPrimaryKey=true"); + if (columns.IsIdentity) + attributes.Add("IsIdentity=true"); + if (attributes.Count == 0) + { + columnattribute = ""; + } + return temp.Replace("{PropertyType}", type) + .Replace("{PropertyName}", columns.DbColumnName) + .Replace("{SugarColumn}", string.Format(columnattribute, string.Join(",", attributes))); + }) + + .CreateClassFile("c:\\Demo\\6"); + } + } +} + \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/3_EasyQuery.cs b/Src/Asp.NetCore2/DuckDBTest/3_EasyQuery.cs new file mode 100644 index 000000000..b4544bab0 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/3_EasyQuery.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SqlSugar; + +namespace OrmTest +{ + internal class _3_EasyQuery + { + /// + /// 初始化方法,包含各种查询操作的演示 + /// Initialization method containing demonstrations of various query operations + /// + public static void Init() + { + // 创建表并插入一条记录 + // Create table and insert a record + CreateTable(); + + // 查询所有学生信息 + // Query all student records + GetAllStudents(); + + // 查询学生总数 + // Get the total count of students + GetStudentCount(); + + // 按条件查询学生信息 + // Query student records based on conditions + GetStudentsByCondition(); + + // 模糊查询学生信息(名字包含"jack"的学生) + // Fuzzy search for student records (students with names containing "jack") + GetStudentsByName("jack"); + + // 根据学生ID查询单个学生 + // Query a single student by student ID + GetStudentById(1); + + // 获取Student03表中的最大Id + // Get the maximum ID from the Student03 table + GetMaxStudentId(); + + // 简单排序(按照Id降序排序) + // Simple sorting (sorting by Id in descending order) + GetStudentsOrderedByIdDesc(); + + // 查询学生姓名列表 + // Query the list of student names + GetStudentNames(); + } + + /// + /// 创建表并插入一条记录 + /// Create table and insert a record + /// + private static void CreateTable() + { + SqlSugarClient db = DbHelper.GetNewDb(); + db.CodeFirst.InitTables(); + db.Insertable(new Student03() { Name = "name" + SnowFlakeSingle.Instance.NextId() }) + .ExecuteCommand(); + } + + /// + /// 查询所有学生信息 + /// Query all student records + /// + private static void GetAllStudents() + { + SqlSugarClient db = DbHelper.GetNewDb(); + var students = db.Queryable().ToList(); + // 处理查询结果 + // Process the query results + } + + /// + /// 查询学生总数 + /// Get the total count of students + /// + private static void GetStudentCount() + { + SqlSugarClient db = DbHelper.GetNewDb(); + var count = db.Queryable().Count(); + // 处理查询结果 + // Process the query results + } + + /// + /// 按条件查询学生信息 + /// Query student records based on conditions + /// + private static void GetStudentsByCondition() + { + SqlSugarClient db = DbHelper.GetNewDb(); + + // 查询name字段不为null的学生 + // Query students where the 'name' field is not null + var studentsWithNameNotNull = db.Queryable().Where(it => it.Name != null).ToList(); + + // 查询name字段为null的学生 + // Query students where the 'name' field is null + var studentsWithNameNull = db.Queryable().Where(it => it.Name == null).ToList(); + + // 查询name字段不为空的学生 + // Query students where the 'name' field is not empty + var studentsWithNameNotEmpty = db.Queryable().Where(it => it.Name != "").ToList(); + + // 多条件查询 + // Query students with multiple conditions + var studentsWithMultipleConditions = db.Queryable().Where(it => it.Id > 10 && it.Name == "a").ToList(); + + // 动态OR查询 + // Dynamic OR query + var exp = Expressionable.Create(); + exp.OrIF(true, it => it.Id == 1); + exp.Or(it => it.Name.Contains("jack")); + var studentsWithDynamicOr = db.Queryable().Where(exp.ToExpression()).ToList(); + + } + + /// + /// 模糊查询学生信息 + /// Fuzzy search for student records + /// + private static void GetStudentsByName(string keyword) + { + SqlSugarClient db = DbHelper.GetNewDb(); + var students = db.Queryable().Where(it => it.Name.Contains(keyword)).ToList(); + // 处理查询结果 + // Process the query results + } + + /// + /// 根据学生ID查询单个学生 + /// Query a single student by student ID + /// + private static void GetStudentById(int id) + { + SqlSugarClient db = DbHelper.GetNewDb(); + var student = db.Queryable().Single(it => it.Id == id); + // 处理查询结果 + // Process the query results + } + + /// + /// 获取Student03表中的最大Id + /// Get the maximum ID from the Student03 table + /// + private static void GetMaxStudentId() + { + SqlSugarClient db = DbHelper.GetNewDb(); + var maxId = db.Queryable().Max(it => it.Id); + // 处理查询结果 + // Process the query results + } + + /// + /// 简单排序(按照Id降序排序) + /// Simple sorting (sorting by Id in descending order) + /// + private static void GetStudentsOrderedByIdDesc() + { + SqlSugarClient db = DbHelper.GetNewDb(); + var students = db.Queryable().OrderBy(sc => sc.Id, OrderByType.Desc).ToList(); + // 处理查询结果 + // Process the query results + } + + /// + /// 查询学生姓名列表 + /// Query the list of student names + /// + private static void GetStudentNames() + { + SqlSugarClient db = DbHelper.GetNewDb(); + var studentNames = db.Queryable().Select(it => it.Name).ToList(); + // 处理查询结果 + // Process the query results + } + + public class Student03 + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + public string Name { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/4_JoinQuery.cs b/Src/Asp.NetCore2/DuckDBTest/4_JoinQuery.cs new file mode 100644 index 000000000..979152df8 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/4_JoinQuery.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static OrmTest._4_JoinQuery; + +namespace OrmTest +{ + internal class _4_JoinQuery + { + public static void Init() + { + InitializeDatabase(); + SyntaxSugar1(); + SyntaxSugar2(); + SyntaxSugar3(); + } + /// + /// 使用语法糖1进行联表查询。 + /// Performs a Join query using Syntax Sugar 1. + /// + /// 查询结果列表。The list of query results. + public static List SyntaxSugar1() + { + var db = DbHelper.GetNewDb(); + var query = db.Queryable() + .LeftJoin((o, cus) => o.CustomId == cus.Id) + .LeftJoin((o, cus, oritem) => o.Id == oritem.OrderId) + .Where(o => o.Id == 1) + .Select((o, cus, oritem) => new ViewOrder2 { Id = o.Id,Name=o.Name, CustomName = cus.Name }) + .ToList(); + + return query; + } + + /// + /// 使用语法糖2进行联表查询。 + /// Performs a Join query using Syntax Sugar 2. + /// + /// 查询结果列表。The list of query results. + public static List SyntaxSugar2() + { + var db = DbHelper.GetNewDb(); + var rightQueryable = db.Queryable() + .LeftJoin((o, i) => o.Id == i.Id) + .Select(o => o); + + var list = db.Queryable() + .LeftJoin(rightQueryable, (c, j) => c.CustomId == j.Id) + .Select(c => c) + .ToList(); + return list; + } + + /// + /// 使用语法糖3进行联表查询。 + /// Performs a Join query using Syntax Sugar 3. + /// + /// 查询结果列表。The list of query results. + public static List SyntaxSugar3() + { + var db = DbHelper.GetNewDb(); + var list = db.Queryable((o, i, c) => o.Id == i.OrderId && c.Id == o.CustomId) + .Select((o, i, c) => new ViewOrder2 { Id = o.Id, Name = o.Name, CustomName = c.Name }) + .ToList(); + + return list; + } + + + static void InitializeDatabase() + { + // Initialize order data + // 初始化订单数据 + var orders = new List + { + new Order { Id = 1, Name = "Order 1", CustomId = 1 }, + new Order { Id = 2, Name = "Order 2", CustomId = 2 }, + new Order { Id = 3, Name = "Order 3", CustomId = 1 }, + }; + + // Initialize order details data + // 初始化订单详情数据 + var orderDetails = new List + { + new OrderDetail { Id = 1, OrderId = 1 }, + new OrderDetail { Id = 2, OrderId = 2 }, + new OrderDetail { Id = 3, OrderId = 3 }, + }; + + // Initialize customer data + // 初始化客户数据 + var customers = new List + { + new Custom { Id = 1, Name = "Customer 1" }, + new Custom { Id = 2, Name = "Customer 2" }, + new Custom { Id = 3, Name = "Customer 3" }, + }; + + // Get database connection + // 获取数据库连接 + var db = DbHelper.GetNewDb(); + + // Initialize database tables and truncate data + // 初始化数据库表并清空数据 + db.CodeFirst.InitTables(); + db.DbMaintenance.TruncateTable(); + + // Insert data into tables + // 向表中插入数据 + db.Insertable(orders).ExecuteCommand(); + db.Insertable(orderDetails).ExecuteCommand(); + db.Insertable(customers).ExecuteCommand(); + } + + /// + /// 订单实体类。 + /// Order entity class. + /// + [SqlSugar.SugarTable("Order04")] + public class Order + { + [SqlSugar.SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + public string Name { get; set; } + public int CustomId { get; set; } + // 其他订单相关属性... + } + + /// + /// 订单详情实体类。 + /// Order detail entity class. + /// + [SqlSugar.SugarTable("OrderDetail04")] + public class OrderDetail + { + [SqlSugar.SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + public int OrderId { get; set; } + // 其他订单详情相关属性... + } + + /// + /// 客户实体类。 + /// Customer entity class. + /// + [SqlSugar.SugarTable("Custom04")] + public class Custom + { + [SqlSugar.SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + public string Name { get; set; } + // 其他客户相关属性... + } + + + + /// + /// 类1实体类。 + /// Class1 entity class. + /// + public class ViewOrder2 + { + public int Id { get; set; } + public string Name { get; set; } + public string CustomName { get; set; } + // 其他类1相关属性... + } + } +} diff --git a/Src/Asp.NetCore2/DuckDBTest/4_Subquery.cs b/Src/Asp.NetCore2/DuckDBTest/4_Subquery.cs new file mode 100644 index 000000000..56c6e9956 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/4_Subquery.cs @@ -0,0 +1,68 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrmTest +{ + public class _4_Subquery + { + public static void Init() + { + + var db = DbHelper.GetNewDb(); + + db.CodeFirst.InitTables(); + db.DbMaintenance.TruncateTable(); + + db.Insertable(new Student() { Id = 1, SchoolId = 1 }).ExecuteCommand(); + db.Insertable(new School() { Id = 1, Name = "Harvard School" }).ExecuteCommand(); + db.Insertable(new Student() { Id = 2, SchoolId = 2 }).ExecuteCommand(); + db.Insertable(new School() { Id = 2, Name = "haha School" }).ExecuteCommand(); + + //subquery select + var result = db.Queryable() + .Select(st => new + { + SchoolName = SqlFunc.Subqueryable().Where(s => s.Id == st.SchoolId).Select(s => s.Name), + MaxSchoolId = SqlFunc.Subqueryable().Where(s => s.Id == st.SchoolId).Select(s => SqlFunc.AggregateMax(s.Id)), + MaxSchoolId2 = SqlFunc.Subqueryable().Where(s => s.Id == st.SchoolId).Max(s => s.Id), + }) + .ToList(); + + //Exists: + //SELECT [Id],[SchoolId] FROM [Student0402] [it] WHERE (EXISTS ( SELECT * FROM [School0402] [s] WHERE ( [Id] = [it].[SchoolId] ) )) + var result2 = db.Queryable() + .Where(it => SqlFunc.Subqueryable().Where(s => s.Id == it.SchoolId).Any()) + .ToList(); + + //In: + //SELECT [Id],[SchoolId] FROM [Student0402] [it] WHERE [Id] in (SELECT [Id] FROM [School0402] [s] GROUP BY [Id]) + var result3 = db.Queryable() + .Where(it => it.Id == SqlFunc.Subqueryable().GroupBy(s => s.Id).Select(s => s.Id)) + .ToList(); + + //Equal: + //SELECT [Id],[SchoolId] FROM [Student0402] [it] WHERE ( [Id] =(SELECT TOP 1 [s].[Id] FROM [School0402] [s] )) + var result4 = db.Queryable() + .Where(it => it.Id == SqlFunc.Subqueryable().Select(s => s.Id)) + .ToList(); + } + + [SugarTable("Student0402")] + public class Student + { + public int Id { get; set; } + public int SchoolId { get; set; } + } + [SugarTable("School0402")] + public class School + { + public int Id { get; set; } + public string Name { get; set; } + } + + } +} diff --git a/Src/Asp.NetCore2/DuckDBTest/5_PageQuery.cs b/Src/Asp.NetCore2/DuckDBTest/5_PageQuery.cs new file mode 100644 index 000000000..fba71c6f7 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/5_PageQuery.cs @@ -0,0 +1,112 @@ +using OrmTest; +using SqlSugar; +using System; +using System.Linq; +using System.Threading.Tasks; + +public class _5_PageQuery +{ + public static void Init() + { + + int pagenumber = 1; + int pageSize = 20; + int totalCount = 0; + + SqlSugarClient db = DbHelper.GetNewDb(); + + //建表 + //Create table + AddTestData(db); + + // 同步分页方法 + // Synchronous pagination method + SyncPagination(db, pagenumber, pageSize, ref totalCount); + + // 异步分页方法 + // Asynchronous pagination method + AsyncPagination(db, pagenumber, pageSize) .GetAwaiter() .GetResult(); + } + + public static void AddTestData(SqlSugarClient db) + { + + //建表 + //Create table + db.CodeFirst.InitTables(); + + // 添加学校数据 + // Add school data + var school1 = new School { Name = "School A" }; + var school2 = new School { Name = "School B" }; + db.Insertable(school1).ExecuteCommand(); + db.Insertable(school2).ExecuteCommand(); + + // 添加学生数据 + // Add student data + var student1 = new Student { SchoolId = school1.Id, Name = "John", CreateTime = DateTime.Now }; + var student2 = new Student { SchoolId = school1.Id, Name = "Alice", CreateTime = DateTime.Now }; + + db.Insertable(student1).ExecuteCommand(); + db.Insertable(student2).ExecuteCommand(); + + Console.WriteLine("Test data added successfully."); + } + + /// + /// 同步分页示例 + /// Synchronous pagination example + /// + /// 数据库连接对象 Database connection object + /// 页码 Page number + /// 每页大小 Page size + /// 总记录数 Total record count + public static void SyncPagination(SqlSugarClient db, int pagenumber, int pageSize, ref int totalCount) + { + // 同步单表分页 + // Synchronous pagination for a single table + var page = db.Queryable().ToPageList(pagenumber, pageSize, ref totalCount); + + // 同步多表分页 + // Synchronous pagination for multiple tables + var list = db.Queryable().LeftJoin((st, sc) => st.SchoolId == sc.Id) + .Select((st, sc) => new { Id = st.Id, Name = st.Name, SchoolName = sc.Name }) + .ToPageList(pagenumber, pageSize, ref totalCount); + + // offset分页 + // offset pagination + var sqlServerPage = db.Queryable().ToOffsetPage(pagenumber, pageSize); + + } + + /// + /// 异步分页示例 + /// Asynchronous pagination example + /// + /// 数据库连接对象 Database connection object + /// 页码 Page number + /// 每页大小 Page size + public static async Task AsyncPagination(SqlSugarClient db, int pagenumber, int pageSize) + { + RefAsync total = 0; + // 异步分页 + // Asynchronous pagination + var orders = await db.Queryable().ToPageListAsync(pagenumber, pageSize, total); + } + [SugarTable("Student05")] + public class Student + { + [SugarColumn(IsIdentity =true,IsPrimaryKey =true)] + public int Id { get; set; } + public int SchoolId { get; set; } + public string Name { get; set; } + public DateTime CreateTime { get; set; } + } + [SugarTable("School05")] + public class School + { + [SugarColumn(IsIdentity = true, IsPrimaryKey = true)] + public int Id { get; set; } + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/6_NavigationPropertyQuery.cs b/Src/Asp.NetCore2/DuckDBTest/6_NavigationPropertyQuery.cs new file mode 100644 index 000000000..6dec5075e --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/6_NavigationPropertyQuery.cs @@ -0,0 +1,268 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrmTest +{ + internal class _6_NavQuery + { + /// + /// Initialize navigation query examples. + /// 初始化导航查询示例。 + /// + public static void Init() + { + var db = DbHelper.GetNewDb(); + + // Initialize database table structures. + // 初始化数据库表结构。 + InitializeDatabase(db); + + // One-to-One navigation query test. + // 一对一导航查询测试。 + OneToOneTest(db); + + // One-to-Many navigation query test. + // 一对多导航查询测试。 + OneToManyTest(db); + + // Many-to-Many navigation query test. + // 多对多导航查询测试。 + ManyToManyTest(db); + } + + /// + /// Test many-to-many navigation queries. + /// 测试多对多导航查询。 + /// + private static void ManyToManyTest(SqlSugarClient db) + { + // Many-to-many navigation query, query table A and include its BList. + // 多对多导航查询,查询A表,并包含其BList。 + var list4 = db.Queryable().Includes(it => it.BList).ToList(); + + // Many-to-many navigation query with filtered BList while preserving the original A records, regardless of the filter on BList. + // 使用过滤条件的多对多导航查询,在过滤BList的同时保持A表的原始记录,不受BList过滤条件的影响。 + var list5 = db.Queryable().Includes(it => it.BList.Where(s => s.BId == 1).ToList()).ToList(); + + // Many-to-many navigation query with filtered A records while preserving the original BList, regardless of the filter on A records. + // 使用过滤条件的多对多导航查询,在过滤A表的同时保持BList的原始记录,不受A表过滤条件的影响。 + var list6 = db.Queryable().Includes(it => it.BList) + .Where(it =>it.BList.Any(s => s.BId == 1)).ToList(); + + // Many-to-many navigation query with filtered BList and filtered A records, but not preserving the original A and B records. + // 使用过滤条件的多对多导航查询,在A表中过滤BList并过滤A记录,但不保持A表和B表的原始记录。 + var list7 = db.Queryable() + .Includes(it => it.BList.Where(s => s.BId == 1).ToList()) + .Where(it => it.BList.Any(s => s.BId == 1)).ToList(); + } + + /// + /// Test one-to-many navigation queries. + /// 测试一对多导航查询。 + /// + private static void OneToManyTest(SqlSugarClient db) + { + // One-to-many navigation query, query table Student and include its Books. + // 一对多导航查询,查询Student表,并包含其Books。 + var list4 = db.Queryable().Includes(it => it.Books).ToList(); + + // One-to-many navigation query with filtered Books while preserving the original Student records, regardless of the filter on Books. + // 使用过滤条件的一对多导航查询,在过滤Books的同时保持Student表的原始记录,不受Books过滤条件的影响。 + var list5 = db.Queryable().Includes(it => it.Books.Where(s => s.BookId == 1).ToList()).ToList(); + + // One-to-many navigation query with filtered Student records while preserving the original Books, regardless of the filter on Student records. + // 使用过滤条件的一对多导航查询,在过滤Student表的同时保持Books的原始记录,不受Student表过滤条件的影响。 + var list6 = db.Queryable().Includes(it => it.Books) + .Where(it => it.Books.Any(s => s.BookId == 1)).ToList(); + + // One-to-many navigation query with filtered Books and filtered Student records, but not preserving the original Student and Books records. + // 使用过滤条件的一对多导航查询,在Student表中过滤Books并过滤Student记录,但不保持Student表和Books表的原始记录。 + var list7 = db.Queryable() + .Includes(it => it.Books.Where(s => s.BookId == 1).ToList()) + .Where(it => it.Books.Any(s => s.BookId == 1)).ToList(); + } + + /// + /// Test one-to-one navigation queries. + /// 测试一对一导航查询。 + /// + private static void OneToOneTest(SqlSugarClient db) + { + // One-to-one navigation query with condition, query table Student and include its associated School with specific SchoolId. + // 带条件的一对一导航查询,查询Student表,并包含其关联的School表,条件为特定的SchoolId。 + var list = db.Queryable() + .Where(it => it.School.SchoolId == 1) + .ToList(); + + // Inner join navigation query, query table Student and include its associated School. + // 内连接导航查询,查询Student表,并包含其关联的School表。 + var list2 = db.Queryable().IncludeInnerJoin(it => it.School) + .ToList(); + + // Includes navigation query, query table Student and include its associated School. + // 包含导航查询,查询Student表,并包含其关联的School表。 + var list3 = db.Queryable().Includes(it => it.School).ToList(); + } + + /// + /// Initialize database tables and insert sample data for navigation query examples. + /// 初始化导航查询示例的数据库表并插入示例数据。 + /// + private static void InitializeDatabase(SqlSugarClient db) + { + // Initialize and truncate tables for Student, School, and Book entities. + // 初始化并清空Student、School和Book表。 + db.CodeFirst.InitTables(); + db.DbMaintenance.TruncateTable(); + + // Sample data for Student, School, and Book entities. + // Student、School和Book表的示例数据。 + var students = new List + { + new Student + { + Name = "Student 1", + SexCode = "M", + School = new School { SchoolName = "School 1" }, + Books = new List + { + new Book { Name = "Book 1" }, + new Book { Name = "Book 2" } + } + }, + new Student + { + Name = "Student 2", + SexCode = "F", + School = new School { SchoolName = "School 2" }, + Books = new List + { + new Book { Name = "Book 3" } + } + } + }; + + // Insert sample data for Student, School, and Book entities using navigation properties. + // 使用导航属性插入Student、School和Book表的示例数据。 + db.InsertNav(students) + .Include(it => it.School) + .Include(it => it.Books).ExecuteCommand(); + + // Initialize and truncate tables for A, B, and ABMapping entities. + // 初始化并清空A、B和ABMapping表。 + db.CodeFirst.InitTables(); + db.DbMaintenance.TruncateTable(); + + // Sample data for A, B, and ABMapping entities. + // A、B和ABMapping表的示例数据。 + List a1 = new List { new A() { Name = "A1" }, new A() { Name = "A2" } }; + B b1 = new B { Name = "B1" }; + B b2 = new B { Name = "B2" }; + a1[0].BList = new List { b1, b2 }; + + // Insert sample data for A, B, and ABMapping entities using navigation properties. + // 使用导航属性插入A、B和ABMapping表的示例数据。 + db.InsertNav(a1).Include(x => x.BList).ExecuteCommand(); + } + + /// + /// Student entity representing the Student table in the database. + /// 表示数据库中Student表的Student实体类。 + /// + [SugarTable("Student06")] + public class Student + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int StudentId { get; set; } + public string Name { get; set; } + public string SexCode { get; set; } + public int SchoolId { get; set; } + + // One-to-One navigation property to School entity. + // 与School实体的一对一导航属性。 + [Navigate(NavigateType.OneToOne, nameof(SchoolId))] + public School School { get; set; } + + // One-to-Many navigation property to Book entities. + // 与Book实体的一对多导航属性。 + [Navigate(NavigateType.OneToMany, nameof(Book.StudentId))] + public List Books { get; set; } + } + + /// + /// School entity representing the School table in the database. + /// 表示数据库中School表的School实体类。 + /// + [SugarTable("School06")] + public class School + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int SchoolId { get; set; } + public string SchoolName { get; set; } + } + + /// + /// Book entity representing the Book table in the database. + /// 表示数据库中Book表的Book实体类。 + /// + [SugarTable("Book06")] + public class Book + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int BookId { get; set; } + public string Name { get; set; } + public int StudentId { get; set; } + } + + /// + /// A entity representing the A table in the database for many-to-many relationship. + /// 表示多对多关系中数据库中A表的A实体类。 + /// + [SugarTable("A06")] + public class A + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int AId { get; set; } + public string Name { get; set; } + + // Many-to-Many navigation property to B entities using ABMapping table. + // 与B实体的多对多导航属性,使用ABMapping表。 + [Navigate(typeof(ABMapping), nameof(ABMapping.AId), nameof(ABMapping.BId))] + public List BList { get; set; } + } + + /// + /// B entity representing the B table in the database for many-to-many relationship. + /// 表示多对多关系中数据库中B表的B实体类。 + /// + [SugarTable("B06")] + public class B + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int BId { get; set; } + public string Name { get; set; } + + // Many-to-Many navigation property to A entities using ABMapping table. + // 与A实体的多对多导航属性,使用ABMapping表。 + [Navigate(typeof(ABMapping), nameof(ABMapping.BId), nameof(ABMapping.AId))] + public List AList { get; set; } + } + + /// + /// ABMapping entity representing the intermediate table for many-to-many relationship between A and B entities. + /// 表示A和B实体之间多对多关系的中间表的ABMapping实体类。 + /// + [SugarTable("ABMapping06")] + public class ABMapping + { + [SugarColumn(IsPrimaryKey = true)] + public int AId { get; set; } + [SugarColumn(IsPrimaryKey = true)] + public int BId { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/7_GroupQuery.cs b/Src/Asp.NetCore2/DuckDBTest/7_GroupQuery.cs new file mode 100644 index 000000000..6eabe8d54 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/7_GroupQuery.cs @@ -0,0 +1,74 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrmTest +{ + internal class _7_GroupQuery + { + public static void Init() + { + var db = DbHelper.GetNewDb(); + List students = new List + { + new Student { Id = 1, Name = "Alice", Age = 20 }, + new Student { Id = 2, Name = "Bob", Age = 22 }, + new Student { Id = 3, Name = "Alice", Age = 21 }, + new Student { Id = 4, Name = "Charlie", Age = 19 }, + new Student { Id = 5, Name = "Bob", Age = 20 } + }; + + // 初始化数据库表结构,如果表不存在则创建 (Initialize database table structure; create if not exists) + db.CodeFirst.InitTables(); + + // 清空指定表中的所有数据 (Truncate all data in the specified table) + db.DbMaintenance.TruncateTable(); + + //插入记录(Insert datas) + db.Insertable(students).ExecuteCommand(); + + // 分组查询示例 (Grouping Query Example) + var groupedStudents = db.Queryable() + .GroupBy(s => s.Name) + .Select(g => new + { + Name = g.Name, // 学生姓名 (Student Name) + Count = SqlFunc.AggregateCount(g.Id), // 学生数量 (Count of Students) + AverageAge = SqlFunc.AggregateAvg(g.Age), // 平均年龄 (Average Age) + MaxAge = SqlFunc.AggregateMax(g.Age), // 最大年龄 (Maximum Age) + MinAge = SqlFunc.AggregateMin(g.Age) // 最小年龄 (Minimum Age) + }) + .ToList(); + + + // 去重查询示例 (Distinct Query Example) + var distinctNames = students.Select(s => s.Name).Distinct().ToList(); + + + // 分组取第一条记录示例 (Group First Record Example) + var groupFirstRecord = db.Queryable() + .Select(g => new + { + index = SqlFunc.RowNumber(SqlFunc.Desc(g.Id), g.Name), + Id = g.Id, + Name = g.Name, + Age =g.Age + }) + .MergeTable() + .Where(it => it.index == 1) + .ToList(); + } + + [SqlSugar.SugarTable("Student07")] + public class Student + { + [SqlSugar.SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } // 学生ID (Student ID) + public string Name { get; set; } // 学生姓名 (Student Name) + public int Age { get; set; } // 学生年龄 (Student Age) + } + } +} diff --git a/Src/Asp.NetCore2/DuckDBTest/8_Insert.cs b/Src/Asp.NetCore2/DuckDBTest/8_Insert.cs new file mode 100644 index 000000000..591a435f9 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/8_Insert.cs @@ -0,0 +1,66 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrmTest +{ + internal class _8_Insert + { + public static void Init() + { + var db = DbHelper.GetNewDb(); + + // 初始化实体表格(Initialize entity tables) + db.CodeFirst.InitTables(); + + // Use Case 1: 返回插入行数(Return the number of inserted rows) + var rowCount = db.Insertable(new StudentWithIdentity() { Name = "name" }).ExecuteCommand(); + + // Use Case 2: 插入数据并返回自增列(Insert data and return the auto-incremented column) + var identity = db.Insertable(new StudentWithIdentity() { Name = "name2" }).ExecuteReturnIdentity(); + + // Use Case 3: 返回雪花ID(Return the snowflake ID) + var snowflakeId = db.Insertable(new StudentWithSnowflake() { Name = "name" }).ExecuteReturnSnowflakeId(); + + // Use Case 4: 强制设置表名别名(Forcefully set table name alias) + db.Insertable(new StudentWithIdentity() { Name = "name2" }).AS("StudentWithIdentity").ExecuteCommand(); + + // Use Case 5: 批量插入实体(非参数化插入)(Batch insert entities (non-parameterized)) + var list = db.Queryable().Take(2).ToList(); + db.Insertable(list).ExecuteCommand(); + db.Insertable(list).PageSize(1000).ExecuteCommand(); + + // Use Case 6: 参数化内部分页插入(Parameterized internal pagination insert) + db.Insertable(list).UseParameter().ExecuteCommand(); + + // Use Case 7: 大数据写入(示例代码,请根据实际情况调整)(Bulk data insertion - Example code, adjust based on actual scenario) + var listLong = new List() { + new StudentWithSnowflake() { Name = "name",Id=SnowFlakeSingle.Instance.NextId() }, + new StudentWithSnowflake() { Name = "name",Id=SnowFlakeSingle.Instance.NextId()} + }; + db.Fastest().BulkCopy(listLong); + } + + // 实体类:带自增主键(Entity class: With auto-increment primary key) + [SugarTable("StudentWithIdentity08")] + public class StudentWithIdentity + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + public string Name { get; set; } + } + + // 实体类:带雪花主键(Entity class: With snowflake primary key) + [SugarTable("StudentWithSnowflake08")] + public class StudentWithSnowflake + { + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + public string Name { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/9_Update.cs b/Src/Asp.NetCore2/DuckDBTest/9_Update.cs new file mode 100644 index 000000000..dc4d0349e --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/9_Update.cs @@ -0,0 +1,88 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static OrmTest._8_Insert; + +namespace OrmTest +{ + internal class _9_Update + { + /// + /// 初始化更新方法(Initialize update methods) + /// + internal static void Init() + { + var db = DbHelper.GetNewDb(); + + // 初始化实体表格(Initialize entity tables) + db.CodeFirst.InitTables(); + + // 创建一个需要更新的实体对象(Create an entity object to be updated) + var updateObj = new StudentWithSnowflake() { Id = 1, Name = "order1" }; + + // 创建需要批量更新的实体对象列表(Create a list of entity objects to be updated in bulk) + var updateObjs = new List { + new StudentWithSnowflake() { Id = 11, Name = "order11", Date=DateTime.Now }, + new StudentWithSnowflake() { Id = 12, Name = "order12", Date=DateTime.Now } + }; + + /***************************根据实体更新 (Update based on entity)***************************/ + + // 更新单个实体对象(Update a single entity object) + var result = db.Updateable(updateObj).ExecuteCommand(); + + // 批量更新实体对象列表(Update a list of entity objects in bulk) + var result20 = db.Updateable(updateObjs).ExecuteCommand(); + var result21 = db.Updateable(updateObjs).PageSize(500).ExecuteCommand(); + + // 更新实体对象,忽略指定列(Update entity object, ignoring specific columns) + var result3 = db.Updateable(updateObj).IgnoreColumns(it => new { it.Remark }).ExecuteCommand(); + + // 更新实体对象的指定列(Update specific columns of the entity object) + var result4 = db.Updateable(updateObj).UpdateColumns(it => new { it.Name, it.Date }).ExecuteCommand(); + + // 如果没有主键,按照指定列更新实体对象(If there is no primary key, update entity object based on specified columns) + var result5 = db.Updateable(updateObj).WhereColumns(it => new { it.Id }).ExecuteCommand(); + + // 如果字段值为NULL,不进行更新(Do not update columns with NULL values) + var result6 = db.Updateable(updateObj).IgnoreNullColumns().ExecuteCommand(); + + // 忽略为NULL和默认值的列进行更新(Ignore columns with NULL and default values during update) + var result7 = db.Updateable(updateObj) + .IgnoreColumns(ignoreAllNullColumns: true, ignoreAllDefaultValue:true) + .ExecuteCommand(); + + // 使用最快的方式批量更新实体对象列表(Bulk update a list of entity objects using the fastest method) + var result8 = db.Fastest().BulkUpdate(updateObjs); + + /***************************表达式更新 (Expression Update)***************************/ + + // 使用表达式更新实体对象的指定列(Update specific columns of the entity object using expressions) + var result71 = db.Updateable() + .SetColumns(it => new StudentWithSnowflake() { Name = "a", Date = DateTime.Now }) + .Where(it => it.Id == 11) + .ExecuteCommand(); + + // 使用表达式更新实体对象的指定列(Update specific columns of the entity object using expressions) + var result81 = db.Updateable() + .SetColumns(it => it.Name == "Name" + "1") + .Where(it => it.Id == 1) + .ExecuteCommand(); + } + + // 实体类:带雪花主键(Entity class: With snowflake primary key) + [SugarTable("StudentWithSnowflake09")] + public class StudentWithSnowflake + { + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + public string Name { get; set; } + public DateTime Date { get; set; } + [SugarColumn(IsNullable = true)] + public string Remark { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/DuckDBTest.csproj b/Src/Asp.NetCore2/DuckDBTest/DuckDBTest.csproj new file mode 100644 index 000000000..6a2ac3e66 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/DuckDBTest.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + enable + Exe + + + + + + + diff --git a/Src/Asp.NetCore2/DuckDBTest/Program.cs b/Src/Asp.NetCore2/DuckDBTest/Program.cs new file mode 100644 index 000000000..81a0814d1 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/Program.cs @@ -0,0 +1,40 @@ +using SqlSugar; + +Console.Read(); +/// +/// Helper class for database operations +/// 数据库操作的辅助类 +/// +public class DbHelper +{ + /// + /// Database connection string + /// 数据库连接字符串 + /// + public readonly static string Connection = "DataSource = train_services.db"; + + /// + /// Get a new SqlSugarClient instance with specific configurations + /// 获取具有特定配置的新 SqlSugarClient 实例 + /// + /// SqlSugarClient instance + public static SqlSugarClient GetNewDb() + { + var db = new SqlSugarClient(new ConnectionConfig() + { + IsAutoCloseConnection = true, + DbType = DbType.DuckDB, + ConnectionString = Connection, + LanguageType = LanguageType.Default//Set language + + }, + it => { + // Logging SQL statements and parameters before execution + // 在执行前记录 SQL 语句和参数 + it.Aop.OnLogExecuting = (sql, para) => + { + Console.WriteLine(UtilMethods.GetNativeSql(sql, para)); + }; + }); + return db; + } \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/a1_Delete.cs b/Src/Asp.NetCore2/DuckDBTest/a1_Delete.cs new file mode 100644 index 000000000..03b37ce43 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/a1_Delete.cs @@ -0,0 +1,186 @@ +using SqlSugar; +using System.Collections.Generic; + +namespace OrmTest +{ + internal class _a1_Delete + { + /// + /// 初始化删除操作的示例方法。 + /// Initializes example methods for delete operations. + /// + internal static void Init() + { + // 获取新的数据库连接对象 + // Get a new database connection object + var db = DbHelper.GetNewDb(); + + db.CodeFirst.InitTables(); + + // 调用各个删除操作的示例方法 + // Calling example methods for various delete operations + DeleteSingleEntity(db); + + // 批量删除实体的示例方法 + // Example method for deleting entities in batch + DeleteBatchEntities(db); + + // 批量删除并分页的示例方法 + // Example method for deleting entities in batch with paging + DeleteBatchEntitiesWithPaging(db); + + // 调用无主键实体删除的示例方法 + // Calling example method for deleting entities without primary key + DeleteEntitiesWithoutPrimaryKey(db); + + // 调用根据主键删除实体的示例方法 + // Calling example method for deleting entity by primary key + DeleteEntityByPrimaryKey(1, db); + + // 调用根据主键数组批量删除实体的示例方法 + // Calling example method for deleting entities by primary key array + DeleteEntitiesByPrimaryKeyArray(db); + + // 调用根据表达式删除实体的示例方法 + // Calling example method for deleting entities by expression + DeleteEntitiesByExpression(db); + + // 调用联表删除实体的示例方法 + // Calling example method for deleting entities with join + DeleteEntitiesWithJoin(db); + } + + /// + /// 删除单个实体的示例方法。 + /// Example method for deleting a single entity. + /// + internal static void DeleteSingleEntity(ISqlSugarClient db) + { + // 删除指定 Id 的学生实体 + // Delete the student entity with the specified Id + db.Deleteable(new Student() { Id = 1 }).ExecuteCommand(); + } + + /// + /// 批量删除实体的示例方法。 + /// Example method for deleting entities in batch. + /// + internal static void DeleteBatchEntities(ISqlSugarClient db) + { + // 创建学生实体列表 + // Create a list of student entities + List list = new List() + { + new Student() { Id = 1 } + }; + + // 批量删除学生实体 + // Delete student entities in batch + db.Deleteable(list).ExecuteCommand(); + } + + /// + /// 批量删除并分页的示例方法。 + /// Example method for deleting entities in batch with paging. + /// + internal static void DeleteBatchEntitiesWithPaging(ISqlSugarClient db) + { + // 创建订单实体列表 + // Create a list of order entities + List list = new List(); + + // 批量删除订单实体并分页 + // Delete order entities in batch with paging + db.Deleteable(list).PageSize(500).ExecuteCommand(); + } + + /// + /// 无主键实体删除的示例方法。 + /// Example method for deleting entities without primary key. + /// + internal static void DeleteEntitiesWithoutPrimaryKey( ISqlSugarClient db) + { + List orders = new List() + { + new Order() { Id = 1 }, + new Order() { Id = 2 } + }; + + // 根据指定的实体列表的 Id 列进行删除 + // Delete entities based on the Id column of the specified entity list + db.Deleteable().WhereColumns(orders, it => new { it.Id }).ExecuteCommand(); + } + + /// + /// 根据主键删除实体的示例方法。 + /// Example method for deleting an entity by primary key. + /// + internal static void DeleteEntityByPrimaryKey(int id, ISqlSugarClient db) + { + // 根据指定的 Id 删除学生实体 + // Delete the student entity with the specified Id + db.Deleteable().In(id).ExecuteCommand(); + } + + /// + /// 根据主键数组批量删除实体的示例方法。 + /// Example method for deleting entities by primary key array. + /// + internal static void DeleteEntitiesByPrimaryKeyArray(ISqlSugarClient db) + { + // 定义主键数组 + // Define an array of primary keys + int[] ids = { 1, 2 }; + + // 根据指定的 Id 数组批量删除学生实体 + // Delete student entities in batch based on the specified Id array + db.Deleteable().In(ids).ExecuteCommand(); + } + + /// + /// 根据表达式删除实体的示例方法。 + /// Example method for deleting entities by expression. + /// + internal static void DeleteEntitiesByExpression(ISqlSugarClient db) + { + // 根据指定的表达式删除学生实体 + // Delete the student entity based on the specified expression + db.Deleteable().Where(it => it.Id == 1).ExecuteCommand(); + } + + /// + /// 联表删除实体的示例方法。 + /// Example method for deleting entities with join. + /// + internal static void DeleteEntitiesWithJoin(ISqlSugarClient db) + { + // 联表删除学生实体 + // Delete student entities with join + db.Deleteable() + .Where(p => SqlFunc.Subqueryable().Where(s => s.Id == p.SchoolId).Any()) + .ExecuteCommand(); + } + + [SugarTable("Students_a1")] + public class Student + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] // 主键 + public int Id { get; set; } + + public string Name { get; set; } + + public int SchoolId { get; set; } + } + + [SugarTable("Orders_a2")] + public class Order + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] // 主键 + public int Id { get; set; } + + public string OrderNumber { get; set; } + + public decimal Amount { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/a2_Sql.cs b/Src/Asp.NetCore2/DuckDBTest/a2_Sql.cs new file mode 100644 index 000000000..ec9efb782 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/a2_Sql.cs @@ -0,0 +1,74 @@ +using SqlSugar; +using System; +using System.Collections.Generic; + +namespace OrmTest +{ + internal class _a2_Sql + { + /// + /// 初始化 SQL 操作的示例方法。 + /// Initializes example methods for SQL operations. + /// + internal static void Init() + { + // 获取新的数据库连接对象 + // Get a new database connection object + var db = DbHelper.GetNewDb(); + + // CodeFirst 初始化 ClassA 表 + // CodeFirst initializes the ClassA table + db.CodeFirst.InitTables(); + db.Insertable(new ClassA() { Name = Guid.NewGuid().ToString("N") }).ExecuteCommand(); + + // 1. 无参数查询 DataTable + // 1. Query DataTable without parameters + var dt1 = db.Ado.GetDataTable("SELECT * FROM Table_a2"); + + // 2. 带参数查询 DataTable(简化用法) + // 2. Query DataTable with parameters (simplified usage) + var dt2 = db.Ado.GetDataTable("SELECT * FROM Table_a2 WHERE id=@id AND name LIKE @name", + new { id = 1, name = "%Jack%" }); + + // 3. 带参数查询 DataTable(复杂用法) + // 3. Query DataTable with parameters (complex usage) + var parameters = new List + { + new SugarParameter("@id", 1), + new SugarParameter("@name", "%Jack%",System.Data.DbType.AnsiString)//DbType + }; + var dt3 = db.Ado.GetDataTable("SELECT * FROM Table_a2 WHERE id=@id AND name LIKE @name", parameters); + + // 4. 带参数查询 DataTable(结合用法) + // 4. Query DataTable with parameters (combined usage) + var dynamicParameters = db.Ado.GetParameters(new { p = 1, p2 = "A" }); + var dt4 = db.Ado.GetDataTable("SELECT * FROM Table_a2 WHERE id=@p AND name=@p2", dynamicParameters); + + // 原生 SQL 使用实体进行查询 + // Native SQL query using an entity + List entities = db.Ado.SqlQuery("SELECT * FROM Table_a2"); + List entities2 = db.Ado.SqlQuery("SELECT * FROM Table_a2 WHERE ID>@ID",new { ID=1}); + + // 原生 SQL 使用匿名对象进行查询 + // Native SQL query using an anonymous object + List anonymousObjects = db.Ado.SqlQuery("SELECT * FROM Table_a2"); + + // 执行 SQL 命令(插入、更新、删除操作) + // Execute SQL commands (insert, update, delete operations) + db.Ado.ExecuteCommand("INSERT INTO Table_a2 (name) VALUES ( 'New Record')"); + } + + /// + /// 示例实体类。 + /// Example entity class. + /// + [SugarTable("Table_a2")] + public class ClassA + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + public string Name { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/a3_Merge.cs b/Src/Asp.NetCore2/DuckDBTest/a3_Merge.cs new file mode 100644 index 000000000..561dd248c --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/a3_Merge.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrmTest +{ + internal class _a3_Merge + { + // 中文备注:初始化方法(用于大数据处理) + // English Comment: Initialization method (for big data processing) + internal static void Init() + { + var db = DbHelper.GetNewDb(); + //建表 + //Create table + db.CodeFirst.InitTables(); + var list = new List() { new Order() { Name = "jack" } }; + + // 中文备注:执行插入或更新操作 + // English Comment: Perform insert or update operation + db.Storageable(list).ExecuteCommand(); + + // 中文备注:分页执行插入或更新操作,每页1000条记录 + // English Comment: Perform insert or update operation with paging, 1000 records per page + db.Storageable(list).PageSize(1000).ExecuteCommand(); + + // 中文备注:带异常处理的分页插入或更新操作,每页1000条记录 + // English Comment: Perform insert or update operation with exception handling and paging, 1000 records per page + db.Storageable(list).PageSize(1000, exrows => { }).ExecuteCommand(); + + // 中文备注:使用Fastest方式批量合并数据(用于大数据处理) + // English Comment: Merge data using Fastest method (for big data processing) + db.Fastest().BulkMerge(list); + + // 中文备注:分页使用Fastest方式批量合并数据,每页100000条记录(用于大数据处理) + // English Comment: Merge data using Fastest method with paging, 100000 records per page (for big data processing) + db.Fastest().PageSize(100000).BulkMerge(list); + } + + [SqlSugar.SugarTable("Order_a3")] + public class Order + { + [SqlSugar.SugarColumn(IsPrimaryKey =true,IsIdentity =true)] + public int Id { get; set; } + public string Name { get; set; } + // 其他属性 + } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/a4_SplitTable.cs b/Src/Asp.NetCore2/DuckDBTest/a4_SplitTable.cs new file mode 100644 index 000000000..dca9e4542 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/a4_SplitTable.cs @@ -0,0 +1,66 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrmTest +{ + internal class _a4_SplitTable + { + // Method for initialization and testing of split tables + // 用于初始化和测试分表的方法 + public static void Init() + { + // Obtain a new instance of SqlSugarClient + // 获取 SqlSugarClient 的新实例 + SqlSugarClient db = DbHelper.GetNewDb(); + + + // Entities change the synchronization table structure + // 实体变化同步表结构 + db.CodeFirst.SplitTables().InitTables(); + + // Insert records into the split table and create table + // 向分表插入记录并创建表 + db.Insertable(new SplitTableDemo() { Name = "jack", Time = DateTime.Now }).SplitTable().ExecuteCommand(); + db.Insertable(new SplitTableDemo() { Name = "jack2", Time = DateTime.Now.AddDays(-11) }).SplitTable().ExecuteCommand(); + + // Query records from the split table within a specified date range + // 在指定日期范围内从分表查询记录 + var list = db.Queryable() + .Where(it=>it.Name!=null) + .SplitTable(DateTime.Now.Date.AddYears(-1), DateTime.Now) + .ToList(); + + // Update records from the split table + // 从分表更新记录 + var updateList = list.Take(2).ToList(); + db.Updateable(updateList).SplitTable().ExecuteCommand(); + + // Delete records from the split table + // 从分表删除记录 + db.Deleteable(updateList).SplitTable().ExecuteCommand(); + } + + // Entity class representing the split table + // 代表分表的实体类 + [SplitTable(SplitType.Day)] // Specify the split type as "Day" + // 指定分表类型为“Day” + [SqlSugar.SugarTable("SplitTableDemo_{year}{month}{day}")] // Specify the table name pattern + // 指定表名模式 + public class SplitTableDemo + { + [SugarColumn(IsPrimaryKey = true)] // Specify primary key + // 指定主键 + public Guid Pk { get; set; } + public string Name { get; set; } + + [SugarColumn(IsNullable = true)] + [SplitField] // Mark the field as a split field + // 将字段标记为分表字段 + public DateTime Time { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/a5_GridSave.cs b/Src/Asp.NetCore2/DuckDBTest/a5_GridSave.cs new file mode 100644 index 000000000..4ee26ac92 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/a5_GridSave.cs @@ -0,0 +1,81 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrmTest +{ + internal class _a5_GridSave + { + public static void Init() + { + // Get a new database connection + // 获取一个新的数据库连接 + SqlSugarClient db = DbHelper.GetNewDb(); + + // Initialize tables using CodeFirst + // 使用 CodeFirst 初始化表 + db.CodeFirst.InitTables(); + + // Clear table data + // 清空表数据 + db.DbMaintenance.TruncateTable(); + + // Insert two student records + // 插入两条学生记录 + db.Insertable(new List() { + new Student() {Name= "jack",CreateTime=DateTime.Now}, + new Student() {Name= "tom",CreateTime=DateTime.Now} + }).ExecuteReturnIdentity(); + + // Query all student records + // 查询所有学生记录 + List getAll = db.Queryable().ToList(); + + + + // Enable entity tracking for the list 'getAll' + // 启用对列表 'getAll' 的实体跟踪 + db.Tracking(getAll); + + + + + // Remove the first record + // 移除第一条记录 + getAll.RemoveAt(0); + + // Modify the name of the last record + // 修改最后一条记录的姓名 + getAll[getAll.Count - 1].Name += "_Update"; + + // Add a new record + // 添加新记录 + getAll.Add(new Student { Name = "NewRecord" }); + + + + + + // Execute GridSave operation + // 执行 GridSave 操作 + db.GridSave(getAll).ExecuteCommand(); + + // Query all students again + // 再次查询所有学生 + var list = db.Queryable().ToList(); + } + + // Define the entity class 定义实体类 + [SugarTable("SaveTable_a5")] + public class Student + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + public string Name { get; set; } + public DateTime CreateTime { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/a6_SqlPage.cs b/Src/Asp.NetCore2/DuckDBTest/a6_SqlPage.cs new file mode 100644 index 000000000..47a67aaef --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/a6_SqlPage.cs @@ -0,0 +1,59 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices.ComTypes; +using System.Text; +using System.Threading.Tasks; + +namespace OrmTest +{ + internal class _a6_SqlPage + { + /// + /// + /// Initializes an example method for SQL paging operations. + /// 初始化 SQL 分页操作的示例方法。 + /// + internal static void Init() + { + // Get a new database connection object + // 获取新的数据库连接对象 + var db = DbHelper.GetNewDb(); + + // CodeFirst initializes the ClassA table + // CodeFirst 初始化 ClassA 表 + db.CodeFirst.InitTables(); + for (int i = 0; i < 16; i++) + { + db.Insertable(new ClassA() { Name = Guid.NewGuid().ToString("N") }).ExecuteCommand(); + } + + + // Query data using paging and get the total count + // 使用分页查询数据,并获取总记录数 + int count = 0; + var list = db.SqlQueryable("select * from Table_a6").ToPageList(1, 5, ref count); + + + + // Asynchronously query data using paging and get the total count + // 使用异步方式分页查询数据,并获取总记录数 + RefAsync countAsync = 0; + var listAsync = db.SqlQueryable("select * from Table_a6").ToPageListAsync(1, 5, countAsync).GetAwaiter().GetResult(); + } + + /// + /// Example entity class. + /// 示例实体类。 + /// + [SugarTable("Table_a6")] + public class ClassA + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + public string Name { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/a7_JsonType.cs b/Src/Asp.NetCore2/DuckDBTest/a7_JsonType.cs new file mode 100644 index 000000000..fe67d3f3e --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/a7_JsonType.cs @@ -0,0 +1,87 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OrmTest +{ + internal class _a7_JsonType + { + /// + /// Demonstrates JSON operations with SqlSugar. + /// 展示了在 SqlSugar 中进行 JSON 操作的示例。 + /// + internal static void Init() + { + // Get a new database connection object + // 获取一个新的数据库连接对象 + var db = DbHelper.GetNewDb(); + + // Create table + // 创建表 + db.CodeFirst.InitTables(); + + // Insert a record with a JSON property + // 插入一条包含 JSON 属性的记录 + db.Insertable(new UnitJsonTest() + { + Name = "json1", + Order = new Order { Id = 1, Name = "order1" } + }).ExecuteCommand(); + + // Query all records from the table + // 查询表中的所有记录 + var list = db.Queryable().ToList(); + + //Sqlfunc.JsonXXX + var list2=db.Queryable() + .Select(it => new + { + id=it.Id, + jsonname=SqlFunc.JsonField(it.Order,"Name") + }) + .ToList(); + + var list3=db.Queryable().Select(it => new + { + + Order1 = new UnitJsonTest() + { + Id=it.Id, + Order = it.Order + } + }).ToList(); + + if (list3.First().Order1.Order == null|| list3.First().Order1.Order.Id==0) + { + throw new Exception("unit error"); + } + } + + /// + /// Represents a class with a JSON property. + /// 表示一个包含 JSON 属性的类。 + /// + [SugarTable("UnitJsonTest_a7")] + public class UnitJsonTest + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + [SugarColumn(IsJson = true)] + public Order Order { get; set; } + + public string Name { get; set; } + } + + /// + /// Represents an order entity. + /// 表示订单实体。 + /// + public class Order + { + public int Id { get; set; } + public string Name { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/DuckDBTest/a8_SelectReturnType.cs b/Src/Asp.NetCore2/DuckDBTest/a8_SelectReturnType.cs new file mode 100644 index 000000000..4e7e67af1 --- /dev/null +++ b/Src/Asp.NetCore2/DuckDBTest/a8_SelectReturnType.cs @@ -0,0 +1,68 @@ +using SqlSugar; +using System; +using System.Collections.Generic; + +namespace OrmTest +{ + internal class _a8_SelectReturnType + { + internal static void Init() + { + var db = DbHelper.GetNewDb(); + + //Create table + //建表 + db.CodeFirst.InitTables(); + //init data + db.Insertable(new Student() { CreateTime = DateTime.Now, Name = "aa" }).ExecuteCommand(); + + + // 返回匿名对象 (Return anonymous objects) + var dynamicList = db.Queryable().Select().ToList(); + // SELECT * FROM Student_a8 + + // 手动:返回匿名集合,支持跨程序集 (Manually: Return an anonymous collection, supporting cross-assembly) + List dynamicListCrossAssembly = db.Queryable().Select(it => (dynamic)new { id = it.Id }).ToList(); + // SELECT id AS id FROM Student_a8 + + // 手动:返回匿名集合,不能跨程序集 (Manually: Return an anonymous collection, within the same assembly) + var dynamicListWithinAssembly = db.Queryable().Select(it => new { id = it.Id }).ToList(); + // SELECT id AS id FROM Student_a8 + + // 手动:返回类集合-手动 (Manually: Return a class collection manually) + List classList = db.Queryable().Select(it => new Student { Id = it.Id }).ToList(); + // SELECT id AS Id FROM Student_a8 + + // 自动返回DTO集合: 请升级至 5.1.3.2 版本 (Automatically return DTO collections: Upgrade to version 5.1.3.2) + var listDto = db.Queryable().Select().ToList(); + + // 自动返回DTO: 请升级至 5.1.3.35 版本 (Automatically return DTO: Upgrade to version 5.1.3.35) + var listDtoAutoMap = db.Queryable() + .Select(it => new StudentDto + { + AppendColumn = 100 // 手动指定一列在自动映射 (Manually specify a column in automatic mapping) + }, + true) // true 表示开启自动映射 (true indicates enabling automatic mapping) + .ToList(); + } + + // 学生表的实体类 (Entity class for the Student table) + [SugarTable("Student_a8")] + public class Student + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + public string Name { get; set; } + public DateTime CreateTime { get; set; } + } + + // DTO 数据传输对象 (DTO - Data Transfer Object) + public class StudentDto + { + public int Id { get; set; } + public string Name { get; set; } + public DateTime CreateTime { get; set; } + public int AppendColumn { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/CodeFirst/DuckDBCodeFirst.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/CodeFirst/DuckDBCodeFirst.cs new file mode 100644 index 000000000..0ea3e0c02 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/CodeFirst/DuckDBCodeFirst.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SqlSugar.DuckDB +{ + public class DuckDBCodeFirst : CodeFirstProvider + { + protected override void ExistLogicEnd(List dbColumns) + { + foreach (EntityColumnInfo column in dbColumns) + { + if (column.DefaultValue != null) + { + this.Context.DbMaintenance.AddDefaultValue(column.DbTableName,column.DbColumnName,column.DefaultValue.ToSqlValue()); + } + } + } + public override void NoExistLogic(EntityInfo entityInfo) + { + var tableName = GetTableName(entityInfo); + //Check.Exception(entityInfo.Columns.Where(it => it.IsPrimarykey).Count() > 1, "Use Code First ,The primary key must not exceed 1"); + List columns = new List(); + if (entityInfo.Columns.HasValue()) + { + foreach (var item in entityInfo.Columns.Where(it=>it.IsIgnore==false)) + { + DbColumnInfo dbColumnInfo = this.EntityColumnToDbColumn(entityInfo, tableName, item); + columns.Add(dbColumnInfo); + } + if (entityInfo.IsCreateTableFiledSort) + { + columns = columns.OrderBy(c => c.CreateTableFieldSort).ToList(); + } + } + columns = columns.OrderBy(it => it.IsPrimarykey ? 0 : 1).ToList(); + this.Context.DbMaintenance.CreateTable(tableName, columns,true); + } + protected override DbColumnInfo EntityColumnToDbColumn(EntityInfo entityInfo, string tableName, EntityColumnInfo item) + { + var propertyType = UtilMethods.GetUnderType(item.PropertyInfo); + var result = new DbColumnInfo() + { + TableId = entityInfo.Columns.IndexOf(item), + DbColumnName = item.DbColumnName.HasValue() ? item.DbColumnName : item.PropertyName, + IsPrimarykey = item.IsPrimarykey, + IsIdentity = item.IsIdentity, + TableName = tableName, + IsNullable = item.IsNullable, + DefaultValue = item.DefaultValue, + ColumnDescription = item.ColumnDescription, + Length = item.Length, + CreateTableFieldSort = item.CreateTableFieldSort + }; + if (propertyType == UtilConstants.DecType) + { + result.Scale = item.DecimalDigits; + result.DecimalDigits = item.DecimalDigits; + } + GetDbType(item, propertyType, result); + if (result.DataType.Equals("varchar", StringComparison.CurrentCultureIgnoreCase) && result.Length == 0) + { + result.Length = 1; + } + return result; + } + + protected override void ConvertColumns(List dbColumns) + { + foreach (var item in dbColumns) + { + if (item.DataType == "DateTime") + { + item.Length = 0; + } + } + } + + protected override void ChangeKey(EntityInfo entityInfo, string tableName, EntityColumnInfo item) + { + this.Context.DbMaintenance.UpdateColumn(tableName, EntityColumnToDbColumn(entityInfo, tableName, item)); + if (!item.IsPrimarykey) + this.Context.DbMaintenance.DropConstraint(tableName,null); + if (item.IsPrimarykey) + this.Context.DbMaintenance.AddPrimaryKey(tableName, item.DbColumnName); + } + + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/DbBind/DuckDBDbBind.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/DbBind/DuckDBDbBind.cs new file mode 100644 index 000000000..c3b997334 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/DbBind/DuckDBDbBind.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace SqlSugar.DuckDB +{ + public class DuckDBDbBind : DbBindProvider + { + public override string GetDbTypeName(string csharpTypeName) + { + if (csharpTypeName == UtilConstants.ByteArrayType.Name) + return "bytea"; + if (csharpTypeName.ToLower() == "int32") + csharpTypeName = "int"; + if (csharpTypeName.ToLower() == "int16") + csharpTypeName = "short"; + if (csharpTypeName.ToLower() == "int64") + csharpTypeName = "long"; + if (csharpTypeName.ToLower().IsIn("boolean", "bool")) + csharpTypeName = "bool"; + if (csharpTypeName == "DateTimeOffset") + csharpTypeName = "DateTime"; + var mappings = this.MappingTypes.Where(it => it.Value.ToString().Equals(csharpTypeName, StringComparison.CurrentCultureIgnoreCase)).ToList(); + if (mappings != null && mappings.Count > 0) + return mappings.First().Key; + else + return "varchar"; + } + public override string GetPropertyTypeName(string dbTypeName) + { + dbTypeName = dbTypeName.ToLower(); + var propertyTypes = MappingTypes.Where(it => it.Value.ToString().ToLower() == dbTypeName || it.Key.ToLower() == dbTypeName); + if (propertyTypes == null) + { + return "other"; + } + else if (dbTypeName == "xml" || dbTypeName == "string"|| dbTypeName == "jsonb"|| dbTypeName == "json") + { + return "string"; + }else if (dbTypeName == "bpchar")//数据库char datatype 查询出来的时候是 bpchar + { + return "char"; + } + if (dbTypeName == "byte[]") + { + return "byte[]"; + } + else if (propertyTypes == null || propertyTypes.Count() == 0) + { + if (dbTypeName.StartsWith("_")) + { + var dbTypeName2 = dbTypeName.TrimStart('_'); + return MappingTypes.Where(it => it.Value.ToString().ToLower() == dbTypeName2 || it.Key.ToLower() == dbTypeName2).Select(it => it.Value + "[]").First(); + } + Check.ThrowNotSupportedException(string.Format(" \"{0}\" Type NotSupported, DbBindProvider.GetPropertyTypeName error.", dbTypeName)); + return null; + } + else if (propertyTypes.First().Value == CSharpDataType.byteArray) + { + return "byte[]"; + } + else + { + return propertyTypes.First().Value.ToString(); + } + } + public override List> MappingTypes + { + get + { + var extService = this.Context.CurrentConnectionConfig.ConfigureExternalServices; + if (extService != null && extService.AppendDataReaderTypeMappings.HasValue()) + { + return extService.AppendDataReaderTypeMappings.Union(MappingTypesConst).ToList(); + } + else + { + return MappingTypesConst; + } + } + } + public static List> MappingTypesConst = new List>(){ + + new KeyValuePair("int2",CSharpDataType.@short), + new KeyValuePair("int1",CSharpDataType.@byte), + new KeyValuePair("smallint",CSharpDataType.@short), + new KeyValuePair("int4",CSharpDataType.@int), + new KeyValuePair("serial",CSharpDataType.@int), + new KeyValuePair("integer",CSharpDataType.@int), + new KeyValuePair("int8",CSharpDataType.@long), + new KeyValuePair("bigint",CSharpDataType.@long), + new KeyValuePair("float4",CSharpDataType.@float), + new KeyValuePair("float4",CSharpDataType.Single), + new KeyValuePair("real",CSharpDataType.@float), + new KeyValuePair("float8",CSharpDataType.@double), + new KeyValuePair("double precision",CSharpDataType.@int), + new KeyValuePair("numeric",CSharpDataType.@decimal), + new KeyValuePair("decimal",CSharpDataType.@decimal), + new KeyValuePair("path",CSharpDataType.@decimal), + new KeyValuePair("point",CSharpDataType.@decimal), + new KeyValuePair("polygon",CSharpDataType.@decimal), + + new KeyValuePair("boolean",CSharpDataType.@bool), + new KeyValuePair("bool",CSharpDataType.@bool), + new KeyValuePair("box",CSharpDataType.@bool), + new KeyValuePair("bytea",CSharpDataType.byteArray), + + new KeyValuePair("varchar",CSharpDataType.@string), + new KeyValuePair("character varying",CSharpDataType.@string), + new KeyValuePair("geometry",CSharpDataType.@string), + new KeyValuePair("name",CSharpDataType.@string), + new KeyValuePair("text",CSharpDataType.@string), + new KeyValuePair("char",CSharpDataType.@string), + new KeyValuePair("character",CSharpDataType.@string), + new KeyValuePair("cidr",CSharpDataType.@string), + new KeyValuePair("circle",CSharpDataType.@string), + new KeyValuePair("tsquery",CSharpDataType.@string), + new KeyValuePair("tsvector",CSharpDataType.@string), + new KeyValuePair("txid_snapshot",CSharpDataType.@string), + new KeyValuePair("uuid",CSharpDataType.Guid), + new KeyValuePair("xml",CSharpDataType.@string), + new KeyValuePair("json",CSharpDataType.@string), + + new KeyValuePair("interval",CSharpDataType.@decimal), + new KeyValuePair("lseg",CSharpDataType.@decimal), + new KeyValuePair("macaddr",CSharpDataType.@decimal), + new KeyValuePair("money",CSharpDataType.@decimal), + new KeyValuePair("timestamp",CSharpDataType.DateTime), + new KeyValuePair("timestamp with time zone",CSharpDataType.DateTime), + new KeyValuePair("timestamptz",CSharpDataType.DateTime), + new KeyValuePair("timestamp without time zone",CSharpDataType.DateTime), + new KeyValuePair("date",CSharpDataType.DateTime), + new KeyValuePair("time",CSharpDataType.DateTime), + new KeyValuePair("time with time zone",CSharpDataType.DateTime), + new KeyValuePair("timetz",CSharpDataType.DateTime), + new KeyValuePair("time without time zone",CSharpDataType.DateTime), + + new KeyValuePair("bit",CSharpDataType.byteArray), + new KeyValuePair("bit varying",CSharpDataType.byteArray), + new KeyValuePair("varbit",CSharpDataType.@byte), + new KeyValuePair("time",CSharpDataType.TimeSpan), + new KeyValuePair("public.geometry",CSharpDataType.@object), + new KeyValuePair("public.geography",CSharpDataType.@object), + new KeyValuePair("inet",CSharpDataType.@object) + }; + public override List StringThrow + { + get + { + return new List() { "int32", "datetime", "decimal", "double", "byte" }; + } + } + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/DbFirst/DuckDBDbFirst.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/DbFirst/DuckDBDbFirst.cs new file mode 100644 index 000000000..b64da4462 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/DbFirst/DuckDBDbFirst.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SqlSugar.DuckDB +{ + public class DuckDBDbFirst : DbFirstProvider + { + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/DbMaintenance/DuckDBDbMaintenance.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/DbMaintenance/DuckDBDbMaintenance.cs new file mode 100644 index 000000000..1d30e093e --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/DbMaintenance/DuckDBDbMaintenance.cs @@ -0,0 +1,516 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SqlSugar.DuckDB +{ + public class DuckDBDbMaintenance : DbMaintenanceProvider + { + #region DML + protected override string GetDataBaseSql + { + get + { + return "SELECT datname FROM pg_database"; + } + } + protected override string GetColumnInfosByTableNameSql + { + get + { + string schema = GetSchema(); + string sql = @"select cast (pclass.oid as int4) as TableId,cast(ptables.tablename as varchar) as TableName, + pcolumn.column_name as DbColumnName,pcolumn.udt_name as DataType, + CASE WHEN pcolumn.numeric_scale >0 THEN pcolumn.numeric_precision ELSE pcolumn.character_maximum_length END as Length, + pcolumn.column_default as DefaultValue, + pcolumn.numeric_scale as DecimalDigits, + pcolumn.numeric_scale as Scale, + col_description(pclass.oid, pcolumn.ordinal_position) as ColumnDescription, + case when pkey.colname = pcolumn.column_name + then true else false end as IsPrimaryKey, + case when pcolumn.column_default like 'nextval%' + then true else false end as IsIdentity, + case when pcolumn.is_nullable = 'YES' + then true else false end as IsNullable + from (select * from pg_tables where upper(tablename) = upper('{0}') and schemaname='" + schema + @"') ptables inner join pg_class pclass + on ptables.tablename = pclass.relname inner join (SELECT * + FROM information_schema.columns + ) pcolumn on pcolumn.table_name = ptables.tablename + left join ( + select pg_class.relname,pg_attribute.attname as colname from + pg_constraint inner join pg_class + on pg_constraint.conrelid = pg_class.oid + inner join pg_attribute on pg_attribute.attrelid = pg_class.oid + and pg_attribute.attnum = pg_constraint.conkey[1] + inner join pg_type on pg_type.oid = pg_attribute.atttypid + where pg_constraint.contype='p' + ) pkey on pcolumn.table_name = pkey.relname + order by table_catalog, table_schema, ordinal_position"; + return sql; + } + } + + protected override string GetTableInfoListSql + { + get + { + var schema = GetSchema(); + return @"select cast(relname as varchar) as Name, + cast(obj_description(c.oid,'pg_class') as varchar) as Description from pg_class c + inner join + pg_namespace n on n.oid = c.relnamespace and nspname='" + schema + @"' + inner join + pg_tables z on z.tablename=c.relname + where relkind in('p', 'r') and relname not like 'hg_%' and relname not like 'sql_%' and schemaname='" + schema + "' order by relname"; + } + } + protected override string GetViewInfoListSql + { + get + { + return @"select cast(relname as varchar) as Name,cast(Description as varchar) from pg_description + join pg_class on pg_description.objoid = pg_class.oid + where objsubid = 0 and relname in (SELECT viewname from pg_views + WHERE schemaname ='"+GetSchema()+"')"; + } + } + #endregion + + #region DDL + protected override string CreateDataBaseSql + { + get + { + return "CREATE DATABASE {0}"; + } + } + protected override string AddPrimaryKeySql + { + get + { + return "ALTER TABLE {0} ADD PRIMARY KEY({2}) /*{1}*/"; + } + } + protected override string AddColumnToTableSql + { + get + { + return "ALTER TABLE {0} ADD COLUMN {1} {2}{3} {4} {5} {6}"; + } + } + protected override string AlterColumnToTableSql + { + get + { + return "alter table {0} ALTER COLUMN {1} {2}{3} {4} {5} {6}"; + } + } + protected override string BackupDataBaseSql + { + get + { + return "mysqldump.exe {0} -uroot -p > {1} "; + } + } + protected override string CreateTableSql + { + get + { + return "CREATE TABLE {0}(\r\n{1} $PrimaryKey)"; + } + } + protected override string CreateTableColumn + { + get + { + return "{0} {1}{2} {3} {4} {5}"; + } + } + protected override string TruncateTableSql + { + get + { + return "TRUNCATE TABLE {0}"; + } + } + protected override string BackupTableSql + { + get + { + return "create table {0} as (select * from {1} limit {2} offset 0)"; + } + } + protected override string DropTableSql + { + get + { + return "DROP TABLE {0}"; + } + } + protected override string DropColumnToTableSql + { + get + { + return "ALTER TABLE {0} DROP COLUMN {1}"; + } + } + protected override string DropConstraintSql + { + get + { + return "ALTER TABLE {0} DROP CONSTRAINT {1}"; + } + } + protected override string RenameColumnSql + { + get + { + return "ALTER TABLE {0} RENAME {1} TO {2}"; + } + } + protected override string AddColumnRemarkSql => "comment on column {1}.{0} is '{2}'"; + + protected override string DeleteColumnRemarkSql => "comment on column {1}.{0} is ''"; + + protected override string IsAnyColumnRemarkSql { get { throw new NotSupportedException(); } } + + protected override string AddTableRemarkSql => "comment on table {0} is '{1}'"; + + protected override string DeleteTableRemarkSql => "comment on table {0} is ''"; + + protected override string IsAnyTableRemarkSql { get { throw new NotSupportedException(); } } + + protected override string RenameTableSql => "alter table {0} to {1}"; + + protected override string CreateIndexSql + { + get + { + return "CREATE {3} INDEX Index_{0}_{2} ON {0} ({1})"; + } + } + protected override string AddDefaultValueSql + { + get + { + return "ALTER TABLE {0} ALTER COLUMN {1} SET DEFAULT {2}"; + } + } + protected override string IsAnyIndexSql + { + get + { + return " SELECT count(1) WHERE upper('{0}') IN ( SELECT upper(indexname) FROM pg_indexes )"; + } + } + protected override string IsAnyProcedureSql => throw new NotImplementedException(); + #endregion + + #region Check + protected override string CheckSystemTablePermissionsSql + { + get + { + return "select 1 from information_schema.columns limit 1 offset 0"; + } + } + #endregion + + #region Scattered + protected override string CreateTableNull + { + get + { + return "DEFAULT NULL"; + } + } + protected override string CreateTableNotNull + { + get + { + return "NOT NULL"; + } + } + protected override string CreateTablePirmaryKey + { + get + { + return "PRIMARY KEY"; + } + } + protected override string CreateTableIdentity + { + get + { + return "serial"; + } + } + #endregion + + #region Methods + public override List GetIndexList(string tableName) + { + var sql = $"SELECT indexname, indexdef FROM pg_indexes WHERE upper(tablename) = upper('{tableName}')"; + return this.Context.Ado.SqlQuery(sql); + } + public override List GetProcList(string dbName) + { + var sql = $"SELECT proname FROM pg_proc p JOIN pg_namespace n ON p.pronamespace = n.oid WHERE n.nspname = '{dbName}'"; + return this.Context.Ado.SqlQuery(sql); + } + public override bool AddDefaultValue(string tableName, string columnName, string defaultValue) + { + return base.AddDefaultValue(this.SqlBuilder.GetTranslationTableName(tableName), this.SqlBuilder.GetTranslationTableName(columnName), defaultValue); + } + public override bool AddColumnRemark(string columnName, string tableName, string description) + { + tableName = this.SqlBuilder.GetTranslationTableName(tableName); + string sql = string.Format(this.AddColumnRemarkSql, this.SqlBuilder.GetTranslationColumnName(columnName.ToLower(isAutoToLowerCodeFirst)), tableName, description); + this.Context.Ado.ExecuteCommand(sql); + return true; + } + public override bool AddTableRemark(string tableName, string description) + { + tableName = this.SqlBuilder.GetTranslationTableName(tableName); + return base.AddTableRemark(tableName, description); + } + public override bool UpdateColumn(string tableName, DbColumnInfo columnInfo) + { + tableName = this.SqlBuilder.GetTranslationTableName(tableName); + var columnName= this.SqlBuilder.GetTranslationColumnName(columnInfo.DbColumnName); + string sql = GetUpdateColumnSql(tableName, columnInfo); + this.Context.Ado.ExecuteCommand(sql); + var isnull = columnInfo.IsNullable?" DROP NOT NULL ": " SET NOT NULL "; + this.Context.Ado.ExecuteCommand(string.Format("alter table {0} alter {1} {2}",tableName,columnName, isnull)); + return true; + } + + protected override string GetUpdateColumnSql(string tableName, DbColumnInfo columnInfo) + { + string columnName = this.SqlBuilder.GetTranslationColumnName(columnInfo.DbColumnName); + tableName = this.SqlBuilder.GetTranslationTableName(tableName); + string dataSize = GetSize(columnInfo); + string dataType = columnInfo.DataType; + if (!string.IsNullOrEmpty(dataType)) + { + dataType = " type " + dataType; + } + string nullType = ""; + string primaryKey = null; + string identity = null; + string result = string.Format(this.AlterColumnToTableSql, tableName, columnName, dataType, dataSize, nullType, primaryKey, identity); + return result; + } + + /// + ///by current connection string + /// + /// + /// + public override bool CreateDatabase(string databaseName, string databaseDirectory = null) + { + if (databaseDirectory != null) + { + if (!FileHelper.IsExistDirectory(databaseDirectory)) + { + FileHelper.CreateDirectory(databaseDirectory); + } + } + // var oldDatabaseName = this.Context.Ado.Connection.Database; + //var connection = this.Context.CurrentConnectionConfig.ConnectionString; + //connection = connection.Replace(oldDatabaseName, ""); + if (this.Context.Ado.IsValidConnection()) + { + return true; + } + var newDb = this.Context.CopyNew(); + newDb.Ado.Connection.ChangeDatabase("highgo"); + newDb.Open(); + if (!GetDataBaseList(newDb).Any(it => it.Equals(databaseName, StringComparison.CurrentCultureIgnoreCase))) + { + newDb.Ado.ExecuteCommand(string.Format(CreateDataBaseSql, this.SqlBuilder.SqlTranslationLeft+databaseName+this.SqlBuilder.SqlTranslationRight, databaseDirectory)); + } + newDb.Close(); + return true; + } + public override bool AddRemark(EntityInfo entity) + { + var db = this.Context; + var columns = entity.Columns.Where(it => it.IsIgnore == false).ToList(); + + foreach (var item in columns) + { + if (item.ColumnDescription != null) + { + db.DbMaintenance.AddColumnRemark(item.DbColumnName, item.DbTableName, item.ColumnDescription); + + } + } + //table remak + if (entity.TableDescription != null) + { + db.DbMaintenance.AddTableRemark(entity.DbTableName, entity.TableDescription); + } + return true; + } + public override bool CreateTable(string tableName, List columns, bool isCreatePrimaryKey = true) + { + if (columns.HasValue()) + { + foreach (var item in columns) + { + if (item.DbColumnName.Equals("GUID", StringComparison.CurrentCultureIgnoreCase) && item.Length == 0) + { + item.Length = 10; + } + } + } + string sql = GetCreateTableSql(tableName, columns); + string primaryKeyInfo = null; + if (columns.Any(it => it.IsPrimarykey) && isCreatePrimaryKey) + { + primaryKeyInfo = string.Format(", Primary key({0})", string.Join(",", columns.Where(it => it.IsPrimarykey).Select(it => this.SqlBuilder.GetTranslationColumnName(it.DbColumnName.ToLower(isAutoToLowerCodeFirst))))); + + } + sql = sql.Replace("$PrimaryKey", primaryKeyInfo); + this.Context.Ado.ExecuteCommand(sql); + return true; + } + protected override string GetCreateTableSql(string tableName, List columns) + { + List columnArray = new List(); + Check.Exception(columns.IsNullOrEmpty(), "No columns found "); + foreach (var item in columns) + { + string columnName = item.DbColumnName; + string dataType = item.DataType; + if (dataType == "varchar" && item.Length == 0) + { + item.Length = 1; + } + //if (dataType == "uuid") + //{ + // item.Length = 50; + // dataType = "varchar"; + //} + string dataSize = item.Length > 0 ? string.Format("({0})", item.Length) : null; + if (item.DecimalDigits > 0&&item.Length>0 && dataType == "numeric") + { + dataSize = $"({item.Length},{item.DecimalDigits})"; + } + string nullType = item.IsNullable ? this.CreateTableNull : CreateTableNotNull; + string primaryKey = null; + string addItem = string.Format(this.CreateTableColumn, this.SqlBuilder.GetTranslationColumnName(columnName.ToLower(isAutoToLowerCodeFirst)), dataType, dataSize, nullType, primaryKey, ""); + if (item.IsIdentity) + { + string length = dataType.Substring(dataType.Length - 1); + string identityDataType = "serial" + length; + addItem = addItem.Replace(dataType, identityDataType); + } + columnArray.Add(addItem); + } + string tableString = string.Format(this.CreateTableSql, this.SqlBuilder.GetTranslationTableName(tableName.ToLower(isAutoToLowerCodeFirst)), string.Join(",\r\n", columnArray)); + return tableString; + } + public override bool IsAnyConstraint(string constraintName) + { + throw new NotSupportedException("PgSql IsAnyConstraint NotSupportedException"); + } + public override bool BackupDataBase(string databaseName, string fullFileName) + { + Check.ThrowNotSupportedException("PgSql BackupDataBase NotSupported"); + return false; + } + + public override List GetColumnInfosByTableName(string tableName, bool isCache = true) + { + var result= base.GetColumnInfosByTableName(tableName.TrimEnd('"').TrimStart('"').ToLower(), isCache); + if (result == null || result.Count() == 0) + { + result = base.GetColumnInfosByTableName(tableName, isCache); + } + try + { + string sql = $@"select + kcu.column_name as key_column + from information_schema.table_constraints tco + join information_schema.key_column_usage kcu + on kcu.constraint_name = tco.constraint_name + and kcu.constraint_schema = tco.constraint_schema + and kcu.constraint_name = tco.constraint_name + where tco.constraint_type = 'PRIMARY KEY' + and kcu.table_schema='{GetSchema()}' and + upper(kcu.table_name)=upper('{tableName.TrimEnd('"').TrimStart('"')}')"; + List pkList = new List(); + if (isCache) + { + pkList=GetListOrCache("GetColumnInfosByTableName_N_Pk"+tableName, sql); + } + else + { + pkList = this.Context.Ado.SqlQuery(sql); + } + if (pkList.Count >1) + { + foreach (var item in result) + { + if (pkList.Select(it=>it.ToUpper()).Contains(item.DbColumnName.ToUpper())) + { + item.IsPrimarykey = true; + } + } + } + } + catch + { + + } + return result; + } + #endregion + + #region Helper + private bool isAutoToLowerCodeFirst + { + get + { + if (this.Context.CurrentConnectionConfig.MoreSettings == null) return true; + else if ( + this.Context.CurrentConnectionConfig.MoreSettings.PgSqlIsAutoToLower == false && + this.Context.CurrentConnectionConfig.MoreSettings?.PgSqlIsAutoToLowerCodeFirst == false) + { + return false; + } + else + { + return true; + } + } + } + private string GetSchema() + { + var schema = "public"; + if (System.Text.RegularExpressions.Regex.IsMatch(this.Context.CurrentConnectionConfig.ConnectionString.ToLower(), "searchpath=")) + { + var regValue = System.Text.RegularExpressions.Regex.Match(this.Context.CurrentConnectionConfig.ConnectionString.ToLower(), @"searchpath\=(\w+)").Groups[1].Value; + if (regValue.HasValue()) + { + schema = regValue; + } + } + else if (System.Text.RegularExpressions.Regex.IsMatch(this.Context.CurrentConnectionConfig.ConnectionString.ToLower(), "search path=")) + { + var regValue = System.Text.RegularExpressions.Regex.Match(this.Context.CurrentConnectionConfig.ConnectionString.ToLower(), @"search path\=(\w+)").Groups[1].Value; + if (regValue.HasValue()) + { + schema = regValue; + } + } + + return schema; + } + + #endregion + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/DuckDBProvider.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/DuckDBProvider.cs new file mode 100644 index 000000000..8c3fe4a33 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/DuckDBProvider.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DuckDB; +using DuckDB.NET.Data; +using DuckDB.NET.Native; + +namespace SqlSugar.DuckDB +{ + public partial class DuckDBProvider : AdoProvider + { + public DuckDBProvider() + { + if (StaticConfig.AppContext_ConvertInfinityDateTime == false) + { + AppContext.SetSwitch("DuckDB.EnableLegacyTimestampBehavior", true); + AppContext.SetSwitch("DuckDB.DisableDateTimeInfinityConversions", true); + } + + } + public override IDbConnection Connection + { + get + { + if (base._DbConnection == null) + { + try + { + var DuckDBConnectionString = base.Context.CurrentConnectionConfig.ConnectionString; + base._DbConnection = new DuckDBConnection(DuckDBConnectionString); + } + catch (Exception) + { + throw; + + } + } + return base._DbConnection; + } + set + { + base._DbConnection = value; + } + } + + public override void BeginTran(string transactionName) + { + base.BeginTran(); + } + /// + /// Only SqlServer + /// + /// + /// + public override void BeginTran(IsolationLevel iso, string transactionName) + { + base.BeginTran(iso); + } + public override IDataAdapter GetAdapter() + { + return new DuckDBDataAdapter(); + } + public override DbCommand GetCommand(string sql, SugarParameter[] parameters) + { + DuckDBCommand sqlCommand = new DuckDBCommand(sql, (DuckDBConnection)this.Connection); + sqlCommand.CommandType = this.CommandType; + sqlCommand.CommandTimeout = this.CommandTimeOut; + if (this.Transaction != null) + { + sqlCommand.Transaction = (DuckDBTransaction)this.Transaction; + } + if (parameters.HasValue()) + { + IDataParameter[] ipars = ToIDbDataParameter(parameters); + sqlCommand.Parameters.AddRange((DuckDBParameter[])ipars); + } + CheckConnection(); + return sqlCommand; + } + public override void SetCommandToAdapter(IDataAdapter dataAdapter, DbCommand command) + { + ((DuckDBDataAdapter)dataAdapter).SelectCommand = (DuckDBCommand)command; + } + /// + /// if mysql return MySqlParameter[] pars + /// if sqlerver return SqlParameter[] pars ... + /// + /// + /// + public override IDataParameter[] ToIDbDataParameter(params SugarParameter[] parameters) + { + if (parameters == null || parameters.Length == 0) return null; + DuckDBParameter[] result = new DuckDBParameter[parameters.Length]; + int index = 0; + var isVarchar = this.Context.IsVarchar(); + foreach (var parameter in parameters) + { + if (parameter.Value == null) parameter.Value = DBNull.Value; + if (parameter.Value is System.Data.SqlTypes.SqlDateTime && parameter.DbType == System.Data.DbType.AnsiString) + { + parameter.DbType = System.Data.DbType.DateTime; + parameter.Value = DBNull.Value; + } + UNumber(parameter); + var sqlParameter = new DuckDBParameter(); + sqlParameter.ParameterName = parameter.ParameterName; + sqlParameter.Size = parameter.Size; + sqlParameter.Value = parameter.Value; + sqlParameter.DbType = parameter.DbType; + sqlParameter.Direction = parameter.Direction; + //if (parameter.IsJson) + //{ + // sqlParameter.DuckDBDbType = DuckDBType.Json; + //} + if (sqlParameter.Direction == 0) + { + sqlParameter.Direction = ParameterDirection.Input; + } + result[index] = sqlParameter; + if (sqlParameter.Direction.IsIn(ParameterDirection.Output, ParameterDirection.InputOutput, ParameterDirection.ReturnValue)) + { + if (this.OutputParameters == null) this.OutputParameters = new List(); + this.OutputParameters.RemoveAll(it => it.ParameterName == sqlParameter.ParameterName); + this.OutputParameters.Add(sqlParameter); + } + if (isVarchar && sqlParameter.DbType == System.Data.DbType.String) + { + sqlParameter.DbType = System.Data.DbType.AnsiString; + } + else if (sqlParameter.Value is DateTime && sqlParameter.DbType == System.Data.DbType.AnsiString) + { + sqlParameter.DbType = System.Data.DbType.DateTime; + } + ++index; + //if (parameter.CustomDbType != null&& parameter.CustomDbType is DuckDBDbType) + //{ + // sqlParameter.DbType = ((DuckDBType)parameter.CustomDbType); + //} + } + return result; + } + + private static void UNumber(SugarParameter parameter) + { + if (parameter.DbType == System.Data.DbType.UInt16) + { + parameter.DbType = System.Data.DbType.Int16; + parameter.Value = Convert.ToInt16(parameter.Value); + } + else if (parameter.DbType == System.Data.DbType.UInt32) + { + parameter.DbType = System.Data.DbType.Int32; + parameter.Value = Convert.ToInt32(parameter.Value); + } + else if (parameter.DbType == System.Data.DbType.UInt64) + { + parameter.DbType = System.Data.DbType.Int64; + parameter.Value = Convert.ToInt64(parameter.Value); + } + } + + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/Insertable/DuckDBInserttable.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/Insertable/DuckDBInserttable.cs new file mode 100644 index 000000000..cf3f2835b --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/Insertable/DuckDBInserttable.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace SqlSugar.DuckDB +{ + public class DuckDBInsertable : InsertableProvider where T : class, new() + { + public override int ExecuteReturnIdentity() + { + InsertBuilder.IsReturnIdentity = true; + PreToSql(); + string identityColumn = GetIdentityColumn(); + string sql = InsertBuilder.ToSqlString().Replace("$PrimaryKey", this.SqlBuilder.GetTranslationColumnName(identityColumn)); + RestoreMapping(); + var result = Ado.GetScalar(sql, InsertBuilder.Parameters == null ? null : InsertBuilder.Parameters.ToArray()).ObjToInt(); + After(sql, result); + return result; + } + public override async Task ExecuteReturnIdentityAsync() + { + InsertBuilder.IsReturnIdentity = true; + PreToSql(); + string identityColumn = GetIdentityColumn(); + string sql = InsertBuilder.ToSqlString().Replace("$PrimaryKey", this.SqlBuilder.GetTranslationColumnName(identityColumn)); + RestoreMapping(); + var obj = await Ado.GetScalarAsync(sql, InsertBuilder.Parameters == null ? null : InsertBuilder.Parameters.ToArray()); + var result = obj.ObjToInt(); + After(sql, result); + return result; + } + public override KeyValuePair> ToSql() + { + var result= base.ToSql(); + var primaryKey = GetPrimaryKeys().FirstOrDefault(); + if (primaryKey != null) + { + primaryKey = this.SqlBuilder.GetTranslationColumnName(primaryKey); + } + return new KeyValuePair>(result.Key.Replace("$PrimaryKey", primaryKey), result.Value); + } + + public override long ExecuteReturnBigIdentity() + { + InsertBuilder.IsReturnIdentity = true; + PreToSql(); + string sql = InsertBuilder.ToSqlString().Replace("$PrimaryKey", this.SqlBuilder.GetTranslationColumnName(GetIdentityKeys().FirstOrDefault())); + RestoreMapping(); + var result = Convert.ToInt64(Ado.GetScalar(sql, InsertBuilder.Parameters == null ? null : InsertBuilder.Parameters.ToArray()) ?? "0"); + After(sql, result); + return result; + } + public override async Task ExecuteReturnBigIdentityAsync() + { + InsertBuilder.IsReturnIdentity = true; + PreToSql(); + string sql = InsertBuilder.ToSqlString().Replace("$PrimaryKey", this.SqlBuilder.GetTranslationColumnName(GetIdentityKeys().FirstOrDefault())); + RestoreMapping(); + var result = Convert.ToInt64(await Ado.GetScalarAsync(sql, InsertBuilder.Parameters == null ? null : InsertBuilder.Parameters.ToArray()) ?? "0"); + After(sql, result); + return result; + } + + public override bool ExecuteCommandIdentityIntoEntity() + { + var result = InsertObjs.First(); + var identityKeys = GetIdentityKeys(); + if (identityKeys.Count == 0) { return this.ExecuteCommand() > 0; } + var idValue = ExecuteReturnBigIdentity(); + Check.Exception(identityKeys.Count > 1, "ExecuteCommandIdentityIntoEntity does not support multiple identity keys"); + var identityKey = identityKeys.First(); + object setValue = 0; + if (idValue > int.MaxValue) + setValue = idValue; + else + setValue = Convert.ToInt32(idValue); + var propertyName = this.Context.EntityMaintenance.GetPropertyName(identityKey); + typeof(T).GetProperties().First(t => t.Name.ToUpper() == propertyName.ToUpper()).SetValue(result, setValue, null); + return idValue > 0; + } + + private string GetIdentityColumn() + { + var identityColumn = GetIdentityKeys().FirstOrDefault(); + if (identityColumn == null) + { + var columns = this.Context.DbMaintenance.GetColumnInfosByTableName(InsertBuilder.GetTableNameString); + identityColumn = columns.First(it => it.IsIdentity || it.IsPrimarykey).DbColumnName; + } + return identityColumn; + } + + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/Queryable/DuckDBQueryable.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/Queryable/DuckDBQueryable.cs new file mode 100644 index 000000000..927a1c08d --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/Queryable/DuckDBQueryable.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SqlSugar.DuckDB +{ + public class DuckDBQueryable : QueryableProvider + { + public override ISugarQueryable With(string withString) + { + return this; + } + + public override ISugarQueryable PartitionBy(string groupFileds) + { + this.GroupBy(groupFileds); + return this; + } + } + public class DuckDBQueryable : QueryableProvider + { + public new ISugarQueryable With(string withString) + { + return this; + } + } + public class DuckDBQueryable : QueryableProvider + { + + } + public class DuckDBQueryable : QueryableProvider + { + + } + public class DuckDBQueryable : QueryableProvider + { + + } + public class DuckDBQueryable : QueryableProvider + { + + } + public class DuckDBQueryable : QueryableProvider + { + + } + public class DuckDBQueryable : QueryableProvider + { + + } + public class DuckDBQueryable : QueryableProvider + { + + } + public class DuckDBQueryable : QueryableProvider + { + + } + public class DuckDBQueryable : QueryableProvider + { + + } + public class DuckDBQueryable : QueryableProvider + { + + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBBuilder.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBBuilder.cs new file mode 100644 index 000000000..a5892c5bc --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBBuilder.cs @@ -0,0 +1,128 @@ +using System; +using System.Linq; +using System.Text.RegularExpressions; + +namespace SqlSugar.DuckDB +{ + public class DuckDBBuilder : SqlBuilderProvider + { + public override string SqlTranslationLeft + { + get + { + return "\""; + } + } + public override string SqlTranslationRight + { + get + { + return "\""; + } + } + public override string SqlDateNow + { + get + { + return "current_date"; + } + } + public override string FullSqlDateNow + { + get + { + return "select current_date"; + } + } + + public bool isAutoToLower + { + get + { + if (this.Context.CurrentConnectionConfig.MoreSettings == null) return true; + return this.Context.CurrentConnectionConfig.MoreSettings.PgSqlIsAutoToLower; + } + } + public override string GetTranslationColumnName(string propertyName) + { + if (propertyName.Contains(".")&& !propertyName.Contains(SqlTranslationLeft)) + { + return string.Join(".", propertyName.Split('.').Select(it => $"{SqlTranslationLeft}{it.ToLower(isAutoToLower)}{SqlTranslationRight}")); + } + + if (propertyName.Contains(SqlTranslationLeft)) return propertyName; + else + return SqlTranslationLeft + propertyName.ToLower(isAutoToLower) + SqlTranslationRight; + } + + //public override string GetNoTranslationColumnName(string name) + //{ + // return name.TrimEnd(Convert.ToChar(SqlTranslationRight)).TrimStart(Convert.ToChar(SqlTranslationLeft)).ToLower(); + //} + public override string GetTranslationColumnName(string entityName, string propertyName) + { + Check.ArgumentNullException(entityName, string.Format(ErrorMessage.ObjNotExist, "Table Name")); + Check.ArgumentNullException(propertyName, string.Format(ErrorMessage.ObjNotExist, "Column Name")); + var context = this.Context; + var mappingInfo = context + .MappingColumns + .FirstOrDefault(it => + it.EntityName.Equals(entityName, StringComparison.CurrentCultureIgnoreCase) && + it.PropertyName.Equals(propertyName, StringComparison.CurrentCultureIgnoreCase)); + return (mappingInfo == null ? SqlTranslationLeft + propertyName.ToLower(isAutoToLower) + SqlTranslationRight : SqlTranslationLeft + mappingInfo.DbColumnName.ToLower(isAutoToLower) + SqlTranslationRight); + } + + public override string GetTranslationTableName(string name) + { + Check.ArgumentNullException(name, string.Format(ErrorMessage.ObjNotExist, "Table Name")); + var context = this.Context; + + var mappingInfo = context + .MappingTables + .FirstOrDefault(it => it.EntityName.Equals(name, StringComparison.CurrentCultureIgnoreCase)); + if (mappingInfo == null && name.Contains(".") && name.Contains("\"")) + { + return name; + } + name = (mappingInfo == null ? name : mappingInfo.DbTableName); + if (name.Contains(".")&& !name.Contains("(")&&!name.Contains("\".\"")) + { + return string.Join(".", name.ToLower(isAutoToLower).Split('.').Select(it => SqlTranslationLeft + it + SqlTranslationRight)); + } + else if (name.Contains("(")) + { + return name; + } + else if (name.Contains(SqlTranslationLeft) && name.Contains(SqlTranslationRight)) + { + return name; + } + else + { + return SqlTranslationLeft + name.ToLower(isAutoToLower).TrimEnd('"').TrimStart('"') + SqlTranslationRight; + } + } + public override string GetUnionFomatSql(string sql) + { + return " ( " + sql + " ) "; + } + + public override Type GetNullType(string tableName, string columnName) + { + if (tableName != null) + tableName = tableName.Trim(); + var columnInfo=this.Context.DbMaintenance.GetColumnInfosByTableName(tableName).FirstOrDefault(z => z.DbColumnName?.ToLower()==columnName?.ToLower()); + if (columnInfo != null) + { + var cTypeName=this.Context.Ado.DbBind.GetCsharpTypeNameByDbTypeName(columnInfo.DataType); + var value=SqlSugar.UtilMethods.GetTypeByTypeName(cTypeName); + if (value != null) + { + var key = "GetNullType_" + tableName + columnName; + return new ReflectionInoCacheService().GetOrCreate(key, () => value); + } + } + return null; + } + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBDeleteBuilder.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBDeleteBuilder.cs new file mode 100644 index 000000000..f9aa48750 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBDeleteBuilder.cs @@ -0,0 +1,7 @@ +namespace SqlSugar.DuckDB +{ + public class DuckDBDeleteBuilder : DeleteBuilder + { + + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBExpressionContext.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBExpressionContext.cs new file mode 100644 index 000000000..a3dda7026 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBExpressionContext.cs @@ -0,0 +1,488 @@ +using System; +using System.Linq; +namespace SqlSugar.DuckDB +{ + public class DuckDBExpressionContext : ExpressionContext, ILambdaExpressions + { + public SqlSugarProvider Context { get; set; } + public DuckDBExpressionContext() + { + base.DbMehtods = new DuckDBMethod(); + } + public override string SqlTranslationLeft + { + get + { + return "\""; + } + } + public override string SqlTranslationRight + { + get + { + return "\""; + } + } + public override string GetTranslationText(string name) + { + return SqlTranslationLeft + name.ToLower(isAutoToLower) + SqlTranslationRight; + } + public bool isAutoToLower + { + get + { + return base.PgSqlIsAutoToLower; + } + } + public override string GetTranslationTableName(string entityName, bool isMapping = true) + { + Check.ArgumentNullException(entityName, string.Format(ErrorMessage.ObjNotExist, "Table Name")); + if (IsTranslationText(entityName)) return entityName; + isMapping = isMapping && this.MappingTables.HasValue(); + var isComplex = entityName.Contains(UtilConstants.Dot); + if (isMapping && isComplex) + { + var columnInfo = entityName.Split(UtilConstants.DotChar); + var mappingInfo = this.MappingTables.FirstOrDefault(it => it.EntityName.Equals(columnInfo.Last(), StringComparison.CurrentCultureIgnoreCase)); + if (mappingInfo != null) + { + columnInfo[columnInfo.Length - 1] = mappingInfo.EntityName; + } + return string.Join(UtilConstants.Dot, columnInfo.Select(it => GetTranslationText(it))); + } + else if (isMapping) + { + var mappingInfo = this.MappingTables.FirstOrDefault(it => it.EntityName.Equals(entityName, StringComparison.CurrentCultureIgnoreCase)); + + var tableName = mappingInfo?.DbTableName+""; + if (tableName.Contains(".")) + { + tableName = string.Join(UtilConstants.Dot, tableName.Split(UtilConstants.DotChar).Select(it => GetTranslationText(it))); + return tableName; + } + + return SqlTranslationLeft + (mappingInfo == null ? entityName : mappingInfo.DbTableName).ToLower(isAutoToLower) + SqlTranslationRight; + } + else if (isComplex) + { + return string.Join(UtilConstants.Dot, entityName.Split(UtilConstants.DotChar).Select(it => GetTranslationText(it))); + } + else + { + return GetTranslationText(entityName); + } + } + public override string GetTranslationColumnName(string columnName) + { + Check.ArgumentNullException(columnName, string.Format(ErrorMessage.ObjNotExist, "Column Name")); + if (columnName.Substring(0, 1) == this.SqlParameterKeyWord) + { + return columnName; + } + if (IsTranslationText(columnName)) return columnName; + if (columnName.Contains(UtilConstants.Dot)) + { + return string.Join(UtilConstants.Dot, columnName.Split(UtilConstants.DotChar).Select(it => GetTranslationText(it))); + } + else + { + return GetTranslationText(columnName); + } + } + public override string GetDbColumnName(string entityName, string propertyName) + { + if (this.MappingColumns.HasValue()) + { + var mappingInfo = this.MappingColumns.SingleOrDefault(it => it.EntityName == entityName && it.PropertyName == propertyName); + return (mappingInfo == null ? propertyName : mappingInfo.DbColumnName).ToLower(isAutoToLower); + } + else + { + return propertyName.ToLower(isAutoToLower); + } + } + + public string GetValue(object entityValue) + { + if (entityValue == null) + return null; + var type = UtilMethods.GetUnderType(entityValue.GetType()); + if (UtilConstants.NumericalTypes.Contains(type)) + { + return entityValue.ToString(); + } + else if (type == UtilConstants.DateType) + { + return this.DbMehtods.ToDate(new MethodCallExpressionModel() + { + Args = new System.Collections.Generic.List() { + new MethodCallExpressionArgs(){ MemberName=$"'{entityValue}'" } + } + }); + } + else + { + return this.DbMehtods.ToString(new MethodCallExpressionModel() + { + Args = new System.Collections.Generic.List() { + new MethodCallExpressionArgs(){ MemberName=$"'{entityValue}'" } + } + }); + } + } + } + public class DuckDBMethod : DefaultDbMethod, IDbMethods + { + + public override string GetDateString(string dateValue, string formatString) + { + if (!(formatString?.Contains("24") == true)) + { + formatString = formatString.Replace("HH", "hh24"); + if (!(formatString?.Contains("24") == true)) + { + formatString = formatString.Replace("hh", "hh24"); + } + } + formatString = formatString.Replace("mm", "mi"); + return $"to_char({dateValue},'{formatString}') "; + } + public override string CharIndex(MethodCallExpressionModel model) + { + return string.Format(" (strpos ({1},{0})-1)", model.Args[0].MemberName, model.Args[1].MemberName); + } + public override string TrueValue() + { + return "true"; + } + public override string FalseValue() + { + return "false"; + } + public override string DateDiff(MethodCallExpressionModel model) + { + var parameter = (DateType)(Enum.Parse(typeof(DateType), model.Args[0].MemberValue.ObjToString())); + var begin = model.Args[1].MemberName; + var end = model.Args[2].MemberName; + switch (parameter) + { + case DateType.Year: + return $" ( DATE_PART('Year', {end} ) - DATE_PART('Year', {begin}) )"; + case DateType.Month: + return $" ( ( DATE_PART('Year', {end} ) - DATE_PART('Year', {begin}) ) * 12 + (DATE_PART('month', {end}) - DATE_PART('month', {begin})) )"; + case DateType.Day: + return $" ( DATE_PART('day', {end} - {begin}) )"; + case DateType.Hour: + return $" ( ( DATE_PART('day', {end} - {begin}) ) * 24 + DATE_PART('hour', {end} - {begin} ) )"; + case DateType.Minute: + return $" ( ( ( DATE_PART('day', {end} - {begin}) ) * 24 + DATE_PART('hour', {end} - {begin} ) ) * 60 + DATE_PART('minute', {end} - {begin} ) )"; + case DateType.Second: + return $" ( ( ( DATE_PART('day', {end} - {begin}) ) * 24 + DATE_PART('hour', {end} - {begin} ) ) * 60 + DATE_PART('minute', {end} - {begin} ) ) * 60 + DATE_PART('second', {end} - {begin} )"; + case DateType.Millisecond: + break; + default: + break; + } + throw new Exception(parameter + " datediff no support"); + } + public override string IIF(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + var parameter2 = model.Args[1]; + var parameter3 = model.Args[2]; + if (parameter.Type == UtilConstants.BoolType) + { + parameter.MemberName = parameter.MemberName.ToString().Replace("=1", "=true"); + parameter2.MemberName = false; + parameter3.MemberName = true; + } + return string.Format("( CASE WHEN {0} THEN {1} ELSE {2} END )", parameter.MemberName, parameter2.MemberName, parameter3.MemberName); + } + public override string DateValue(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + var parameter2 = model.Args[1]; + var format = "dd"; + if (parameter2.MemberValue.ObjToString() == DateType.Year.ToString()) + { + format = "yyyy"; + } + if (parameter2.MemberValue.ObjToString() == DateType.Month.ToString()) + { + format = "MM"; + } + if (parameter2.MemberValue.ObjToString() == DateType.Day.ToString()) + { + format = "dd"; + } + if (parameter2.MemberValue.ObjToString() == DateType.Hour.ToString()) + { + format = "hh"; + } + if (parameter2.MemberValue.ObjToString() == DateType.Minute.ToString()) + { + format = "mi"; + } + if (parameter2.MemberValue.ObjToString() == DateType.Second.ToString()) + { + format = "ss"; + } + if (parameter2.MemberValue.ObjToString() == DateType.Millisecond.ToString()) + { + format = "ms"; + } + if (parameter2.MemberValue.ObjToString() == DateType.Weekday.ToString()) + { + return $" extract(DOW FROM cast({parameter.MemberName} as TIMESTAMP)) "; + } + + return string.Format(" cast( to_char({1},'{0}')as integer ) ", format, parameter.MemberName); + } + + public override string Contains(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + var parameter2 = model.Args[1]; + return string.Format(" ({0} like concat('%',{1},'%')) ", parameter.MemberName, parameter2.MemberName ); + } + + public override string StartsWith(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + var parameter2 = model.Args[1]; + return string.Format(" ({0} like concat({1},'%')) ", parameter.MemberName, parameter2.MemberName); + } + + public override string EndsWith(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + var parameter2 = model.Args[1]; + return string.Format(" ({0} like concat('%',{1}))", parameter.MemberName,parameter2.MemberName); + } + + public override string DateIsSameDay(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + var parameter2 = model.Args[1]; + return string.Format(" ( to_char({0},'yyyy-MM-dd')=to_char({1},'yyyy-MM-dd') ) ", parameter.MemberName, parameter2.MemberName); ; + } + + public override string HasValue(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + return string.Format("( {0} IS NOT NULL )", parameter.MemberName); + } + + public override string DateIsSameByType(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + var parameter2 = model.Args[1]; + var parameter3 = model.Args[2]; + DateType dateType =(DateType)parameter3.MemberValue; + var format = "yyyy-MM-dd"; + if (dateType == DateType.Quarter) + { + return string.Format(" (date_trunc('quarter',{0})=date_trunc('quarter',{1}) ) ", parameter.MemberName, parameter2.MemberName,format); + } + switch (dateType) + { + case DateType.Year: + format = "yyyy"; + break; + case DateType.Month: + format = "yyyy-MM"; + break; + case DateType.Day: + break; + case DateType.Hour: + format = "yyyy-MM-dd HH"; + break; + case DateType.Second: + format = "yyyy-MM-dd HH:mm:ss"; + break; + case DateType.Minute: + format = "yyyy-MM-dd HH:mm"; + break; + case DateType.Millisecond: + format = "yyyy-MM-dd HH:mm.ms"; + break; + default: + break; + } + return string.Format(" ( to_char({0},'{2}')=to_char({1},'{2}') ) ", parameter.MemberName, parameter2.MemberName, format); + } + + public override string ToDate(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + return string.Format(" CAST({0} AS timestamp)", parameter.MemberName); + } + public override string DateAddByType(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + var parameter2 = model.Args[1]; + var parameter3 = model.Args[2]; + return string.Format(" ({1} + ({2}||'{0}')::INTERVAL) ", parameter3.MemberValue, parameter.MemberName, parameter2.MemberName); + } + + public override string DateAddDay(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + var parameter2 = model.Args[1]; + return string.Format(" ({0} + ({1}||'day')::INTERVAL) ", parameter.MemberName, parameter2.MemberName); + } + + public override string ToInt32(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + return string.Format(" CAST({0} AS INT4)", parameter.MemberName); + } + + public override string ToInt64(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + return string.Format(" CAST({0} AS INT8)", parameter.MemberName); + } + + public override string ToString(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + return string.Format(" CAST({0} AS VARCHAR)", parameter.MemberName); + } + + public override string ToGuid(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + return string.Format(" CAST({0} AS UUID)", parameter.MemberName); + } + + public override string ToDouble(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + return string.Format(" CAST({0} AS DECIMAL(18,4))", parameter.MemberName); + } + + public override string ToBool(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + return string.Format(" CAST({0} AS boolean)", parameter.MemberName); + } + + public override string ToDecimal(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + return string.Format(" CAST({0} AS DECIMAL(18,4))", parameter.MemberName); + } + + public override string Length(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + return string.Format(" LENGTH({0})", parameter.MemberName); + } + public override string MergeString(params string[] strings) + { + return " concat("+string.Join(",", strings).Replace("+", "") + ") "; + } + public override string IsNull(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + var parameter1 = model.Args[1]; + return string.Format("(CASE WHEN {0} IS NULL THEN {1} ELSE {0} END)", parameter.MemberName, parameter1.MemberName); + } + public override string GetDate() + { + return "NOW()"; + } + public override string GetRandom() + { + return "RANDOM()"; + } + + public override string EqualTrue(string fieldName) + { + return "( " + fieldName + "=true )"; + } + + public override string JsonField(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + var parameter1 = model.Args[1]; + //var parameter2 = model.Args[2]; + //var parameter3= model.Args[3]; + var result= GetJson(parameter.MemberName, parameter1.MemberName, model.Args.Count()==2); + if (model.Args.Count > 2) + { + result = GetJson(result, model.Args[2].MemberName, model.Args.Count() == 3); + } + if (model.Args.Count > 3) + { + result = GetJson(result, model.Args[3].MemberName, model.Args.Count() == 4); + } + if (model.Args.Count > 4) + { + result = GetJson(result, model.Args[4].MemberName, model.Args.Count() == 5); + } + if (model.Args.Count > 5) + { + result = GetJson(result, model.Args[5].MemberName, model.Args.Count() == 6); + } + return result; + } + + public override string JsonContainsFieldName(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + var parameter1 = model.Args[1]; + return $"({parameter.MemberName}::jsonb ?{parameter1.MemberName})"; + } + + private string GetJson(object memberName1, object memberName2,bool isLast) + { + if (isLast) + { + return $"({memberName1}::json->>{memberName2})"; + } + else + { + return $"({memberName1}->{memberName2})"; + } + } + + public override string JsonArrayLength(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + //var parameter1 = model.Args[1]; + return $" json_array_length({parameter.MemberName}::json) "; + } + + public override string JsonParse(MethodCallExpressionModel model) + { + var parameter = model.Args[0]; + //var parameter1 = model.Args[1]; + return $" ({parameter.MemberName}::json) "; + } + + public override string JsonArrayAny(MethodCallExpressionModel model) + { + if (SqlSugar.UtilMethods.IsNumber(model.Args[1].MemberValue.GetType().Name)) + { + return $" {model.Args[0].MemberName}::jsonb @> '[{model.Args[1].MemberValue.ObjToStringNoTrim().ToSqlFilter()}]'::jsonb"; + } + else + { + return $" {model.Args[0].MemberName}::jsonb @> '[\"{model.Args[1].MemberValue}\"]'::jsonb"; + } + } + public override string JsonListObjectAny(MethodCallExpressionModel model) + { + if (SqlSugar.UtilMethods.IsNumber(model.Args[2].MemberValue.GetType().Name)) + { + return $" {model.Args[0].MemberName}::jsonb @> '[{{\"{model.Args[1].MemberValue}\":{model.Args[2].MemberValue}}}]'::jsonb"; + } + else + { + return $" {model.Args[0].MemberName}::jsonb @> '[{{\"{model.Args[1].MemberValue}\":\"{model.Args[2].MemberValue.ObjToStringNoTrim().ToSqlFilter()}\"}}]'::jsonb"; + } + } + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBFastBuilder.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBFastBuilder.cs new file mode 100644 index 000000000..937c3e531 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBFastBuilder.cs @@ -0,0 +1,19 @@ +using DuckDB; +using DuckDB.NET.Data; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SqlSugar.DuckDB +{ + public class DuckDBFastBuilder : FastBuilder, IFastBuilder + { + public Task ExecuteBulkCopyAsync(DataTable dt) + { + throw new NotImplementedException(); + } + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBInsertBuilder.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBInsertBuilder.cs new file mode 100644 index 000000000..280d182b4 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBInsertBuilder.cs @@ -0,0 +1,178 @@ +using System; +using System.Linq; +using System.Text; + +namespace SqlSugar.DuckDB +{ + public class DuckDBInsertBuilder : InsertBuilder + { + public override string SqlTemplate + { + get + { + if (IsReturnIdentity) + { + return @"INSERT INTO {0} + ({1}) + VALUES + ({2}) returning $PrimaryKey"; + } + else + { + return @"INSERT INTO {0} + ({1}) + VALUES + ({2}) ;"; + + } + } + } + public override string SqlTemplateBatch => "INSERT INTO {0} ({1})"; + public override string SqlTemplateBatchUnion => " VALUES "; + + public override string SqlTemplateBatchSelect => " {0} "; + + public override Func ConvertInsertReturnIdFunc { get; set; } = (name, sql) => + { + return sql.Trim().TrimEnd(';')+ $"returning {name} "; + }; + public override string ToSqlString() + { + if (IsNoInsertNull) + { + DbColumnInfoList = DbColumnInfoList.Where(it => it.Value != null).ToList(); + } + var groupList = DbColumnInfoList.GroupBy(it => it.TableId).ToList(); + var isSingle = groupList.Count() == 1; + string columnsString = string.Join(",", groupList.First().Select(it => Builder.GetTranslationColumnName(it.DbColumnName))); + if (isSingle) + { + string columnParametersString = string.Join(",", this.DbColumnInfoList.Select(it =>base.GetDbColumn(it, Builder.SqlParameterKeyWord + it.DbColumnName))); + ActionMinDate(); + return string.Format(SqlTemplate, GetTableNameString, columnsString, columnParametersString); + } + else + { + StringBuilder batchInsetrSql = new StringBuilder(); + int pageSize = 200; + int pageIndex = 1; + if (IsNoPage&&IsReturnPkList) + { + pageSize = groupList.Count; + } + int totalRecord = groupList.Count; + int pageCount = (totalRecord + pageSize - 1) / pageSize; + while (pageCount >= pageIndex) + { + batchInsetrSql.AppendFormat(SqlTemplateBatch, GetTableNameString, columnsString); + int i = 0; + foreach (var columns in groupList.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList()) + { + var isFirst = i == 0; + if (isFirst) + { + batchInsetrSql.Append(SqlTemplateBatchUnion); + } + batchInsetrSql.Append("\r\n ( " + string.Join(",", columns.Select(it => + { + if (it.InsertServerTime || it.InsertSql.HasValue()||it.SqlParameterDbType is Type|| it?.PropertyType?.Name=="DateOnly" || it?.PropertyType?.Name == "TimeOnly") + { + return GetDbColumn(it, null); + } + object value = null; + if (it.Value is DateTime) + { + value = ((DateTime)it.Value).ToString("O"); + } + else if (it.Value is DateTimeOffset) + { + return FormatDateTimeOffset(it.Value); + } + else if (it.IsArray&&it.Value!=null) + { + return FormatValue(it.Value,it.PropertyName,i,it); + } + else + { + value = it.Value; + } + if (value == null||value==DBNull.Value) + { + return string.Format(SqlTemplateBatchSelect, "NULL"); + } + return string.Format(SqlTemplateBatchSelect, "'" + value.ObjToStringNoTrim().ToSqlFilter() + "'"); + })) + "),"); + ++i; + } + pageIndex++; + batchInsetrSql.Remove(batchInsetrSql.Length - 1,1).Append("\r\n;\r\n"); + } + return batchInsetrSql.ToString(); + } + } + + public object FormatValue(object value, string name, int i, DbColumnInfo columnInfo) + { + if (value == null) + { + return "NULL"; + } + else + { + var type = value.GetType(); + if (type == UtilConstants.DateType || columnInfo.IsArray || columnInfo.IsJson) + { + var parameterName = this.Builder.SqlParameterKeyWord + name + i; + var paramter = new SugarParameter(parameterName, value); + if (columnInfo.IsJson) + { + paramter.IsJson = true; + } + if (columnInfo.IsArray) + { + paramter.IsArray = true; + } + this.Parameters.Add(paramter); + return parameterName; + } + else if (type == UtilConstants.ByteArrayType) + { + string bytesString = "0x" + BitConverter.ToString((byte[])value); + return bytesString; + } + else if (type.IsEnum()) + { + if (this.Context.CurrentConnectionConfig.MoreSettings?.TableEnumIsString == true) + { + return value.ToSqlValue(); + } + else + { + return Convert.ToInt64(value); + } + } + else if (type == UtilConstants.DateTimeOffsetType) + { + return FormatDateTimeOffset(value); + } + else if (type == UtilConstants.BoolType) + { + return value.ObjToBool() ? "1" : "0"; + } + else if (type == UtilConstants.StringType || type == UtilConstants.ObjType) + { + return "'" + value.ToString().ToSqlFilter() + "'"; + } + else + { + return "'" + value.ToString() + "'"; + } + } + } + public override string FormatDateTimeOffset(object value) + { + return "'" + ((DateTimeOffset)value).ToString("o") + "'"; + } + + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBQueryBuilder.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBQueryBuilder.cs new file mode 100644 index 000000000..dea54de51 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBQueryBuilder.cs @@ -0,0 +1,121 @@ +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace SqlSugar.DuckDB +{ + public partial class DuckDBQueryBuilder : QueryBuilder + { + #region Sql Template + public override string PageTempalte + { + get + { + /* + SELECT * FROM TABLE WHERE CONDITION ORDER BY ID DESC LIMIT 10 offset 0 + */ + var template = "SELECT {0} FROM {1} {2} {3} {4} LIMIT {6} offset {5}"; + return template; + } + } + public override string DefaultOrderByTemplate + { + get + { + return "ORDER BY NOW() "; + } + } + + #endregion + + #region Common Methods + public override string GetTableNameString + { + get + { + if (this.TableShortName != null&&this.Context.CurrentConnectionConfig?.MoreSettings?.PgSqlIsAutoToLower==false) + { + this.TableShortName = Builder.GetTranslationColumnName(this.TableShortName); + } + return base.GetTableNameString; + } + } + public override bool IsComplexModel(string sql) + { + return Regex.IsMatch(sql, @"AS ""\w+\.\w+""")|| Regex.IsMatch(sql, @"AS ""\w+\.\w+\.\w+"""); + } + public override string ToSqlString() + { + base.AppendFilter(); + string oldOrderValue = this.OrderByValue; + string result = null; + sql = new StringBuilder(); + sql.AppendFormat(SqlTemplate, GetSelectValue, GetTableNameString, GetWhereValueString, GetGroupByString + HavingInfos, (Skip != null || Take != null) ? null : GetOrderByString); + if (IsCount) { return sql.ToString(); } + if (Skip != null && Take == null) + { + if (this.OrderByValue == "ORDER BY ") this.OrderByValue += GetSelectValue.Split(',')[0]; + result = string.Format(PageTempalte, GetSelectValue, GetTableNameString, GetWhereValueString, GetGroupByString + HavingInfos, (Skip != null || Take != null) ? null : GetOrderByString, Skip.ObjToInt(), long.MaxValue); + } + else if (Skip == null && Take != null) + { + if (this.OrderByValue == "ORDER BY ") this.OrderByValue += GetSelectValue.Split(',')[0]; + result = string.Format(PageTempalte, GetSelectValue, GetTableNameString, GetWhereValueString, GetGroupByString + HavingInfos, GetOrderByString, 0, Take.ObjToInt()); + } + else if (Skip != null && Take != null) + { + if (this.OrderByValue == "ORDER BY ") this.OrderByValue += GetSelectValue.Split(',')[0]; + result = string.Format(PageTempalte, GetSelectValue, GetTableNameString, GetWhereValueString, GetGroupByString + HavingInfos, GetOrderByString, Skip.ObjToInt() > 0 ? Skip.ObjToInt() : 0, Take); + } + else + { + result = sql.ToString(); + } + this.OrderByValue = oldOrderValue; + result = GetSqlQuerySql(result); + if (result.IndexOf("-- No table") > 0) + { + return "-- No table"; + } + if (TranLock != null) + { + result = result + TranLock; + } + return result; + } + + #endregion + + #region Get SQL Partial + public override string GetSelectValue + { + get + { + string result = string.Empty; + if (this.SelectValue == null || this.SelectValue is string) + { + result = GetSelectValueByString(); + } + else + { + result = GetSelectValueByExpression(); + } + if (this.SelectType == ResolveExpressType.SelectMultiple) + { + this.SelectCacheKey = this.SelectCacheKey + string.Join("-", this.JoinQueryInfos.Select(it => it.TableName)); + } + if (IsDistinct) + { + result = "distinct "+result; + } + if (this.SubToListParameters != null && this.SubToListParameters.Any()) + { + result = SubToListMethod(result); + } + return result; + } + } + + #endregion + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBUpdateBuilder.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBUpdateBuilder.cs new file mode 100644 index 000000000..07fdac430 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDB/SqlBuilder/DuckDBUpdateBuilder.cs @@ -0,0 +1,249 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SqlSugar.DuckDB +{ + public class DuckDBUpdateBuilder : UpdateBuilder + { + public override string SqlTemplateBatch + { + get + { + return @"UPDATE {1} {2} SET {0} FROM ${{0}} "; + } + } + public override string SqlTemplateJoin + { + get + { + return @" (VALUES + {0} + + ) AS T ({2}) WHERE {1} + "; + } + } + + public override string SqlTemplateBatchUnion + { + get + { + return ","; + } + } + + public object FormatValue(object value,string name,int i,DbColumnInfo columnInfo) + { + if (value == null) + { + return "NULL"; + } + else + { + var type =UtilMethods.GetUnderType(value.GetType()); + if (type == UtilConstants.DateType||columnInfo.IsArray||columnInfo.IsJson) + { + var parameterName = this.Builder.SqlParameterKeyWord + name + i; + var paramter = new SugarParameter(parameterName, value); + if (columnInfo.IsJson) + { + paramter.IsJson = true; + } + if (columnInfo.IsArray) + { + paramter.IsArray = true; + } + this.Parameters.Add(paramter); + return parameterName; + } + else if (type == UtilConstants.DateTimeOffsetType) + { + return FormatDateTimeOffset(value); + } + else if (type == UtilConstants.ByteArrayType) + { + string bytesString = "0x" + BitConverter.ToString((byte[])value); + return bytesString; + } + else if (type.IsEnum()) + { + if (this.Context.CurrentConnectionConfig.MoreSettings?.TableEnumIsString == true) + { + return value.ToSqlValue(); + } + else + { + return Convert.ToInt64(value); + } + } + else if (type == UtilConstants.BoolType) + { + return value.ObjToBool() ? "1" : "0"; + } + else if (type == UtilConstants.StringType || type == UtilConstants.ObjType) + { + return "'" + value.ToString().ToSqlFilter() + "'"; + } + else + { + return "'" + value.ToString() + "'"; + } + } + } + + protected override string TomultipleSqlString(List> groupList) + { + Check.Exception(PrimaryKeys == null || PrimaryKeys.Count == 0, " Update List need Primary key"); + int pageSize = 200; + int pageIndex = 1; + int totalRecord = groupList.Count; + int pageCount = (totalRecord + pageSize - 1) / pageSize; + StringBuilder batchUpdateSql = new StringBuilder(); + while (pageCount >= pageIndex) + { + StringBuilder updateTable = new StringBuilder(); + string setValues = string.Join(",", groupList.First().Where(it => it.IsPrimarykey == false && (it.IsIdentity == false || (IsOffIdentity && it.IsIdentity))).Select(it => + { + if (SetValues.IsValuable()) + { + var setValue = SetValues.Where(sv => sv.Key == Builder.GetTranslationColumnName(it.DbColumnName)); + if (setValue != null && setValue.Any()) + { + return setValue.First().Value; + } + } + var result = string.Format("{0}=T.{0}", Builder.GetTranslationColumnName(it.DbColumnName)); + return result; + })); + string tempColumnValue = string.Join(",", groupList.First().Select(it => + { + if (SetValues.IsValuable()) + { + var setValue = SetValues.Where(sv => sv.Key == Builder.GetTranslationColumnName(it.DbColumnName)); + if (setValue != null && setValue.Any()) + { + return setValue.First().Value; + } + } + var result = Builder.GetTranslationColumnName(it.DbColumnName); + return result; + })); + batchUpdateSql.AppendFormat(SqlTemplateBatch.ToString(), setValues, GetTableNameStringNoWith, TableWithString); + int i = 0; + var tableColumnList = this.Context.DbMaintenance.GetColumnInfosByTableName(GetTableNameStringNoWith); + + foreach (var columns in groupList.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList()) + { + var isFirst = i == 0; + if (!isFirst) + { + updateTable.Append(SqlTemplateBatchUnion); + } + updateTable.Append("\r\n (" + string.Join(",", columns.Select(it => + { + var columnInfo = tableColumnList.FirstOrDefault(x => x.DbColumnName.Equals(it.DbColumnName, StringComparison.OrdinalIgnoreCase)); + var dbType = columnInfo?.DataType; + if (dbType == null) { + var typeName = it.PropertyType.Name.ToLower(); + if (columnInfo==null&&it.PropertyType.IsEnum) + { + if (this.Context.CurrentConnectionConfig?.MoreSettings?.TableEnumIsString!=true) + { + typeName = "int"; + } + } + if (typeName == "int32") + typeName = "int"; + if (typeName == "int64") + typeName = "long"; + if (typeName == "int16") + typeName = "short"; + if (typeName == "boolean") + typeName = "bool"; + + var isAnyType = DuckDBDbBind.MappingTypesConst.Where(x => x.Value.ToString().ToLower() == typeName).Any(); + if (isAnyType) + { + dbType = DuckDBDbBind.MappingTypesConst.Where(x => x.Value.ToString().ToLower() == typeName).FirstOrDefault().Key; + } + else { + dbType = "varchar"; + } + } + return string.Format("CAST({0} AS {1})", base.GetDbColumn(it,FormatValue(it.Value,it.DbColumnName,i,it)), dbType); + + })) + ")"); + ++i; + } + pageIndex++; + updateTable.Append("\r\n"); + string whereString = null; + if (this.WhereValues.HasValue()) + { + foreach (var item in WhereValues) + { + var isFirst = whereString == null; + whereString += (isFirst ? null : " AND "); + whereString += item; + } + } + else if (PrimaryKeys.HasValue()) + { + foreach (var item in PrimaryKeys) + { + var isFirst = whereString == null; + whereString += (isFirst ? null : " AND "); + whereString += string.Format("{0}.{1}=T.{1}", GetTableNameStringNoWith, Builder.GetTranslationColumnName(item)); + } + } + var format = string.Format(SqlTemplateJoin, updateTable, whereString, tempColumnValue); + batchUpdateSql.Replace("${0}", format); + batchUpdateSql.Append(";"); + } + batchUpdateSql = GetBatchUpdateSql(batchUpdateSql); + return batchUpdateSql.ToString(); + } + + private StringBuilder GetBatchUpdateSql(StringBuilder batchUpdateSql) + { + if (ReSetValueBySqlExpListType == null && ReSetValueBySqlExpList != null) + { + var result = batchUpdateSql.ToString(); + foreach (var item in ReSetValueBySqlExpList) + { + var dbColumnName = item.Value.DbColumnName; + if (item.Value.Type == ReSetValueBySqlExpListModelType.List) + { + result = result.Replace($"{dbColumnName}=T.{dbColumnName}", $"{dbColumnName}={GetTableNameString}.{dbColumnName}{item.Value.Sql}T.{dbColumnName}"); + } + else + { + result = result.Replace($"{dbColumnName}=T.{dbColumnName}", $"{dbColumnName}={item.Value.Sql.Replace(dbColumnName, $"{Builder.GetTranslationColumnName(this.TableName)}.{dbColumnName}")}"); + } + batchUpdateSql = new StringBuilder(result); + } + } + + return batchUpdateSql; + } + protected override string GetJoinUpdate(string columnsString, ref string whereString) + { + var formString = $" {Builder.GetTranslationColumnName(this.TableName)} AS {Builder.GetTranslationColumnName(this.ShortName)} "; + var joinString = ""; + foreach (var item in this.JoinInfos) + { + whereString += " AND "+item.JoinWhere; + joinString += $"\r\n FROM {Builder.GetTranslationColumnName(item.TableName)} {Builder.GetTranslationColumnName(item.ShortName)} "; + } + var tableName = formString + "\r\n "; + columnsString = columnsString.Replace(Builder.GetTranslationColumnName(this.ShortName)+".","")+joinString; + return string.Format(SqlTemplate, tableName, columnsString, whereString); + } + public override string FormatDateTimeOffset(object value) + { + return "'" + ((DateTimeOffset)value).ToString("o") + "'"; + } + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDBDataAdapter.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDBDataAdapter.cs new file mode 100644 index 000000000..e905ca847 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/DuckDBDataAdapter.cs @@ -0,0 +1,144 @@ +using DuckDB; +using DuckDB.NET.Data; +using System; +using System.Collections.Generic; +using System.Data; +using System.Text; + +namespace SqlSugar +{ + /// + /// 数据填充器 + /// + public class DuckDBDataAdapter : IDataAdapter + { + private DuckDBCommand command; + private string sql; + private DuckDBConnection _sqlConnection; + + /// + /// SqlDataAdapter + /// + /// + public DuckDBDataAdapter(DuckDBCommand command) + { + this.command = command; + } + + public DuckDBDataAdapter() + { + + } + + /// + /// SqlDataAdapter + /// + /// + /// + public DuckDBDataAdapter(string sql, DuckDBConnection _sqlConnection) + { + this.sql = sql; + this._sqlConnection = _sqlConnection; + } + + /// + /// SelectCommand + /// + public DuckDBCommand SelectCommand + { + get + { + if (this.command == null) + { + this.command = new DuckDBCommand(this.sql, this._sqlConnection); + } + return this.command; + } + set + { + this.command = value; + } + } + + /// + /// Fill + /// + /// + public void Fill(DataTable dt) + { + if (dt == null) + { + dt = new DataTable(); + } + var columns = dt.Columns; + var rows = dt.Rows; + using (DuckDBDataReader dr = command.ExecuteReader()) + { + for (int i = 0; i < dr.FieldCount; i++) + { + string name = dr.GetName(i).Trim(); + if (!columns.Contains(name)) + columns.Add(new DataColumn(name, dr.GetFieldType(i))); + else + { + columns.Add(new DataColumn(name + i, dr.GetFieldType(i))); + } + } + + while (dr.Read()) + { + DataRow daRow = dt.NewRow(); + for (int i = 0; i < columns.Count; i++) + { + daRow[columns[i].ColumnName] = dr.GetValue(i); + } + dt.Rows.Add(daRow); + } + } + dt.AcceptChanges(); + } + + /// + /// Fill + /// + /// + public void Fill(DataSet ds) + { + if (ds == null) + { + ds = new DataSet(); + } + using (DuckDBDataReader dr = command.ExecuteReader()) + { + do + { + var dt = new DataTable(); + var columns = dt.Columns; + var rows = dt.Rows; + for (int i = 0; i < dr.FieldCount; i++) + { + string name = dr.GetName(i).Trim(); + if (!columns.Contains(name)) + columns.Add(new DataColumn(name, dr.GetFieldType(i))); + else + { + columns.Add(new DataColumn(name + i, dr.GetFieldType(i))); + } + } + + while (dr.Read()) + { + DataRow daRow = dt.NewRow(); + for (int i = 0; i < columns.Count; i++) + { + daRow[columns[i].ColumnName] = dr.GetValue(i); + } + dt.Rows.Add(daRow); + } + dt.AcceptChanges(); + ds.Tables.Add(dt); + } while (dr.NextResult()); + } + } + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/SqlSugar.DuckDBCore.csproj b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/SqlSugar.DuckDBCore.csproj new file mode 100644 index 000000000..7bb73a184 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/SqlSugar.DuckDBCore.csproj @@ -0,0 +1,16 @@ + + + + netstandard2.1 + enable + + + + + + + + + + + diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/ErrorMessage.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/ErrorMessage.cs new file mode 100644 index 000000000..a208149c1 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/ErrorMessage.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +namespace SqlSugar.DuckDB +{ + internal static partial class ErrorMessage + { + internal static LanguageType SugarLanguageType { get; set; } = LanguageType.Default; + internal static string ObjNotExist + { + get + { + return GetThrowMessage("{0} does not exist.", + "{0}不存在。"); + } + } + internal static string EntityMappingError + { + get + { + return GetThrowMessage("Entity mapping error.{0}", + "实体与表映射出错。{0}"); + } + } + + public static string NotSupportedDictionary + { + get + { + return GetThrowMessage("This type of Dictionary is not supported for the time being. You can try Dictionary, or contact the author!!", + "暂时不支持该类型的Dictionary 你可以试试 Dictionary或者联系作者!!"); + } + } + + public static string NotSupportedArray + { + get + { + return GetThrowMessage("This type of Array is not supported for the time being. You can try object[] or contact the author!!", + "暂时不支持该类型的Array 你可以试试 object[] 或者联系作者!!"); + } + } + + internal static string GetThrowMessage(string enMessage, string cnMessage, params string[] args) + { + if (SugarLanguageType == LanguageType.Default) + { + List formatArgs = new List() { enMessage, cnMessage }; + formatArgs.AddRange(args); + return string.Format(@"中文提示 : {1} +English Message : {0}", formatArgs.ToArray()); + } + else if (SugarLanguageType == LanguageType.English) + { + return enMessage; + } + else + { + return cnMessage; + } + } + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/FileHelper.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/FileHelper.cs new file mode 100644 index 000000000..87f2b3dfd --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/FileHelper.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace SqlSugar.DuckDB +{ + internal class FileHelper + { + public static void CreateFile(string filePath, string text, Encoding encoding) + { + try + { + if (IsExistFile(filePath)) + { + DeleteFile(filePath); + } + if (!IsExistFile(filePath)) + { + string directoryPath = GetDirectoryFromFilePath(filePath); + CreateDirectory(directoryPath); + + //Create File + FileInfo file = new FileInfo(filePath); + using (FileStream stream = file.Create()) + { + using (StreamWriter writer = new StreamWriter(stream, encoding)) + { + writer.Write(text); + writer.Flush(); + } + } + } + } + catch(Exception ex) + { + throw ex; + } + } + public static bool IsExistDirectory(string directoryPath) + { + return Directory.Exists(directoryPath); + } + public static void CreateDirectory(string directoryPath) + { + if (!IsExistDirectory(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + } + public static void DeleteFile(string filePath) + { + if (IsExistFile(filePath)) + { + File.Delete(filePath); + } + } + public static string GetDirectoryFromFilePath(string filePath) + { + FileInfo file = new FileInfo(filePath); + DirectoryInfo directory = file.Directory; + return directory.FullName; + } + public static bool IsExistFile(string filePath) + { + return File.Exists(filePath); + } + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/UtilConstants.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/UtilConstants.cs new file mode 100644 index 000000000..46df82ca1 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/UtilConstants.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq; +using System.Text; +namespace SqlSugar.DuckDB +{ + internal static class UtilConstants + { + public const string Dot = "."; + public const char DotChar = '.'; + internal const string Space = " "; + internal const char SpaceChar =' '; + internal const string AssemblyName = "SqlSugar"; + internal const string ReplaceKey = "{662E689B-17A1-4D06-9D27-F29EAB8BC3D6}"; + internal const string ReplaceCommaKey = "{112A689B-17A1-4A06-9D27-A39EAB8BC3D5}"; + + internal static Type IntType = typeof(int); + internal static Type LongType = typeof(long); + internal static Type GuidType = typeof(Guid); + internal static Type BoolType = typeof(bool); + internal static Type BoolTypeNull = typeof(bool?); + internal static Type ByteType = typeof(Byte); + internal static Type ObjType = typeof(object); + internal static Type DobType = typeof(double); + internal static Type FloatType = typeof(float); + internal static Type ShortType = typeof(short); + internal static Type DecType = typeof(decimal); + internal static Type StringType = typeof(string); + internal static Type DateType = typeof(DateTime); + internal static Type DateTimeOffsetType = typeof(DateTimeOffset); + internal static Type TimeSpanType = typeof(TimeSpan); + internal static Type ByteArrayType = typeof(byte[]); + internal static Type ModelType= typeof(ModelContext); + internal static Type DynamicType = typeof(ExpandoObject); + internal static Type Dicii = typeof(KeyValuePair); + internal static Type DicIS = typeof(KeyValuePair); + internal static Type DicSi = typeof(KeyValuePair); + internal static Type DicSS = typeof(KeyValuePair); + internal static Type DicOO = typeof(KeyValuePair); + internal static Type DicSo = typeof(KeyValuePair); + internal static Type DicArraySS = typeof(Dictionary); + internal static Type DicArraySO = typeof(Dictionary); + + public static Type SugarType = typeof(SqlSugarProvider); + + + internal static Type[] NumericalTypes = new Type[] + { + typeof(int), + typeof(uint), + typeof(byte), + typeof(sbyte), + typeof(long), + typeof(ulong), + typeof(short), + typeof(ushort), + }; + + + internal static string[] DateTypeStringList = new string[] + { + "Year", + "Month", + "Day", + "Hour", + "Second" , + "Minute", + "Millisecond", + "Date" + }; + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/UtilExtensions.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/UtilExtensions.cs new file mode 100644 index 000000000..91504f5c7 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/UtilExtensions.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +namespace SqlSugar.DuckDB +{ + /// + ///Common Extensions for external users + /// + public static class UtilExtensions + { + public static string ObjToStringNoTrim(this object thisValue) + { + if (thisValue != null) return thisValue.ToString(); + return ""; + } + public static string ToLower(this string value, bool isLower) + { + if (isLower) + { + return value.ObjToString().ToLower(); + } + return value.ObjToString(); + } + public static int ObjToInt(this object thisValue) + { + int reval = 0; + if (thisValue == null) return 0; + if (thisValue is Enum) + { + return (int)thisValue; + } + if (thisValue != null && thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval)) + { + return reval; + } + return reval; + } + + public static int ObjToInt(this object thisValue, int errorValue) + { + int reval = 0; + if (thisValue is Enum) + { + return (int)thisValue; + } + if (thisValue != null && thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval)) + { + return reval; + } + return errorValue; + } + + public static double ObjToMoney(this object thisValue) + { + double reval = 0; + if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval)) + { + return reval; + } + return 0; + } + + public static double ObjToMoney(this object thisValue, double errorValue) + { + double reval = 0; + if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval)) + { + return reval; + } + return errorValue; + } + + public static string ObjToString(this object thisValue) + { + if (thisValue != null) return thisValue.ToString().Trim(); + return ""; + } + + public static string ObjToString(this object thisValue, string errorValue) + { + if (thisValue != null) return thisValue.ToString().Trim(); + return errorValue; + } + + public static Decimal ObjToDecimal(this object thisValue) + { + Decimal reval = 0; + if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval)) + { + return reval; + } + return 0; + } + + public static Decimal ObjToDecimal(this object thisValue, decimal errorValue) + { + Decimal reval = 0; + if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval)) + { + return reval; + } + return errorValue; + } + + public static DateTime ObjToDate(this object thisValue) + { + DateTime reval = DateTime.MinValue; + if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval)) + { + reval = Convert.ToDateTime(thisValue); + } + return reval; + } + + public static DateTime ObjToDate(this object thisValue, DateTime errorValue) + { + DateTime reval = DateTime.MinValue; + if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval)) + { + return reval; + } + return errorValue; + } + + public static bool ObjToBool(this object thisValue) + { + bool reval = false; + if (thisValue != null && thisValue != DBNull.Value && bool.TryParse(thisValue.ToString(), out reval)) + { + return reval; + } + return reval; + } + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/UtilMethods.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/UtilMethods.cs new file mode 100644 index 000000000..1b379af0d --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/UtilMethods.cs @@ -0,0 +1,507 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; + +namespace SqlSugar.DuckDB +{ + public class UtilMethods + { + internal static DateTime GetMinDate(ConnectionConfig currentConnectionConfig) + { + if (currentConnectionConfig.MoreSettings == null) + { + return Convert.ToDateTime("1900-01-01"); + } + else if (currentConnectionConfig.MoreSettings.DbMinDate == null) + { + return Convert.ToDateTime("1900-01-01"); + } + else + { + return currentConnectionConfig.MoreSettings.DbMinDate.Value; + } + } + internal static DateTime ConvertFromDateTimeOffset(DateTimeOffset dateTime) + { + if (dateTime.Offset.Equals(TimeSpan.Zero)) + return dateTime.UtcDateTime; + else if (dateTime.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(dateTime.DateTime))) + return DateTime.SpecifyKind(dateTime.DateTime, DateTimeKind.Local); + else + return dateTime.DateTime; + } + + internal static object To(object value, Type destinationType) + { + return To(value, destinationType, CultureInfo.InvariantCulture); + } + + internal static object To(object value, Type destinationType, CultureInfo culture) + { + if (value != null) + { + destinationType = UtilMethods.GetUnderType(destinationType); + var sourceType = value.GetType(); + + var destinationConverter = TypeDescriptor.GetConverter(destinationType); + if (destinationConverter != null && destinationConverter.CanConvertFrom(value.GetType())) + return destinationConverter.ConvertFrom(null, culture, value); + + var sourceConverter = TypeDescriptor.GetConverter(sourceType); + if (sourceConverter != null && sourceConverter.CanConvertTo(destinationType)) + return sourceConverter.ConvertTo(null, culture, value, destinationType); + + if (destinationType.IsEnum && value is int) + return Enum.ToObject(destinationType, (int)value); + + if (!destinationType.IsInstanceOfType(value)) + return Convert.ChangeType(value, destinationType, culture); + } + return value; + } + public static bool IsAnyAsyncMethod(StackFrame[] methods) + { + bool isAsync = false; + foreach (var item in methods) + { + if (UtilMethods.IsAsyncMethod(item.GetMethod())) + { + isAsync = true; + break; + } + } + return isAsync; + } + + public static bool IsAsyncMethod(MethodBase method) + { + if (method == null) + { + return false; + } + if (method.DeclaringType != null) + { + if (method.DeclaringType.GetInterfaces().Contains(typeof(IAsyncStateMachine))) + { + return true; + } + } + var name = method.Name; + if (name.Contains("OutputAsyncCausalityEvents")) + { + return true; + } + if (name.Contains("OutputWaitEtwEvents")) + { + return true; + } + if (name.Contains("ExecuteAsync")) + { + return true; + } + Type attType = typeof(AsyncStateMachineAttribute); + var attrib = (AsyncStateMachineAttribute)method.GetCustomAttribute(attType); + return (attrib != null); + } + + public static StackTraceInfo GetStackTrace() + { + + StackTrace st = new StackTrace(true); + StackTraceInfo info = new StackTraceInfo(); + info.MyStackTraceList = new List(); + info.SugarStackTraceList = new List(); + for (int i = 0; i < st.FrameCount; i++) + { + var frame = st.GetFrame(i); + if (frame.GetMethod().Module.Name.ToLower() != "sqlsugar.dll" && frame.GetMethod().Name.First() != '<') + { + info.MyStackTraceList.Add(new StackTraceInfoItem() + { + FileName = frame.GetFileName(), + MethodName = frame.GetMethod().Name, + Line = frame.GetFileLineNumber() + }); + } + else + { + info.SugarStackTraceList.Add(new StackTraceInfoItem() + { + FileName = frame.GetFileName(), + MethodName = frame.GetMethod().Name, + Line = frame.GetFileLineNumber() + }); + } + } + return info; + } + + internal static T To(object value) + { + return (T)To(value, typeof(T)); + } + internal static Type GetUnderType(Type oldType) + { + Type type = Nullable.GetUnderlyingType(oldType); + return type == null ? oldType : type; + } + public static string ReplaceSqlParameter(string itemSql, SugarParameter itemParameter, string newName) + { + itemSql = Regex.Replace(itemSql, string.Format(@"{0} ", "\\" + itemParameter.ParameterName), newName + " ", RegexOptions.IgnoreCase); + itemSql = Regex.Replace(itemSql, string.Format(@"{0}\)", "\\" + itemParameter.ParameterName), newName + ")", RegexOptions.IgnoreCase); + itemSql = Regex.Replace(itemSql, string.Format(@"{0}\,", "\\" + itemParameter.ParameterName), newName + ",", RegexOptions.IgnoreCase); + itemSql = Regex.Replace(itemSql, string.Format(@"{0}$", "\\" + itemParameter.ParameterName), newName, RegexOptions.IgnoreCase); + itemSql = Regex.Replace(itemSql, string.Format(@"\+{0}\+", "\\" + itemParameter.ParameterName), "+" + newName + "+", RegexOptions.IgnoreCase); + itemSql = Regex.Replace(itemSql, string.Format(@"\+{0} ", "\\" + itemParameter.ParameterName), "+" + newName + " ", RegexOptions.IgnoreCase); + itemSql = Regex.Replace(itemSql, string.Format(@" {0}\+", "\\" + itemParameter.ParameterName), " " + newName + "+", RegexOptions.IgnoreCase); + itemSql = Regex.Replace(itemSql, string.Format(@"\|\|{0}\|\|", "\\" + itemParameter.ParameterName), "||" + newName + "||", RegexOptions.IgnoreCase); + itemSql = Regex.Replace(itemSql, string.Format(@"\={0}\+", "\\" + itemParameter.ParameterName), "=" + newName + "+", RegexOptions.IgnoreCase); + itemSql = Regex.Replace(itemSql, string.Format(@"{0}\|\|", "\\" + itemParameter.ParameterName), newName + "||", RegexOptions.IgnoreCase); + return itemSql; + } + internal static Type GetRootBaseType(Type entityType) + { + var baseType = entityType.BaseType; + while (baseType != null && baseType.BaseType != UtilConstants.ObjType) + { + baseType = baseType.BaseType; + } + return baseType; + } + + + internal static Type GetUnderType(PropertyInfo propertyInfo, ref bool isNullable) + { + Type unType = Nullable.GetUnderlyingType(propertyInfo.PropertyType); + isNullable = unType != null; + unType = unType ?? propertyInfo.PropertyType; + return unType; + } + + internal static Type GetUnderType(PropertyInfo propertyInfo) + { + Type unType = Nullable.GetUnderlyingType(propertyInfo.PropertyType); + unType = unType ?? propertyInfo.PropertyType; + return unType; + } + + internal static bool IsNullable(PropertyInfo propertyInfo) + { + Type unType = Nullable.GetUnderlyingType(propertyInfo.PropertyType); + return unType != null; + } + + internal static bool IsNullable(Type type) + { + Type unType = Nullable.GetUnderlyingType(type); + return unType != null; + } + //internal static T IsNullReturnNew(T returnObj) where T : new() + //{ + // if (returnObj.IsNullOrEmpty()) + // { + // returnObj = new T(); + // } + // return returnObj; + //} + public static object ChangeType2(object value, Type type) + { + if (value == null && type.IsGenericType) return Activator.CreateInstance(type); + if (value == null) return null; + if (type == value.GetType()) return value; + if (type.IsEnum) + { + if (value is string) + return Enum.Parse(type, value as string); + else + return Enum.ToObject(type, value); + } + if (!type.IsInterface && type.IsGenericType) + { + Type innerType = type.GetGenericArguments()[0]; + object innerValue = ChangeType(value, innerType); + return Activator.CreateInstance(type, new object[] { innerValue }); + } + if (value is string && type == typeof(Guid)) return new Guid(value as string); + if (value is string && type == typeof(Version)) return new Version(value as string); + if (!(value is IConvertible)) return value; + return Convert.ChangeType(value, type); + } + + internal static T ChangeType(T obj, Type type) + { + return (T)Convert.ChangeType(obj, type); + } + + internal static T ChangeType(T obj) + { + return (T)Convert.ChangeType(obj, typeof(T)); + } + + internal static DateTimeOffset GetDateTimeOffsetByDateTime(DateTime date) + { + date = DateTime.SpecifyKind(date, DateTimeKind.Utc); + DateTimeOffset utcTime2 = date; + return utcTime2; + } + + //internal static void RepairReplicationParameters(ref string appendSql, SugarParameter[] parameters, int addIndex, string append = null) + //{ + // if (appendSql.HasValue() && parameters.HasValue()) + // { + // foreach (var parameter in parameters.OrderByDescending(it => it.ParameterName.Length)) + // { + // //Compatible with.NET CORE parameters case + // var name = parameter.ParameterName; + // string newName = name + append + addIndex; + // appendSql = ReplaceSqlParameter(appendSql, parameter, newName); + // parameter.ParameterName = newName; + // } + // } + //} + + internal static string GetPackTable(string sql, string shortName) + { + return string.Format(" ({0}) {1} ", sql, shortName); + } + + public static Func GetTypeConvert(object value) + { + if (value is int || value is uint || value is int? || value is uint?) + { + return x => Convert.ToInt32(x); + } + else if (value is short || value is ushort || value is short? || value is ushort?) + { + return x => Convert.ToInt16(x); + } + else if (value is long || value is long? || value is ulong? || value is long?) + { + return x => Convert.ToInt64(x); + } + else if (value is DateTime|| value is DateTime?) + { + return x => Convert.ToDateTime(x); + } + else if (value is bool||value is bool?) + { + return x => Convert.ToBoolean(x); + } + return null; + } + + internal static string GetTypeName(object value) + { + if (value == null) + { + return null; + } + else + { + return value.GetType().Name; + } + } + + internal static string GetParenthesesValue(string dbTypeName) + { + if (Regex.IsMatch(dbTypeName, @"\(.+\)")) + { + dbTypeName = Regex.Replace(dbTypeName, @"\(.+\)", ""); + } + dbTypeName = dbTypeName.Trim(); + return dbTypeName; + } + + internal static T GetOldValue(T value, Action action) + { + action(); + return value; + } + + internal static object DefaultForType(Type targetType) + { + return targetType.IsValueType ? Activator.CreateInstance(targetType) : null; + } + + internal static Int64 GetLong(byte[] bytes) + { + return Convert.ToInt64(string.Join("", bytes).PadRight(20, '0')); + } + public static object GetPropertyValue(T t, string PropertyName) + { + return t.GetType().GetProperty(PropertyName).GetValue(t, null); + } + internal static string GetMD5(string myString) + { + MD5 md5 = new MD5CryptoServiceProvider(); + byte[] fromData = System.Text.Encoding.Unicode.GetBytes(myString); + byte[] targetData = md5.ComputeHash(fromData); + string byte2String = null; + + for (int i = 0; i < targetData.Length; i++) + { + byte2String += targetData[i].ToString("x"); + } + + return byte2String; + } + + //public static string EncodeBase64(string code) + //{ + // if (code.IsNullOrEmpty()) return code; + // string encode = ""; + // byte[] bytes = Encoding.GetEncoding("utf-8").GetBytes(code); + // try + // { + // encode = Convert.ToBase64String(bytes); + // } + // catch + // { + // encode = code; + // } + // return encode; + //} + public static string ConvertNumbersToString(string value) + { + string[] splitInt = value.Split(new char[] { '9' }, StringSplitOptions.RemoveEmptyEntries); + + var splitChars = splitInt.Select(s => Convert.ToChar( + Convert.ToInt32(s, 8) + ).ToString()); + + return string.Join("", splitChars); + } + public static string ConvertStringToNumbers(string value) + { + StringBuilder sb = new StringBuilder(); + + foreach (char c in value) + { + int cAscil = (int)c; + sb.Append(Convert.ToString(c, 8) + "9"); + } + + return sb.ToString(); + } + + //public static string DecodeBase64(string code) + //{ + // try + // { + // if (code.IsNullOrEmpty()) return code; + // string decode = ""; + // byte[] bytes = Convert.FromBase64String(code); + // try + // { + // decode = Encoding.GetEncoding("utf-8").GetString(bytes); + // } + // catch + // { + // decode = code; + // } + // return decode; + // } + // catch + // { + // return code; + // } + //} + + public static void DataInoveByExpresson(Type[] datas, MethodCallExpression callExpresion) + { + var methodInfo = callExpresion.Method; + foreach (var item in datas) + { + if (callExpresion.Arguments.Count == 0) + { + methodInfo.Invoke(item, null); + } + else + { + List methodParameters = new List(); + foreach (var callItem in callExpresion.Arguments) + { + var parameter = callItem.GetType().GetProperties().FirstOrDefault(it => it.Name == "Value"); + if (parameter == null) + { + var value = LambdaExpression.Lambda(callItem).Compile().DynamicInvoke(); + methodParameters.Add(value); + } + else + { + var value = parameter.GetValue(callItem, null); + methodParameters.Add(value); + } + } + methodInfo.Invoke(item, methodParameters.ToArray()); + } + } + } + + public static Dictionary EnumToDictionary() + { + Dictionary dic = new Dictionary(); + if (!typeof(T).IsEnum) + { + return dic; + } + string desc = string.Empty; + foreach (var item in Enum.GetValues(typeof(T))) + { + var key = item.ToString().ToLower(); + if (!dic.ContainsKey(key)) + dic.Add(key, (T)item); + } + return dic; + } + //public static object ConvertDataByTypeName(string ctypename,string value) + //{ + // var item = new ConditionalModel() { + // CSharpTypeName = ctypename, + // FieldValue = value + // }; + // if (item.CSharpTypeName.EqualCase(UtilConstants.DecType.Name)) + // { + // return Convert.ToDecimal(item.FieldValue); + // } + // else if (item.CSharpTypeName.EqualCase(UtilConstants.DobType.Name)) + // { + // return Convert.ToDouble(item.FieldValue); + // } + // else if (item.CSharpTypeName.EqualCase(UtilConstants.DateType.Name)) + // { + // return Convert.ToDateTime(item.FieldValue); + // } + // else if (item.CSharpTypeName.EqualCase(UtilConstants.IntType.Name)) + // { + // return Convert.ToInt32(item.FieldValue); + // } + // else if (item.CSharpTypeName.EqualCase(UtilConstants.LongType.Name)) + // { + // return Convert.ToInt64(item.FieldValue); + // } + // else if (item.CSharpTypeName.EqualCase(UtilConstants.ShortType.Name)) + // { + // return Convert.ToInt16(item.FieldValue); + // } + // else if (item.CSharpTypeName.EqualCase(UtilConstants.DateTimeOffsetType.Name)) + // { + // return UtilMethods.GetDateTimeOffsetByDateTime(Convert.ToDateTime(item.FieldValue)); + // } + // else + // { + // return item.FieldValue; + // } + //} + } +} diff --git a/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/ValidateExtensions.cs b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/ValidateExtensions.cs new file mode 100644 index 000000000..6b9f295b8 --- /dev/null +++ b/Src/Asp.NetCore2/SqlSugar.DuckDBCore/Tools/ValidateExtensions.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +namespace SqlSugar.DuckDB +{ + internal static class ValidateExtensions + { + public static bool IsInRange(this int thisValue, int begin, int end) + { + return thisValue >= begin && thisValue <= end; + } + + public static bool IsInRange(this DateTime thisValue, DateTime begin, DateTime end) + { + return thisValue >= begin && thisValue <= end; + } + + public static bool IsIn(this T thisValue, params T[] values) + { + return values.Contains(thisValue); + } + + public static bool IsContainsIn(this string thisValue, params string[] inValues) + { + return inValues.Any(it => thisValue.Contains(it)); + } + + public static bool IsNullOrEmpty(this object thisValue) + { + if (thisValue == null || thisValue == DBNull.Value) return true; + return thisValue.ToString() == ""; + } + + public static bool IsNullOrEmpty(this Guid? thisValue) + { + if (thisValue == null) return true; + return thisValue == Guid.Empty; + } + + public static bool IsNullOrEmpty(this Guid thisValue) + { + if (thisValue == null) return true; + return thisValue == Guid.Empty; + } + + public static bool IsNullOrEmpty(this IEnumerable thisValue) + { + if (thisValue == null || thisValue.Count() == 0) return true; + return false; + } + + public static bool HasValue(this object thisValue) + { + if (thisValue == null || thisValue == DBNull.Value) return false; + return thisValue.ToString() != ""; + } + + public static bool HasValue(this IEnumerable thisValue) + { + if (thisValue == null || thisValue.Count() == 0) return false; + return true; + } + + public static bool IsValuable(this IEnumerable> thisValue) + { + if (thisValue == null || thisValue.Count() == 0) return false; + return true; + } + + public static bool IsZero(this object thisValue) + { + return (thisValue == null || thisValue.ToString() == "0"); + } + + public static bool IsInt(this object thisValue) + { + if (thisValue == null) return false; + return Regex.IsMatch(thisValue.ToString(), @"^\d+$"); + } + + /// + public static bool IsNoInt(this object thisValue) + { + if (thisValue == null) return true; + return !Regex.IsMatch(thisValue.ToString(), @"^\d+$"); + } + + public static bool IsMoney(this object thisValue) + { + if (thisValue == null) return false; + double outValue = 0; + return double.TryParse(thisValue.ToString(), out outValue); + } + public static bool IsGuid(this object thisValue) + { + if (thisValue == null) return false; + Guid outValue = Guid.Empty; + return Guid.TryParse(thisValue.ToString(), out outValue); + } + + public static bool IsDate(this object thisValue) + { + if (thisValue == null) return false; + DateTime outValue = DateTime.MinValue; + return DateTime.TryParse(thisValue.ToString(), out outValue); + } + + public static bool IsEamil(this object thisValue) + { + if (thisValue == null) return false; + return Regex.IsMatch(thisValue.ToString(), @"^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$"); + } + + public static bool IsMobile(this object thisValue) + { + if (thisValue == null) return false; + return Regex.IsMatch(thisValue.ToString(), @"^\d{11}$"); + } + + public static bool IsTelephone(this object thisValue) + { + if (thisValue == null) return false; + return System.Text.RegularExpressions.Regex.IsMatch(thisValue.ToString(), @"^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{8}$"); + + } + + public static bool IsIDcard(this object thisValue) + { + if (thisValue == null) return false; + return System.Text.RegularExpressions.Regex.IsMatch(thisValue.ToString(), @"^(\d{15}$|^\d{18}$|^\d{17}(\d|X|x))$"); + } + + public static bool IsFax(this object thisValue) + { + if (thisValue == null) return false; + return System.Text.RegularExpressions.Regex.IsMatch(thisValue.ToString(), @"^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$"); + } + + public static bool IsMatch(this object thisValue, string pattern) + { + if (thisValue == null) return false; + Regex reg = new Regex(pattern); + return reg.IsMatch(thisValue.ToString()); + } + public static bool IsAnonymousType(this Type type) + { + string typeName = type.Name; + return typeName.Contains("<>") && typeName.Contains("__") && typeName.Contains("AnonymousType"); + } + public static bool IsCollectionsList(this string thisValue) + { + return (thisValue + "").StartsWith("System.Collections.Generic.List")|| (thisValue + "").StartsWith("System.Collections.Generic.IEnumerable"); + } + public static bool IsStringArray(this string thisValue) + { + return (thisValue + "").IsMatch(@"System\.[a-z,A-Z,0-9]+?\[\]"); + } + public static bool IsEnumerable(this string thisValue) + { + return (thisValue + "").StartsWith("System.Linq.Enumerable"); + } + + public static Type StringType = typeof (string); + + public static bool IsClass(this Type thisValue) + { + return thisValue != StringType && thisValue.IsEntity()&&thisValue!=UtilConstants.ByteArrayType; + } + } +} diff --git a/Src/Asp.NetCore2/SqlSugarCore.sln b/Src/Asp.NetCore2/SqlSugarCore.sln index ce2dd7b44..b17c1833f 100644 --- a/Src/Asp.NetCore2/SqlSugarCore.sln +++ b/Src/Asp.NetCore2/SqlSugarCore.sln @@ -94,6 +94,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SqlSugar.GaussDBCore", "Sql EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GaussDBTest", "GaussTest\GaussDBTest.csproj", "{F17886C5-60CB-4B69-9B0A-7E07E073B385}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SqlSugar.DuckDBCore", "SqlSugar.DuckDBCore\SqlSugar.DuckDBCore.csproj", "{7AF1C5DF-AEA1-47E2-92CA-621330F68860}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DuckDBTest", "DuckDBTest\DuckDBTest.csproj", "{F8DBA187-9A40-4AE5-972F-230835FEAEE4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -608,6 +612,30 @@ Global {F17886C5-60CB-4B69-9B0A-7E07E073B385}.Release|ARM32.Build.0 = Release|Any CPU {F17886C5-60CB-4B69-9B0A-7E07E073B385}.Release|x86.ActiveCfg = Release|Any CPU {F17886C5-60CB-4B69-9B0A-7E07E073B385}.Release|x86.Build.0 = Release|Any CPU + {7AF1C5DF-AEA1-47E2-92CA-621330F68860}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AF1C5DF-AEA1-47E2-92CA-621330F68860}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AF1C5DF-AEA1-47E2-92CA-621330F68860}.Debug|ARM32.ActiveCfg = Debug|Any CPU + {7AF1C5DF-AEA1-47E2-92CA-621330F68860}.Debug|ARM32.Build.0 = Debug|Any CPU + {7AF1C5DF-AEA1-47E2-92CA-621330F68860}.Debug|x86.ActiveCfg = Debug|Any CPU + {7AF1C5DF-AEA1-47E2-92CA-621330F68860}.Debug|x86.Build.0 = Debug|Any CPU + {7AF1C5DF-AEA1-47E2-92CA-621330F68860}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AF1C5DF-AEA1-47E2-92CA-621330F68860}.Release|Any CPU.Build.0 = Release|Any CPU + {7AF1C5DF-AEA1-47E2-92CA-621330F68860}.Release|ARM32.ActiveCfg = Release|Any CPU + {7AF1C5DF-AEA1-47E2-92CA-621330F68860}.Release|ARM32.Build.0 = Release|Any CPU + {7AF1C5DF-AEA1-47E2-92CA-621330F68860}.Release|x86.ActiveCfg = Release|Any CPU + {7AF1C5DF-AEA1-47E2-92CA-621330F68860}.Release|x86.Build.0 = Release|Any CPU + {F8DBA187-9A40-4AE5-972F-230835FEAEE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F8DBA187-9A40-4AE5-972F-230835FEAEE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8DBA187-9A40-4AE5-972F-230835FEAEE4}.Debug|ARM32.ActiveCfg = Debug|Any CPU + {F8DBA187-9A40-4AE5-972F-230835FEAEE4}.Debug|ARM32.Build.0 = Debug|Any CPU + {F8DBA187-9A40-4AE5-972F-230835FEAEE4}.Debug|x86.ActiveCfg = Debug|Any CPU + {F8DBA187-9A40-4AE5-972F-230835FEAEE4}.Debug|x86.Build.0 = Debug|Any CPU + {F8DBA187-9A40-4AE5-972F-230835FEAEE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F8DBA187-9A40-4AE5-972F-230835FEAEE4}.Release|Any CPU.Build.0 = Release|Any CPU + {F8DBA187-9A40-4AE5-972F-230835FEAEE4}.Release|ARM32.ActiveCfg = Release|Any CPU + {F8DBA187-9A40-4AE5-972F-230835FEAEE4}.Release|ARM32.Build.0 = Release|Any CPU + {F8DBA187-9A40-4AE5-972F-230835FEAEE4}.Release|x86.ActiveCfg = Release|Any CPU + {F8DBA187-9A40-4AE5-972F-230835FEAEE4}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -626,6 +654,7 @@ Global {B3C4B993-C33E-48AF-955F-EB801774FBE8} = {88992AAF-146B-4253-9AD7-493E8F415B57} {F706204F-2FC4-5112-646F-28D498E56AF4} = {88992AAF-146B-4253-9AD7-493E8F415B57} {15CB3CFF-E99D-4A79-8F6F-D9175CC2F7CB} = {88992AAF-146B-4253-9AD7-493E8F415B57} + {7AF1C5DF-AEA1-47E2-92CA-621330F68860} = {88992AAF-146B-4253-9AD7-493E8F415B57} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {230A85B9-54F1-41B1-B1DA-80086581B2B4}