From 36759402ccb15aee50c3d6588c3fe57dd91e8037 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Thu, 16 Apr 2020 02:58:34 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=20FreeSql.DbContext=20On?= =?UTF-8?q?ModelCreating=20=E8=99=9A=E6=96=B9=E6=B3=95=EF=BC=8C=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E5=9C=A8=20DbContext=20=E4=BD=BF=E7=94=A8=20FluentApi?= =?UTF-8?q?=EF=BC=9B#4=20-=20=E7=A7=BB=E9=99=A4=20FreeSql.Extensions.EfCor?= =?UTF-8?q?eFluentApi=EF=BC=8C=E5=8A=9F=E8=83=BD=E7=A7=BB=E8=87=B3=20FreeS?= =?UTF-8?q?ql.DbContext=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/ValuesController.cs | 40 +-- .../dbcontext_01/DbContexts/SongContext.cs | 87 ++++- Examples/dbcontext_01/Program.cs | 49 --- Examples/efcore_to_freesql/Startup.cs | 2 +- .../efcore_to_freesql.csproj | 2 +- .../FreeSql.Extensions.EfCoreFluentApi.csproj | 37 -- .../FreeSql.Extensions.EfCoreFluentApi.xml | 15 - .../ICodeFirstExtensions.cs | 115 ------- .../key.snk | Bin 596 -> 0 bytes .../readme.md | 103 ------ FreeSql.DbContext/DbContext/DbContext.cs | 24 +- .../EfCoreFluentApi}/EfCoreColumnFluent.cs | 4 + .../EfCoreFluentApiExtensions.cs | 120 +++++++ .../EfCoreFluentApi}/EfCoreTableFluent.cs | 4 + .../Extensions/DependencyInjection.cs | 6 +- .../Extensions/FreeSqlDbContextExtensions.cs | 2 +- FreeSql.DbContext/FreeSql.DbContext.xml | 36 +- .../Extensions/DependencyInjection.cs | 6 +- .../Extensions/FreeSqlRepositoryExtensions.cs | 2 +- FreeSql.sln | 15 - ... FreeSqlGlobalExpressionCallExtensions.cs} | 2 +- FreeSql/FreeSql.xml | 316 ++++++++---------- FreeSql/Interface/ICodeFirst.cs | 6 +- 23 files changed, 418 insertions(+), 575 deletions(-) delete mode 100644 Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.csproj delete mode 100644 Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.xml delete mode 100644 Extensions/FreeSql.Extensions.EfCoreFluentApi/ICodeFirstExtensions.cs delete mode 100644 Extensions/FreeSql.Extensions.EfCoreFluentApi/key.snk delete mode 100644 Extensions/FreeSql.Extensions.EfCoreFluentApi/readme.md rename {Extensions/FreeSql.Extensions.EfCoreFluentApi => FreeSql.DbContext/EfCoreFluentApi}/EfCoreColumnFluent.cs (88%) create mode 100644 FreeSql.DbContext/EfCoreFluentApi/EfCoreFluentApiExtensions.cs rename {Extensions/FreeSql.Extensions.EfCoreFluentApi => FreeSql.DbContext/EfCoreFluentApi}/EfCoreTableFluent.cs (98%) rename FreeSql/Extensions/{FreeSqlGlobalExpressionCall.cs => FreeSqlGlobalExpressionCallExtensions.cs} (96%) diff --git a/Examples/dbcontext_01/Controllers/ValuesController.cs b/Examples/dbcontext_01/Controllers/ValuesController.cs index 7ad083b1..6bedf450 100644 --- a/Examples/dbcontext_01/Controllers/ValuesController.cs +++ b/Examples/dbcontext_01/Controllers/ValuesController.cs @@ -42,12 +42,12 @@ namespace dbcontext_01.Controllers repos2Song.Where(a => a.Id > 10).ToList(); //查询结果,进入 states - var song = new Song { }; + var song = new Song { Title = "empty" }; repos2Song.Insert(song); id = song.Id; var adds = Enumerable.Range(0, 100) - .Select(a => new Song { Create_time = DateTime.Now, Is_deleted = false, Title = "xxxx" + a, Url = "url222" }) + .Select(a => new Song { CreateTime = DateTime.Now, Title = "xxxx" + a, Url = "url222" }) .ToList(); //创建一堆无主键值 @@ -72,17 +72,7 @@ namespace dbcontext_01.Controllers var ctx = _songContext; var tag = new Tag { - Name = "testaddsublist", - Tags = new[] { - new Tag { Name = "sub1" }, - new Tag { Name = "sub2" }, - new Tag { - Name = "sub3", - Tags = new[] { - new Tag { Name = "sub3_01" } - } - } - } + Name = "testaddsublist" }; ctx.Tags.Add(tag); @@ -91,17 +81,7 @@ namespace dbcontext_01.Controllers var tagAsync = new Tag { - Name = "testaddsublist", - Tags = new[] { - new Tag { Name = "sub1" }, - new Tag { Name = "sub2" }, - new Tag { - Name = "sub3", - Tags = new[] { - new Tag { Name = "sub3_01" } - } - } - } + Name = "testaddsublist" }; await ctx.Tags.AddAsync(tagAsync); @@ -109,7 +89,7 @@ namespace dbcontext_01.Controllers ctx.Songs.Select.Where(a => a.Id > 10).ToList(); //查询结果,进入 states - song = new Song { }; + song = new Song { Title = "empty" }; //可插入的 song ctx.Songs.Add(song); @@ -117,7 +97,7 @@ namespace dbcontext_01.Controllers //因有自增类型,立即开启事务执行SQL,返回自增值 adds = Enumerable.Range(0, 100) - .Select(a => new Song { Create_time = DateTime.Now, Is_deleted = false, Title = "xxxx" + a, Url = "url222" }) + .Select(a => new Song { CreateTime = DateTime.Now, Title = "xxxx" + a, Url = "url222" }) .ToList(); //创建一堆无主键值 @@ -159,12 +139,12 @@ namespace dbcontext_01.Controllers reposSong.Where(a => a.Id > 10).ToList(); //查询结果,进入 states - song = new Song { }; + song = new Song { Title = "empty" }; reposSong.Insert(song); id = song.Id; adds = Enumerable.Range(0, 100) - .Select(a => new Song { Create_time = DateTime.Now, Is_deleted = false, Title = "xxxx" + a, Url = "url222" }) + .Select(a => new Song { CreateTime = DateTime.Now, Title = "xxxx" + a, Url = "url222" }) .ToList(); //创建一堆无主键值 @@ -193,12 +173,12 @@ namespace dbcontext_01.Controllers using (ctx = new SongContext()) { - song = new Song { }; + song = new Song { Title = "empty" }; await ctx.Songs.AddAsync(song); id = song.Id; adds = Enumerable.Range(0, 100) - .Select(a => new Song { Create_time = DateTime.Now, Is_deleted = false, Title = "xxxx" + a, Url = "url222" }) + .Select(a => new Song { CreateTime = DateTime.Now, Title = "xxxx" + a, Url = "url222" }) .ToList(); await ctx.Songs.AddRangeAsync(adds); diff --git a/Examples/dbcontext_01/DbContexts/SongContext.cs b/Examples/dbcontext_01/DbContexts/SongContext.cs index da7da534..b920f23d 100644 --- a/Examples/dbcontext_01/DbContexts/SongContext.cs +++ b/Examples/dbcontext_01/DbContexts/SongContext.cs @@ -5,56 +5,109 @@ using System.Collections.Generic; namespace dbcontext_01 { - public class SongContext : DbContext { - public SongContext() : base() { } - public SongContext(IFreeSql fsql) : base(fsql, null) { } - public DbSet Songs { get; set; } public DbSet Tags { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder builder) { builder.UseFreeSql(Startup.Fsql); + //这里直接指定一个静态的 IFreeSql 对象即可,切勿重新 Build() + } + + protected override void OnModelCreating(ICodeFirst codefirst) + { + codefirst.Entity(eb => + { + eb.ToTable("tb_song"); + eb.Ignore(a => a.Field1); + eb.Property(a => a.Title).HasColumnType("varchar(50)").IsRequired(); + eb.Property(a => a.Url).HasMaxLength(100); + + eb.Property(a => a.RowVersion).IsRowVersion(); + eb.Property(a => a.CreateTime).HasDefaultValueSql("current_timestamp"); + + eb.HasKey(a => a.Id); + eb.HasIndex(a => new { a.Id, a.Title }).IsUnique().HasName("idx_xxx11"); + + //一对多、多对一 + eb.HasOne(a => a.Type).HasForeignKey(a => a.TypeId).WithMany(a => a.Songs); + + //多对多 + eb.HasMany(a => a.Tags).WithMany(a => a.Songs, typeof(Song_tag)); + }); + + codefirst.Entity(eb => + { + eb.HasMany(a => a.Songs).WithOne(a => a.Type).HasForeignKey(a => a.TypeId); + + eb.HasData(new[] + { + new SongType + { + Id = 1, + Name = "流行", + Songs = new List(new[] + { + new Song{ Title = "真的爱你" }, + new Song{ Title = "爱你一万年" }, + }) + }, + new SongType + { + Id = 2, + Name = "乡村", + Songs = new List(new[] + { + new Song{ Title = "乡里乡亲" }, + }) + }, + }); + }); + + codefirst.SyncStructure(); + codefirst.SyncStructure(); } } + public class SongType + { + public int Id { get; set; } + public string Name { get; set; } + public List Songs { get; set; } + } public class Song { [Column(IsIdentity = true)] public int Id { get; set; } - public DateTime? Create_time { get; set; } - public bool? Is_deleted { get; set; } public string Title { get; set; } public string Url { get; set; } + public DateTime CreateTime { get; set; } - public virtual ICollection Tags { get; set; } + public int TypeId { get; set; } + public SongType Type { get; set; } + public List Tags { get; set; } - [Column(IsVersion = true)] - public long versionRow { get; set; } + public int Field1 { get; set; } + public long RowVersion { get; set; } } public class Song_tag { public int Song_id { get; set; } - public virtual Song Song { get; set; } + public Song Song { get; set; } public int Tag_id { get; set; } - public virtual Tag Tag { get; set; } + public Tag Tag { get; set; } } - public class Tag { [Column(IsIdentity = true)] public int Id { get; set; } - public int? Parent_id { get; set; } - public virtual Tag Parent { get; set; } - public decimal? Ddd { get; set; } public string Name { get; set; } - public virtual ICollection Songs { get; set; } - public virtual ICollection Tags { get; set; } + public List Songs { get; set; } } } diff --git a/Examples/dbcontext_01/Program.cs b/Examples/dbcontext_01/Program.cs index 6f7b9727..657e3abd 100644 --- a/Examples/dbcontext_01/Program.cs +++ b/Examples/dbcontext_01/Program.cs @@ -16,57 +16,8 @@ namespace dbcontext_01 { public class Program { - - public class Song - { - [Column(IsIdentity = true)] - public int Id { get; set; } - public string BigNumber { get; set; } - - [Column(IsVersion = true)]//使用简单 - public long versionRow { get; set; } - } - - public class SongContext : DbContext - { - - public DbSet Songs { get; set; } - - protected override void OnConfiguring(DbContextOptionsBuilder builder) - { - builder.UseFreeSql(fsql); - } - } - static IFreeSql fsql; public static void Main(string[] args) { - var asse = typeof(FreeSql.Internal.ObjectPool.ObjectPool<>).Assembly; - - fsql = new FreeSql.FreeSqlBuilder() - .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\dd2.db;Pooling=true;Max Pool Size=10") - .UseAutoSyncStructure(true) - .UseLazyLoading(true) - .UseNoneCommandParameter(true) - - .UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText)) - .Build(); - - - using (var ctx = new SongContext()) - { - var song = new Song { BigNumber = "1000000000000000000" }; - ctx.Songs.Add(song); - - ctx.Songs.Update(song); - - song.BigNumber = (BigInteger.Parse(song.BigNumber) + 1).ToString(); - ctx.Songs.Update(song); - - ctx.SaveChanges(); - - var sql = fsql.Update().SetSource(song).ToSql(); - } - CreateWebHostBuilder(args).Build().Run(); } diff --git a/Examples/efcore_to_freesql/Startup.cs b/Examples/efcore_to_freesql/Startup.cs index 6d98c5e5..2271d74f 100644 --- a/Examples/efcore_to_freesql/Startup.cs +++ b/Examples/efcore_to_freesql/Startup.cs @@ -27,7 +27,7 @@ namespace efcore_to_freesql .UseAutoSyncStructure(true) .Build(); - FreeSql.Extensions.EfCoreFluentApi.ICodeFirstExtensions.Test(Fsql); + FreeSqlDbContextExtensions.EfCoreFluentApiTest(Fsql); DBContexts.BaseDBContext.Fsql = Fsql; diff --git a/Examples/efcore_to_freesql/efcore_to_freesql.csproj b/Examples/efcore_to_freesql/efcore_to_freesql.csproj index 3624b40c..e6a6a3fb 100644 --- a/Examples/efcore_to_freesql/efcore_to_freesql.csproj +++ b/Examples/efcore_to_freesql/efcore_to_freesql.csproj @@ -10,7 +10,7 @@ - + diff --git a/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.csproj b/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.csproj deleted file mode 100644 index fb1393e3..00000000 --- a/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.csproj +++ /dev/null @@ -1,37 +0,0 @@ - - - - netstandard2.0 - 1.4.0-preview0415 - true - YeXiangQin - FreeSql 扩展包实现,使用 FluentApi 方式配置实体模型,使用习惯接近 EFCore,方便过渡. - https://github.com/2881099/FreeSql - https://github.com/2881099/FreeSql - git - MIT - FreeSql;ORM;FluentApi - $(AssemblyName) - logo.png - $(AssemblyName) - true - true - true - key.snk - false - - - - - - - - - - - - FreeSql.Extensions.EfCoreFluentApi.xml - 3 - - - diff --git a/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.xml b/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.xml deleted file mode 100644 index 55be793f..00000000 --- a/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - FreeSql.Extensions.EfCoreFluentApi - - - - - 使用 Repository + EnableAddOrUpdateNavigateList + NoneParameter 方式插入种子数据 - - - - - - diff --git a/Extensions/FreeSql.Extensions.EfCoreFluentApi/ICodeFirstExtensions.cs b/Extensions/FreeSql.Extensions.EfCoreFluentApi/ICodeFirstExtensions.cs deleted file mode 100644 index 542af7c2..00000000 --- a/Extensions/FreeSql.Extensions.EfCoreFluentApi/ICodeFirstExtensions.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using FreeSql.DataAnnotations; -using FreeSql.Internal.CommonProvider; - -namespace FreeSql.Extensions.EfCoreFluentApi -{ - public static class ICodeFirstExtensions - { - - public static ICodeFirst Entity(this ICodeFirst codeFirst, Action> modelBuilder) - { - var cf = codeFirst as CodeFirstProvider; - codeFirst.ConfigEntity(tf => modelBuilder(new EfCoreTableFluent(cf._orm, tf))); - return codeFirst; - } - - public static void Test(IFreeSql fsql) - { - var cf = fsql.CodeFirst; - cf.Entity(eb => - { - eb.ToTable("tb_song"); - eb.Ignore(a => a.Field1); - eb.Property(a => a.Title).HasColumnType("varchar(50)").IsRequired(); - eb.Property(a => a.Url).HasMaxLength(100); - - eb.Property(a => a.RowVersion).IsRowVersion(); - eb.Property(a => a.CreateTime).HasDefaultValueSql("current_timestamp"); - - eb.HasKey(a => a.Id); - eb.HasIndex(a => a.Title).IsUnique().HasName("idx_xxx11"); - - //一对多、多对一 - eb.HasOne(a => a.Type).HasForeignKey(a => a.TypeId).WithMany(a => a.Songs); - - //多对多 - eb.HasMany(a => a.Tags).WithMany(a => a.Songs, typeof(Song_tag)); - }); - cf.Entity(eb => - { - eb.HasMany(a => a.Songs).WithOne(a => a.Type).HasForeignKey(a => a.TypeId); - - eb.HasData(new[] - { - new SongType - { - Id = 1, - Name = "流行", - Songs = new List(new[] - { - new Song{ Title = "真的爱你" }, - new Song{ Title = "爱你一万年" }, - }) - }, - new SongType - { - Id = 2, - Name = "乡村", - Songs = new List(new[] - { - new Song{ Title = "乡里乡亲" }, - }) - }, - }); - }); - - cf.SyncStructure(); - cf.SyncStructure(); - } - - public class SongType - { - public int Id { get; set; } - public string Name { get; set; } - - public List Songs { get; set; } - } - - public class Song - { - [Column(IsIdentity = true)] - public int Id { get; set; } - public string Title { get; set; } - public string Url { get; set; } - public DateTime CreateTime { get; set; } - - public int TypeId { get; set; } - public SongType Type { get; set; } - public List Tags { get; set; } - - public int Field1 { get; set; } - public long RowVersion { get; set; } - } - public class Song_tag - { - public int Song_id { get; set; } - public Song Song { get; set; } - - public int Tag_id { get; set; } - public Tag Tag { get; set; } - } - - public class Tag - { - [Column(IsIdentity = true)] - public int Id { get; set; } - - public string Name { get; set; } - - public List Songs { get; set; } - } - } -} diff --git a/Extensions/FreeSql.Extensions.EfCoreFluentApi/key.snk b/Extensions/FreeSql.Extensions.EfCoreFluentApi/key.snk deleted file mode 100644 index 9651c6f6dca7fbfe187084d653fca7c139c7d84a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50097P=7d$>wVBs&v2*nzWIybp^a_TG#wMBR z9;`#2JIny2^KS;JL10G8RJp@bXIl86_Ep6}VeXsPu}NlBdUknchkmNk+KM18EUQoh zvMc_{lvG;WGhv`|lr1v+ZSwImfg98Vr;@T>Y)tPNgFS-uZ_$f)D8x)L54|Au?s?EN zNa~@z?gEkaTR6%IyQh5$5Vi*TL*!8@LezE|G6ar#^3+yRfa8Anv}0*u_A2;L>OBNk zIQT9I&vFm0?El=~_O)+E)qmKmLsuCZf3rB`t>5lmlZUoEeXQuaIx0Xc?Qr(x0Md~0 zfW2jtGin`LH6r@A4kaoo`!ha{M1JwZiFqe6J?Y!QUpc%U*T$2V{LVl7BMZG~mJOHS zD@D=?v~pQ;DUD1o5K^QX1!%Nzh`gOrU1v$+{U(j~#0LORdaY5}&ZCI<(D!L(=|Pa; z{M)JI|HfK(V-z$}A&Rt^w$Ma<^(zX5y_UTA0Pw{%>9hl`T_3ky<3-aO%r?<+d>k_J z^?^>17_0!=LwI7Hc!Jh@4KC dotnet add package FreeSql.Extensions.EfCoreFluentApi - -## 以假乱真 - -```csharp -static void Test() -{ - ICodeFirst cf = null; - cf.Entity(eb => - { - eb.ToTable("tb_song"); - eb.Ignore(a => a.Field1); - eb.Property(a => a.Title).HasColumnType("varchar(50)").IsRequired(); - eb.Property(a => a.Url).HasMaxLength(100); - - eb.Property(a => a.RowVersion).IsRowVersion(); - eb.Property(a => a.CreateTime).HasDefaultValueSql("getdate()"); - - eb.HasKey(a => a.Id); - eb.HasIndex(a => a.Title).IsUnique().HasName("idx_xxx11"); - - //一对多、多对一 - eb.HasOne(a => a.Type).HasForeignKey(a => a.TypeId).WithMany(a => a.Songs); - - //多对多 - eb.HasMany(a => a.Tags).WithMany(a => a.Songs, typeof(Song_tag)); - }); - - cf.Entity(eb => - { - eb.HasMany(a => a.Songs).WithOne(a => a.Type).HasForeignKey(a => a.TypeId); - - eb.HasData(new[] - { - new SongType - { - Id = 1, - Name = "流行", - Songs = new List(new[] - { - new Song{ Title = "真的爱你" }, - new Song{ Title = "爱你一万年" }, - }) - }, - new SongType - { - Id = 2, - Name = "乡村", - Songs = new List(new[] - { - new Song{ Title = "乡里乡亲" }, - }) - }, - }); - }); -} - -public class SongType -{ - public int Id { get; set; } - public string Name { get; set; } - - public List Songs { get; set; } -} - -public class Song -{ - [Column(IsIdentity = true)] - public int Id { get; set; } - public string Title { get; set; } - public string Url { get; set; } - public DateTime CreateTime { get; set; } - - public int TypeId { get; set; } - public SongType Type { get; set; } - public List Tags { get; set; } - - public int Field1 { get; set; } - public long RowVersion { get; set; } -} -public class Song_tag -{ - public int Song_id { get; set; } - public Song Song { get; set; } - - public int Tag_id { get; set; } - public Tag Tag { get; set; } -} - -public class Tag -{ - [Column(IsIdentity = true)] - public int Id { get; set; } - - public string Name { get; set; } - - public List Songs { get; set; } -} -``` \ No newline at end of file diff --git a/FreeSql.DbContext/DbContext/DbContext.cs b/FreeSql.DbContext/DbContext/DbContext.cs index 42188cb3..cac45b44 100644 --- a/FreeSql.DbContext/DbContext/DbContext.cs +++ b/FreeSql.DbContext/DbContext/DbContext.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; using System.Threading; +using FreeSql.Internal.Model; namespace FreeSql { @@ -71,18 +72,27 @@ namespace FreeSql } if (_ormScoped != null) InitPropSets(); } - protected virtual void OnConfiguring(DbContextOptionsBuilder builder) { } + protected virtual void OnConfiguring(DbContextOptionsBuilder options) { } + protected virtual void OnModelCreating(ICodeFirst codefirst) { } #region Set - static ConcurrentDictionary _dicGetDbSetProps = new ConcurrentDictionary(); + static ConcurrentDictionary> _dicGetDbSetProps = new ConcurrentDictionary>(); internal void InitPropSets() { - var props = _dicGetDbSetProps.GetOrAdd(this.GetType(), tp => - tp.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public) - .Where(a => a.PropertyType.IsGenericType && - a.PropertyType == typeof(DbSet<>).MakeGenericType(a.PropertyType.GetGenericArguments()[0])).ToArray()); + var thisType = this.GetType(); + var dicval = _dicGetDbSetProps.GetOrAdd(thisType, tp => + NaviteTuple.Create( + tp.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public) + .Where(a => a.PropertyType.IsGenericType && + a.PropertyType == typeof(DbSet<>).MakeGenericType(a.PropertyType.GetGenericArguments()[0])).ToArray(), + false)); + if (dicval.Item2 == false) + { + if (_dicGetDbSetProps.TryUpdate(thisType, NaviteTuple.Create(dicval.Item1, true), dicval)) + OnModelCreating(OrmOriginal.CodeFirst); + } - foreach (var prop in props) + foreach (var prop in dicval.Item1) { var set = this.Set(prop.PropertyType.GetGenericArguments()[0]); diff --git a/Extensions/FreeSql.Extensions.EfCoreFluentApi/EfCoreColumnFluent.cs b/FreeSql.DbContext/EfCoreFluentApi/EfCoreColumnFluent.cs similarity index 88% rename from Extensions/FreeSql.Extensions.EfCoreFluentApi/EfCoreColumnFluent.cs rename to FreeSql.DbContext/EfCoreFluentApi/EfCoreColumnFluent.cs index f91e6019..0b87862c 100644 --- a/Extensions/FreeSql.Extensions.EfCoreFluentApi/EfCoreColumnFluent.cs +++ b/FreeSql.DbContext/EfCoreFluentApi/EfCoreColumnFluent.cs @@ -14,6 +14,10 @@ namespace FreeSql.Extensions.EfCoreFluentApi _cf = tf; } + /// + /// 使用 FreeSql FluentApi 方法,当 EFCore FluentApi 方法无法表示的时候使用 + /// + /// public ColumnFluent Help() => _cf; public EfCoreColumnFluent HasColumnName(string name) diff --git a/FreeSql.DbContext/EfCoreFluentApi/EfCoreFluentApiExtensions.cs b/FreeSql.DbContext/EfCoreFluentApi/EfCoreFluentApiExtensions.cs new file mode 100644 index 00000000..30661258 --- /dev/null +++ b/FreeSql.DbContext/EfCoreFluentApi/EfCoreFluentApiExtensions.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using FreeSql; +using FreeSql.DataAnnotations; +using FreeSql.Extensions.EfCoreFluentApi; +using FreeSql.Internal.CommonProvider; + +partial class FreeSqlDbContextExtensions +{ + /// + /// EFCore 99% 相似的 FluentApi 扩展方法 + /// + /// + /// + /// + /// + public static ICodeFirst Entity(this ICodeFirst codeFirst, Action> modelBuilder) + { + var cf = codeFirst as CodeFirstProvider; + codeFirst.ConfigEntity(tf => modelBuilder(new EfCoreTableFluent(cf._orm, tf))); + return codeFirst; + } + + public static void EfCoreFluentApiTest(IFreeSql fsql) + { + var cf = fsql.CodeFirst; + cf.Entity(eb => + { + eb.ToTable("tb_song"); + eb.Ignore(a => a.Field1); + eb.Property(a => a.Title).HasColumnType("varchar(50)").IsRequired(); + eb.Property(a => a.Url).HasMaxLength(100); + + eb.Property(a => a.RowVersion).IsRowVersion(); + eb.Property(a => a.CreateTime).HasDefaultValueSql("current_timestamp"); + + eb.HasKey(a => a.Id); + eb.HasIndex(a => a.Title).IsUnique().HasName("idx_xxx11"); + + //一对多、多对一 + eb.HasOne(a => a.Type).HasForeignKey(a => a.TypeId).WithMany(a => a.Songs); + + //多对多 + eb.HasMany(a => a.Tags).WithMany(a => a.Songs, typeof(Song_tag)); + }); + cf.Entity(eb => + { + eb.HasMany(a => a.Songs).WithOne(a => a.Type).HasForeignKey(a => a.TypeId); + + eb.HasData(new[] + { + new SongType + { + Id = 1, + Name = "流行", + Songs = new List(new[] + { + new Song{ Title = "真的爱你" }, + new Song{ Title = "爱你一万年" }, + }) + }, + new SongType + { + Id = 2, + Name = "乡村", + Songs = new List(new[] + { + new Song{ Title = "乡里乡亲" }, + }) + }, + }); + }); + + cf.SyncStructure(); + cf.SyncStructure(); + } + + public class SongType + { + public int Id { get; set; } + public string Name { get; set; } + + public List Songs { get; set; } + } + + public class Song + { + [Column(IsIdentity = true)] + public int Id { get; set; } + public string Title { get; set; } + public string Url { get; set; } + public DateTime CreateTime { get; set; } + + public int TypeId { get; set; } + public SongType Type { get; set; } + public List Tags { get; set; } + + public int Field1 { get; set; } + public long RowVersion { get; set; } + } + public class Song_tag + { + public int Song_id { get; set; } + public Song Song { get; set; } + + public int Tag_id { get; set; } + public Tag Tag { get; set; } + } + + public class Tag + { + [Column(IsIdentity = true)] + public int Id { get; set; } + + public string Name { get; set; } + + public List Songs { get; set; } + } +} diff --git a/Extensions/FreeSql.Extensions.EfCoreFluentApi/EfCoreTableFluent.cs b/FreeSql.DbContext/EfCoreFluentApi/EfCoreTableFluent.cs similarity index 98% rename from Extensions/FreeSql.Extensions.EfCoreFluentApi/EfCoreTableFluent.cs rename to FreeSql.DbContext/EfCoreFluentApi/EfCoreTableFluent.cs index db7dd65f..388e7198 100644 --- a/Extensions/FreeSql.Extensions.EfCoreFluentApi/EfCoreTableFluent.cs +++ b/FreeSql.DbContext/EfCoreFluentApi/EfCoreTableFluent.cs @@ -31,6 +31,10 @@ namespace FreeSql.Extensions.EfCoreFluentApi public EfCoreColumnFluent Property(Expression> property) => new EfCoreColumnFluent(_tf.Property(property)); public EfCoreColumnFluent Property(string property) => new EfCoreColumnFluent(_tf.Property(property)); + /// + /// 使用 FreeSql FluentApi 方法,当 EFCore FluentApi 方法无法表示的时候使用 + /// + /// public TableFluent Help() => _tf; #region HasKey diff --git a/FreeSql.DbContext/Extensions/DependencyInjection.cs b/FreeSql.DbContext/Extensions/DependencyInjection.cs index 6e7fb6cd..dd96b306 100644 --- a/FreeSql.DbContext/Extensions/DependencyInjection.cs +++ b/FreeSql.DbContext/Extensions/DependencyInjection.cs @@ -1,12 +1,12 @@ #if netcoreapp -using Microsoft.Extensions.DependencyInjection; +using FreeSql; using System; using System.Linq; using System.Reflection; -namespace FreeSql +namespace Microsoft.Extensions.DependencyInjection { - public static class DbContextDependencyInjection + public static class FreeSqlDbContextDependencyInjection { static IServiceCollection AddFreeDbContext(this IServiceCollection services, Type dbContextType, Action options) { diff --git a/FreeSql.DbContext/Extensions/FreeSqlDbContextExtensions.cs b/FreeSql.DbContext/Extensions/FreeSqlDbContextExtensions.cs index c6084096..f0ad468e 100644 --- a/FreeSql.DbContext/Extensions/FreeSqlDbContextExtensions.cs +++ b/FreeSql.DbContext/Extensions/FreeSqlDbContextExtensions.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -public static class FreeSqlDbContextExtensions +public static partial class FreeSqlDbContextExtensions { /// diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 8cf53748..299c91e5 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -162,6 +162,25 @@ + + + 使用 FreeSql FluentApi 方法,当 EFCore FluentApi 方法无法表示的时候使用 + + + + + + 使用 FreeSql FluentApi 方法,当 EFCore FluentApi 方法无法表示的时候使用 + + + + + + 使用 Repository + EnableAddOrUpdateNavigateList + NoneParameter 方式插入种子数据 + + + + 在工作单元内创建默认仓库类,工作单元下的仓储操作具有事务特点 @@ -302,6 +321,15 @@ 例如:20191121_214504_1 + + + EFCore 99% 相似的 FluentApi 扩展方法 + + + + + + 创建普通数据上下文档对象 @@ -324,7 +352,7 @@ - + 返回默认仓库类 @@ -334,7 +362,7 @@ 数据过滤 + 验证 - + 返回默认仓库类,适用联合主键的仓储类 @@ -343,7 +371,7 @@ 数据过滤 + 验证 - + 返回仓库类 @@ -353,7 +381,7 @@ 分表规则,参数:旧表名;返回:新表名 https://github.com/2881099/FreeSql/wiki/Repository - + 创建基于仓储功能的工作单元,务必使用 using 包含使用 diff --git a/FreeSql.DbContext/Repository/Extensions/DependencyInjection.cs b/FreeSql.DbContext/Repository/Extensions/DependencyInjection.cs index e0ae86eb..087f176d 100644 --- a/FreeSql.DbContext/Repository/Extensions/DependencyInjection.cs +++ b/FreeSql.DbContext/Repository/Extensions/DependencyInjection.cs @@ -1,11 +1,10 @@ #if netcoreapp - -using Microsoft.Extensions.DependencyInjection; +using FreeSql; using System; using System.Linq; using System.Reflection; -namespace FreeSql +namespace Microsoft.Extensions.DependencyInjection { public static class FreeSqlRepositoryDependencyInjection { @@ -41,5 +40,4 @@ namespace FreeSql } } } - #endif \ No newline at end of file diff --git a/FreeSql.DbContext/Repository/Extensions/FreeSqlRepositoryExtensions.cs b/FreeSql.DbContext/Repository/Extensions/FreeSqlRepositoryExtensions.cs index af4aaaaa..9b4ed306 100644 --- a/FreeSql.DbContext/Repository/Extensions/FreeSqlRepositoryExtensions.cs +++ b/FreeSql.DbContext/Repository/Extensions/FreeSqlRepositoryExtensions.cs @@ -3,7 +3,7 @@ using System; using System.Linq; using System.Linq.Expressions; -public static class FreeSqlRepositoryExtensions +partial class FreeSqlDbContextExtensions { /// diff --git a/FreeSql.sln b/FreeSql.sln index 3ffc7d3d..7cf8a130 100644 --- a/FreeSql.sln +++ b/FreeSql.sln @@ -72,8 +72,6 @@ Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "FreeSql.Tests.VB", "FreeSql EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.MsAccess", "Providers\FreeSql.Provider.MsAccess\FreeSql.Provider.MsAccess.csproj", "{B397A761-F646-41CF-A160-AB6C05DAF2FB}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.EfCoreFluentApi", "Extensions\FreeSql.Extensions.EfCoreFluentApi\FreeSql.Extensions.EfCoreFluentApi.csproj", "{773D5B63-DE6E-46DB-AF16-6FB1C1352B3F}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.All", "FreeSql.All\FreeSql.All.csproj", "{933115AD-769C-4FBE-B000-2E8CF2292377}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.Linq", "Extensions\FreeSql.Extensions.Linq\FreeSql.Extensions.Linq.csproj", "{57B3F5B0-D46A-4442-8EC6-9A9A784404B7}" @@ -438,18 +436,6 @@ Global {B397A761-F646-41CF-A160-AB6C05DAF2FB}.Release|x64.Build.0 = Release|Any CPU {B397A761-F646-41CF-A160-AB6C05DAF2FB}.Release|x86.ActiveCfg = Release|Any CPU {B397A761-F646-41CF-A160-AB6C05DAF2FB}.Release|x86.Build.0 = Release|Any CPU - {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F}.Debug|x64.ActiveCfg = Debug|Any CPU - {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F}.Debug|x64.Build.0 = Debug|Any CPU - {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F}.Debug|x86.ActiveCfg = Debug|Any CPU - {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F}.Debug|x86.Build.0 = Debug|Any CPU - {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F}.Release|Any CPU.Build.0 = Release|Any CPU - {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F}.Release|x64.ActiveCfg = Release|Any CPU - {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F}.Release|x64.Build.0 = Release|Any CPU - {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F}.Release|x86.ActiveCfg = Release|Any CPU - {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F}.Release|x86.Build.0 = Release|Any CPU {933115AD-769C-4FBE-B000-2E8CF2292377}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {933115AD-769C-4FBE-B000-2E8CF2292377}.Debug|Any CPU.Build.0 = Debug|Any CPU {933115AD-769C-4FBE-B000-2E8CF2292377}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -511,7 +497,6 @@ Global {1674BCE3-EEB4-4003-A2A7-06F51EFAEA23} = {94C8A78D-AA15-47B2-A348-530CD86BFC1B} {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA} {B397A761-F646-41CF-A160-AB6C05DAF2FB} = {2A381C57-2697-427B-9F10-55DA11FD02E4} - {773D5B63-DE6E-46DB-AF16-6FB1C1352B3F} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA} {57B3F5B0-D46A-4442-8EC6-9A9A784404B7} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA} {E74D90E8-1CBC-4677-817B-1CA05AB97937} = {2A381C57-2697-427B-9F10-55DA11FD02E4} EndGlobalSection diff --git a/FreeSql/Extensions/FreeSqlGlobalExpressionCall.cs b/FreeSql/Extensions/FreeSqlGlobalExpressionCallExtensions.cs similarity index 96% rename from FreeSql/Extensions/FreeSqlGlobalExpressionCall.cs rename to FreeSql/Extensions/FreeSqlGlobalExpressionCallExtensions.cs index 67faf87a..63c48c4e 100644 --- a/FreeSql/Extensions/FreeSqlGlobalExpressionCall.cs +++ b/FreeSql/Extensions/FreeSqlGlobalExpressionCallExtensions.cs @@ -3,7 +3,7 @@ using System; using System.Threading; [ExpressionCall] -public static class FreeSqlGlobalExpressionCall +public static class FreeSqlGlobalExpressionCallExtensions { public static ThreadLocal expContext = new ThreadLocal(); diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 891fa7b5..cb7ec67f 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -2305,6 +2305,137 @@ + + + 查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】 + + + + + + + + + 查询,ExecuteReaderAsync(dr => {}, "select * from user where age > ?age", new { age = 25 }) + + + + + + + 查询 + + + + + + + 查询,ExecuteArrayAsync("select * from user where age > ?age", new { age = 25 }) + + + + + + + + 查询 + + + + + + + 查询,ExecuteDataSetAsync("select * from user where age > ?age; select 2", new { age = 25 }) + + + + + + + + 查询 + + + + + + + 查询,ExecuteDataTableAsync("select * from user where age > ?age", new { age = 25 }) + + + + + + + + 在【主库】执行 + + + + + + + + 在【主库】执行,ExecuteNonQueryAsync("delete from user where age > ?age", new { age = 25 }) + + + + + + + + 在【主库】执行 + + + + + + + + 在【主库】执行,ExecuteScalarAsync("select 1 from user where age > ?age", new { age = 25 }) + + + + + + + + 执行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 }) + + + + + + + + + 执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 }) + + + + + + + + + + 执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new { age = 25 }) + + + + + + 可自定义解析表达式 @@ -2651,7 +2782,7 @@ - 在外部配置实体的特性 + FreeSql FluentApi 配置实体,方法名与特性相同 @@ -2659,7 +2790,7 @@ - 在外部配置实体的特性 + FreeSql FluentApi 配置实体,方法名与特性相同 @@ -2667,7 +2798,7 @@ - 获取在外部配置实体的特性 + 获取 FreeSql FluentApi 配置实体的元数据 未使用ConfigEntity配置时,返回null @@ -2825,6 +2956,12 @@ 超时 + + + 获取资源 + + + 使用完毕后,归还资源 @@ -2895,6 +3032,12 @@ 资源对象 + + + 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象 + + 资源对象 + 归还对象给对象池的时候触发 @@ -3078,7 +3221,7 @@ BigApple -> bigapple - + C#: that >= between && that <= and SQL: that BETWEEN between AND and @@ -3088,7 +3231,7 @@ - + 注意:这个方法和 Between 有细微区别 C#: that >= start && that < end @@ -3527,167 +3670,4 @@ - - - - - - 使用 or 拼接两个 lambda 表达式 - - - - - - 使用 or 拼接两个 lambda 表达式 - - - true 时生效 - - - - - - 将 lambda 表达式取反 - - - true 时生效 - - - - - 生成类似Mongodb的ObjectId有序、不重复Guid - - - - - - 插入数据 - - - - - - - 插入数据,传入实体 - - - - - - - - 插入数据,传入实体数组 - - - - - - - - 插入数据,传入实体集合 - - - - - - - - 插入数据,传入实体集合 - - - - - - - - 修改数据 - - - - - - - 修改数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - - - - - 查询数据 - - - - - - - 查询数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - - - - - 删除数据 - - - - - - - 删除数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - - - - - 开启事务(不支持异步),60秒未执行完成(可能)被其他线程事务自动提交 - - 事务体 () => {} - - - - 开启事务(不支持异步) - - 超时,未执行完成(可能)被其他线程事务自动提交 - 事务体 () => {} - - - - 开启事务(不支持异步) - - - 事务体 () => {} - 超时,未执行完成(可能)被其他线程事务自动提交 - - - - 数据库访问对象 - - - - - 所有拦截方法都在这里 - - - - - CodeFirst 模式开发相关方法 - - - - - DbFirst 模式开发相关方法 - - - - - 全局过滤设置,可默认附加为 Select/Update/Delete 条件 - - - diff --git a/FreeSql/Interface/ICodeFirst.cs b/FreeSql/Interface/ICodeFirst.cs index c5cd16e6..e0ee5e45 100644 --- a/FreeSql/Interface/ICodeFirst.cs +++ b/FreeSql/Interface/ICodeFirst.cs @@ -86,21 +86,21 @@ namespace FreeSql /// DbInfoResult GetDbInfo(Type type); /// - /// 在外部配置实体的特性 + /// FreeSql FluentApi 配置实体,方法名与特性相同 /// /// /// /// ICodeFirst ConfigEntity(Action> entity); /// - /// 在外部配置实体的特性 + /// FreeSql FluentApi 配置实体,方法名与特性相同 /// /// /// /// ICodeFirst ConfigEntity(Type type, Action entity); /// - /// 获取在外部配置实体的特性 + /// 获取 FreeSql FluentApi 配置实体的元数据 /// /// /// 未使用ConfigEntity配置时,返回null