diff --git a/Examples/zore_entity/JObjectExtensions.cs b/Examples/zore_entity/JObjectExtensions.cs new file mode 100644 index 00000000..d8ef3fc9 --- /dev/null +++ b/Examples/zore_entity/JObjectExtensions.cs @@ -0,0 +1,68 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +public static class JObjectExtensions +{ + /// + /// 将JObject转化成字典 + /// + /// + /// + public static Dictionary ToDictionary(this JToken json) + { + var propertyValuePairs = json.ToObject>(); + ProcessJObjectProperties(propertyValuePairs); + ProcessJArrayProperties(propertyValuePairs); + return propertyValuePairs; + } + + private static void ProcessJObjectProperties(Dictionary propertyValuePairs) + { + var objectPropertyNames = (from property in propertyValuePairs + let propertyName = property.Key + let value = property.Value + where value is JObject + select propertyName).ToList(); + + objectPropertyNames.ForEach(propertyName => propertyValuePairs[propertyName] = ToDictionary((JObject)propertyValuePairs[propertyName])); + } + + private static void ProcessJArrayProperties(Dictionary propertyValuePairs) + { + var arrayPropertyNames = (from property in propertyValuePairs + let propertyName = property.Key + let value = property.Value + where value is JArray + select propertyName).ToList(); + + arrayPropertyNames.ForEach(propertyName => propertyValuePairs[propertyName] = ToArray((JArray)propertyValuePairs[propertyName])); + } + + /// + /// + /// + /// + /// + public static object[] ToArray(this JArray array) + { + return array.ToObject().Select(ProcessArrayEntry).ToArray(); + } + + private static object ProcessArrayEntry(object value) + { + if (value is JObject) + { + return ToDictionary((JObject)value); + } + if (value is JArray) + { + return ToArray((JArray)value); + } + return value; + } + +} \ No newline at end of file diff --git a/Examples/zore_entity/Program.cs b/Examples/zore_entity/Program.cs new file mode 100644 index 00000000..02ebcbd6 --- /dev/null +++ b/Examples/zore_entity/Program.cs @@ -0,0 +1,297 @@ + +using FreeSql; +using FreeSql.DataAnnotations; +using FreeSql.Extensions.ZoreEntity; +using FreeSql.Internal.Model; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Data; +using System.Text.Json; + +using (var fsql = new FreeSqlBuilder() + .UseConnectionString(DataType.Sqlite, "data source=111.db") + .UseAutoSyncStructure(true) + .UseNoneCommandParameter(true) + .UseMonitorCommand(cmd => Console.WriteLine(cmd.CommandText + "\r\n")) + .Build()) +{ + var json = JsonConvert.SerializeObject(Helper.GetTestDesc()); + + var dyctx = new ZoreDbContext(fsql, JsonConvert.DeserializeObject(@" +[ + { + ""Name"":""User"", + ""Comment"":""用户表"", + ""Columns"": [ + {""Name"":""Id"",""IsPrimary"":true,""IsIdentity"":true,""MapType"":""System.Int32""}, + {""Name"":""Name"",""MapType"":""System.String""} + ], + ""Navigates"":[ + {""Name"":""Ext"",""Type"":""OneToOne"",""RelTable"":""UserExt""}, + {""Name"":""Claims"",""Type"":""OneToMany"",""RelTable"":""UserClaim"",""Bind"":""UserId""}, + {""Name"":""Roles"",""Type"":""ManyToMany"",""RelTable"":""Role"",""ManyToMany"":""UserRole""} + ], + ""Indexes"":[] + }, + { + ""Name"":""UserExt"", + ""Comment"":""用户扩展信息表"", + ""Columns"":[ + {""Name"":""UserId"",""IsPrimary"":true,""MapType"":""System.Int32""}, + ], + ""Navigates"":[ + {""Name"":""Remarks"",""Type"":""OneToMany"",""RelTable"":""UserExtRemarks"",""Bind"":""UserId""}, + ], + }, + { + ""Name"":""UserExtRemarks"", + ""Comment"":""用户扩展信息表-子表"", + ""Columns"":[ + {""Name"":""RemarkId"",""IsPrimary"":true,""MapType"":""System.Guid""}, + {""Name"":""UserId"",""MapType"":""System.Int32""}, + {""Name"":""Remark"",""MapType"":""System.String""}, + ], + }, + { + ""Name"":""UserClaim"", + ""Comment"":""一对多测试表"", + ""Columns"":[ + {""Name"":""Id"",""IsPrimary"":true,""IsIdentity"":true,""MapType"":""System.Int32""}, + {""Name"":""UserId"",""MapType"":""System.Int32""}, + {""Name"":""ClaimName"",""MapType"":""System.String""}, + ], + }, + { + ""Name"":""Role"", + ""Comment"":""权限表"", + ""Columns"":[ + {""Name"":""Id"",""IsPrimary"":true,""IsIdentity"":true,""MapType"":""System.Int32""}, + {""Name"":""Name"",""MapType"":""System.String""} + ], + ""Navigates"":[ + {""Name"":""Users"",""Type"":""ManyToMany"",""RelTable"":""User"",""ManyToMany"":""UserRole""} + ], + ""Indexes"":[] + }, + { + ""Name"":""UserRole"", + ""Comment"":""多对多中间表"", + ""Columns"":[ + {""Name"":""UserId"",""IsPrimary"":true,""MapType"":""System.Int32""}, + {""Name"":""RoleId"",""IsPrimary"":true,""MapType"":""System.Int32""} + ], + ""Navigates"":[ + {""Name"":""User"",""Type"":""ManyToOne"",""RelTable"":""User"",""Bind"":""UserId""}, + {""Name"":""Role"",""Type"":""ManyToOne"",""RelTable"":""Role"",""Bind"":""RoleId""} + ] + } +] +")); + + var dyrt3 = dyctx.SelectNoTracking("User") + .Include("Ext.Remarks", then => then.Where("remark", "like", "error")) + .Include("Roles", then => then.Include("Users", + then => then.Include("Ext.Remarks"))) + .ToList(); + + var dyrt2 = dyctx.SelectNoTracking("User") + .LeftJoin("UserExt", "UserId", "User.Id") + .LeftJoin("UserExt", "UserId", "User.Id") + //.IncludeAll() + .WhereExists(q => q.From("UserClaim") + .WhereColumns("userid", "=", "user.id") + .WhereExists(q2 => q2.From("User") + .WhereColumns("id", "=", "UserClaim.userid"))) + .ToList(); + + var dyrt1 = dyctx.Select.ToList(); + dyctx.Delete(dyrt1); + + var itemJson = JsonConvert.SerializeObject(new Dictionary + { + ["Name"] = "user1", + ["Ext"] = new Dictionary + { + }, + ["Claims"] = new List> + { + new Dictionary + { + ["ClaimName"] = "claim1" + }, + new Dictionary + { + ["ClaimName"] = "claim2" + }, + new Dictionary + { + ["ClaimName"] = "claim3" + }, + }, + + ["Roles"] = new List> + { + new Dictionary + { + ["Name"] = "role1" + }, + new Dictionary + { + ["Name"] = "role2" + }, + }, + }); + + var item = JsonConvert.DeserializeObject>(@" +{ +""Name"":""user1"", +""Ext"":{ + ""Remarks"":[{""Remark"":""remark1""},{""Remark"":""remark2""}] +}, +""Claims"":[{""ClaimName"":""claim1""},{""ClaimName"":""claim2""},{""ClaimName"":""claim3""}], +""Roles"":[{""Name"":""role1""},{""Name"":""role2""}] +}"); + + var item2 = System.Text.Json.JsonSerializer.Deserialize>(@" +{ +""Name"":""user1"", +""Ext"":{ + ""Remarks"":[{""Remark"":""remark1""},{""Remark"":""remark2""}] +}, +""Claims"":[{""ClaimName"":""claim1""},{""ClaimName"":""claim2""},{""ClaimName"":""claim3""}], +""Roles"":[{""Name"":""role1""},{""Name"":""role2""}] +}"); + dyctx.Insert(item2); + + var item3 = JsonConvert.DeserializeObject>(@" +{ +""Id"":1, +""Name"":""user1111"", +""Ext"":{}, +""Claims"":[{""Id"":1,""ClaimName"":""claim1111""},{""Id"":""3"",""ClaimName"":""claim3222222""},{""ClaimName"":""claim0000""}], +""Roles"":[{""Name"":""role111100001""},{""Id"":2,""Name"":""role2""}] +}"); + item3["Id"] = item2["Id"]; + dyctx.Update(item3); + dyctx.Delete(item3); + + + + + + Task.Run(async () => + { + var users = await fsql.Select().IncludeMany(a => a.Roles).ToListAsync(); + }).Wait(); +} + +[Table(DisableSyncStructure = true)] +class userdto +{ + public int Id { get; set; } + public bool? isdeleted { get; set; } +} + +class User +{ + [Column(IsIdentity = true)] + public int Id { get; set; } //Id、UserId、User_id + public string Name { get; set; } + public UserExt Ext { get; set; } + + [Navigate(nameof(UserClaim.UserId))] + public List Claims { get; set; } + public List Roles { get; set; } +} +class UserExt +{ + public int UserId { get; set; } + public User User { get; set; } +} +class UserClaim +{ + [Column(IsIdentity = true)] + public int Id { get; set; } + public int UserId { get; set; } + public string ClaimName { get; set; } +} +class Role +{ + [Column(IsIdentity = true)] + public int Id { get; set; } + public string Name { get; set; } + + public List Users { get; set; } +} +class UserRole +{ + public int UserId { get; set; } + public User User { get; set; } + + public int RoleId { get; set; } + public Role Role { get; set; } +} + +static class Helper +{ + public static TableDescriptor[] GetTestDesc() + { + return new[] + { + new TableDescriptor + { + Name = "User", + Columns = + { + new TableDescriptor.ColumnDescriptor{ Name = "Id", MapType = typeof(int), IsPrimary = true, IsIdentity = true }, + new TableDescriptor.ColumnDescriptor{ Name = "Name", MapType = typeof(string), StringLength = 100 }, + }, + Navigates = + { + new TableDescriptor.NavigateDescriptor { Name = "Ext", RelTable = "UserExt", Type = TableDescriptor.NavigateType.OneToOne }, + new TableDescriptor.NavigateDescriptor { Name = "Roles", RelTable = "Role", Type = TableDescriptor.NavigateType.ManyToMany, ManyToMany = "UserRole" }, + } + }, + new TableDescriptor + { + Name = "UserExt", + Columns = + { + new TableDescriptor.ColumnDescriptor{ Name = "UserId", MapType = typeof(int), IsPrimary = true }, + new TableDescriptor.ColumnDescriptor{ Name = "Name", MapType = typeof(string), StringLength = 100 }, + }, + Navigates = + { + new TableDescriptor.NavigateDescriptor { Name = "User", RelTable = "User", Type = TableDescriptor.NavigateType.OneToOne }, + } + }, + new TableDescriptor + { + Name = "Role", + Columns = + { + new TableDescriptor.ColumnDescriptor{ Name = "Id", MapType = typeof(int), IsPrimary = true, IsIdentity = true }, + new TableDescriptor.ColumnDescriptor{ Name = "Name", MapType = typeof(string), StringLength = 50 }, + }, + Navigates = + { + new TableDescriptor.NavigateDescriptor { Name = "Users", RelTable = "User", Type = TableDescriptor.NavigateType.ManyToMany, ManyToMany = "UserRole" }, + } + }, + new TableDescriptor + { + Name = "UserRole", + Columns = + { + new TableDescriptor.ColumnDescriptor{ Name = "UserId", MapType = typeof(int), IsPrimary = true }, + new TableDescriptor.ColumnDescriptor{ Name = "RoleId", MapType = typeof(int), IsPrimary = true }, + }, + Navigates = + { + new TableDescriptor.NavigateDescriptor { Name = "User", RelTable = "User", Type = TableDescriptor.NavigateType.ManyToOne, Bind = "UserId" }, + new TableDescriptor.NavigateDescriptor { Name = "Role", RelTable = "Role", Type = TableDescriptor.NavigateType.ManyToOne, Bind = "RoleId" }, + } + }, + }; + } +} \ No newline at end of file diff --git a/Examples/zore_entity/zore_entity.csproj b/Examples/zore_entity/zore_entity.csproj new file mode 100644 index 00000000..d21213be --- /dev/null +++ b/Examples/zore_entity/zore_entity.csproj @@ -0,0 +1,19 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/Extensions/FreeSql.Extensions.ZoreEntity/FreeSql.Extensions.ZoreEntity.csproj b/Extensions/FreeSql.Extensions.ZoreEntity/FreeSql.Extensions.ZoreEntity.csproj index 0ab3de8e..ef3429e8 100644 --- a/Extensions/FreeSql.Extensions.ZoreEntity/FreeSql.Extensions.ZoreEntity.csproj +++ b/Extensions/FreeSql.Extensions.ZoreEntity/FreeSql.Extensions.ZoreEntity.csproj @@ -18,7 +18,7 @@ true key.snk false - 3.2.806 + 3.2.807-preview20231214 readme.md diff --git a/Extensions/FreeSql.Extensions.ZoreEntity/ZoreDbContext.cs b/Extensions/FreeSql.Extensions.ZoreEntity/ZoreDbContext.cs index 2cf5d95f..17ec0d4a 100644 --- a/Extensions/FreeSql.Extensions.ZoreEntity/ZoreDbContext.cs +++ b/Extensions/FreeSql.Extensions.ZoreEntity/ZoreDbContext.cs @@ -73,6 +73,13 @@ ManyToMany 级联删除中间表(注意不删除外部根) orm.CodeFirst.SyncStructure(table, table.DbName, false); } + public TableInfo GetTableInfo(string name) => _tables.Where(a => a.CsName == name).FirstOrDefault(); + public void SyncStructure(string name) + { + var table = GetTableInfo(name); + _orm.CodeFirst.SyncStructure(table, table.DbName, false); + } + static List VilidateSchemaToInfo(IFreeSql orm, IEnumerable schemas) { var common = (orm.Ado as AdoProvider)._util; diff --git a/FreeSql-ZoreEntity.sln b/FreeSql-ZoreEntity.sln new file mode 100644 index 00000000..ee6bafda --- /dev/null +++ b/FreeSql-ZoreEntity.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql", "FreeSql\FreeSql.csproj", "{3AAE17E8-8608-4905-826A-6DB68F75F339}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.ZoreEntity", "Extensions\FreeSql.Extensions.ZoreEntity\FreeSql.Extensions.ZoreEntity.csproj", "{E0480E6F-CFCD-4108-969C-448E44023C97}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.Sqlite", "Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj", "{5E4928F2-E52B-4563-9FF7-C0A4119E6596}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "zore_entity", "Examples\zore_entity\zore_entity.csproj", "{E58095E7-DD2C-41E6-A2E5-4EBE586FA3AD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3AAE17E8-8608-4905-826A-6DB68F75F339}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3AAE17E8-8608-4905-826A-6DB68F75F339}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3AAE17E8-8608-4905-826A-6DB68F75F339}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3AAE17E8-8608-4905-826A-6DB68F75F339}.Release|Any CPU.Build.0 = Release|Any CPU + {E0480E6F-CFCD-4108-969C-448E44023C97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0480E6F-CFCD-4108-969C-448E44023C97}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0480E6F-CFCD-4108-969C-448E44023C97}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0480E6F-CFCD-4108-969C-448E44023C97}.Release|Any CPU.Build.0 = Release|Any CPU + {5E4928F2-E52B-4563-9FF7-C0A4119E6596}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E4928F2-E52B-4563-9FF7-C0A4119E6596}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E4928F2-E52B-4563-9FF7-C0A4119E6596}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E4928F2-E52B-4563-9FF7-C0A4119E6596}.Release|Any CPU.Build.0 = Release|Any CPU + {E58095E7-DD2C-41E6-A2E5-4EBE586FA3AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E58095E7-DD2C-41E6-A2E5-4EBE586FA3AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E58095E7-DD2C-41E6-A2E5-4EBE586FA3AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E58095E7-DD2C-41E6-A2E5-4EBE586FA3AD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 341e3d36..c1335e5e 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -739,15 +739,6 @@ - - - 根据Assembly扫描所有继承IEntityTypeConfiguration<T>的配置类 - - - - - - 创建普通数据上下文档对象 @@ -806,14 +797,5 @@ - - - 批量注入 Repository,可以参考代码自行调整 - - - - - - diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index ed01ba68..79f068d6 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -1104,82 +1104,6 @@ - - - 动态创建实体类型 - - - - - 配置Class - - 类名 - 类标记的特性[Table(Name = "xxx")] [Index(xxxx)] - - - - - 配置属性 - - 属性名称 - 属性类型 - 属性标记的特性-支持多个 - - - - - 配置属性 - - 属性名称 - 属性类型 - 该属性是否重写父类属性 - 属性标记的特性-支持多个 - - - - - 配置属性 - - 属性名称 - 属性类型 - 该属性是否重写父类属性 - 属性默认值 - 属性标记的特性-支持多个 - - - - - 配置父类 - - 父类类型 - - - - - Override属性 - - - - - - Emit动态创建出Class - Type - - - - - - 首字母小写 - - - - - - - 首字母大写 - - - - 获取实体的主键值,以 "*|_,[,_|*" 分割,当任意一个主键属性无值时,返回 null @@ -3346,13 +3270,6 @@ - - - 执行SQL语句,返回更新后的记录 - 注意:此方法只有 Postgresql/SqlServer 有效果 - - - 指定事务对象 @@ -3697,177 +3614,6 @@ - - - 测试数据库是否连接正确,本方法执行如下命令: - MySql/SqlServer/PostgreSQL/达梦/人大金仓/神通: SELECT 1 - Oracle: SELECT 1 FROM dual - - 命令超时设置(秒) - - true: 成功, false: 失败 - - - - 查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】 - - - - - - - - - - 查询,ExecuteReaderAsync(dr => {}, "select * from user where age > @age", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - 查询 - - - - - - - - - 查询,ExecuteArrayAsync("select * from user where age > @age", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - 查询 - - - - - - - - - 查询,ExecuteDataSetAsync("select * from user where age > @age; select 2", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - 查询 - - - - - - - - - 查询,ExecuteDataTableAsync("select * from user where age > @age", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - 在【主库】执行 - - - - - - - - - 在【主库】执行,ExecuteNonQueryAsync("delete from user where age > @age", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - 在【主库】执行 - - - - - - - - - 在【主库】执行,ExecuteScalarAsync("select 1 from user where age > @age", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new SqlParameter { ParameterName = "age", Value = 25 }) - - - - - - - - - - - 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - - 执行SQL返回对象集合,Query<User>("select * from user where age > @age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 }) - - - - - - - - - - - - 执行SQL返回对象集合,Query<User, Address>("select * from user where age > @age; select * from address", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - 可自定义解析表达式 @@ -4867,12 +4613,6 @@ 超时 - - - 获取资源 - - - 使用完毕后,归还资源 @@ -4948,12 +4688,6 @@ 资源对象 - - - 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象 - - 资源对象 - 归还对象给对象池的时候触发 @@ -5884,28 +5618,6 @@ 请使用 fsql.InsertDict(dict) 方法插入字典数据 - - - 动态构建Class Type - - - - - - 根据字典,创建 table 对应的实体对象 - - - - - - - - 根据实体对象,创建 table 对应的字典 - - - - - C#: that >= between && that <= and