From ab9db8270d84f928b57684a653c54f423cf02880 Mon Sep 17 00:00:00 2001 From: 2881099 <2881099@qq.com> Date: Fri, 2 Sep 2022 16:14:48 +0800 Subject: [PATCH] AggregateRootRepository --- FreeSql-DbContext.sln | 49 +++++++++ FreeSql.Repository/AggregateRootRepository.cs | 70 ++++++------ .../AggregateRootRepositorySync.cs | 11 +- .../FreeSqlRepositoryExtensions.cs | 12 +++ .../AggregateRootRepositoryTest.cs | 101 ++++++++++++++++++ .../FreeSql.Tests.DbContext2.csproj | 28 +++++ FreeSql.Tests/FreeSql.Tests.DbContext2/g.cs | 35 ++++++ 7 files changed, 268 insertions(+), 38 deletions(-) create mode 100644 FreeSql-DbContext.sln create mode 100644 FreeSql.Repository/FreeSqlRepositoryExtensions.cs create mode 100644 FreeSql.Tests/FreeSql.Tests.DbContext2/AggregateRootRepositoryTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests.DbContext2/FreeSql.Tests.DbContext2.csproj create mode 100644 FreeSql.Tests/FreeSql.Tests.DbContext2/g.cs diff --git a/FreeSql-DbContext.sln b/FreeSql-DbContext.sln new file mode 100644 index 00000000..c98618ed --- /dev/null +++ b/FreeSql-DbContext.sln @@ -0,0 +1,49 @@ + +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", "{6FF3EE89-EE9C-4542-B078-134E98AD7410}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.DbContext", "FreeSql.DbContext\FreeSql.DbContext.csproj", "{A3B931A2-C38F-455D-A07A-5B29BE2AADA4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Repository", "FreeSql.Repository\FreeSql.Repository.csproj", "{02C02FB6-2E7D-4D64-80E6-A62CCFD4C248}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.Sqlite", "Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj", "{076FB016-D462-45AF-9368-47E359111FB8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Tests.DbContext2", "FreeSql.Tests\FreeSql.Tests.DbContext2\FreeSql.Tests.DbContext2.csproj", "{5B0AFA8E-D367-4D30-85C0-107DACB0FF49}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6FF3EE89-EE9C-4542-B078-134E98AD7410}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6FF3EE89-EE9C-4542-B078-134E98AD7410}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6FF3EE89-EE9C-4542-B078-134E98AD7410}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6FF3EE89-EE9C-4542-B078-134E98AD7410}.Release|Any CPU.Build.0 = Release|Any CPU + {A3B931A2-C38F-455D-A07A-5B29BE2AADA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A3B931A2-C38F-455D-A07A-5B29BE2AADA4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A3B931A2-C38F-455D-A07A-5B29BE2AADA4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A3B931A2-C38F-455D-A07A-5B29BE2AADA4}.Release|Any CPU.Build.0 = Release|Any CPU + {02C02FB6-2E7D-4D64-80E6-A62CCFD4C248}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {02C02FB6-2E7D-4D64-80E6-A62CCFD4C248}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02C02FB6-2E7D-4D64-80E6-A62CCFD4C248}.Release|Any CPU.ActiveCfg = Release|Any CPU + {02C02FB6-2E7D-4D64-80E6-A62CCFD4C248}.Release|Any CPU.Build.0 = Release|Any CPU + {076FB016-D462-45AF-9368-47E359111FB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {076FB016-D462-45AF-9368-47E359111FB8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {076FB016-D462-45AF-9368-47E359111FB8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {076FB016-D462-45AF-9368-47E359111FB8}.Release|Any CPU.Build.0 = Release|Any CPU + {5B0AFA8E-D367-4D30-85C0-107DACB0FF49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B0AFA8E-D367-4D30-85C0-107DACB0FF49}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B0AFA8E-D367-4D30-85C0-107DACB0FF49}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B0AFA8E-D367-4D30-85C0-107DACB0FF49}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F28A32E9-6D71-4474-AB43-5E813111F5D1} + EndGlobalSection +EndGlobal diff --git a/FreeSql.Repository/AggregateRootRepository.cs b/FreeSql.Repository/AggregateRootRepository.cs index 5d3e08f3..6e4440d6 100644 --- a/FreeSql.Repository/AggregateRootRepository.cs +++ b/FreeSql.Repository/AggregateRootRepository.cs @@ -57,11 +57,16 @@ namespace FreeSql public Type EntityType => _repository.EntityType; public IDataFilter DataFilter => _repository.DataFilter; - public void Attach(TEntity entity) => AttachAggregateRoot(entity); + public void Attach(TEntity entity) + { + var state = CreateEntityState(entity); + if (_states.ContainsKey(state.Key)) _states[state.Key] = state; + else _states.Add(state.Key, state); + } public void Attach(IEnumerable entity) { foreach (var item in entity) - AttachAggregateRoot(item); + Attach(item); } public IBaseRepository AttachOnlyPrimary(TEntity data) => _repository.AttachOnlyPrimary(data); public Dictionary CompareState(TEntity newdata) => _repository.CompareState(newdata); @@ -130,17 +135,11 @@ namespace FreeSql if (string.IsNullOrEmpty(key)) return null; return _states.ContainsKey(key); } - void AttachAggregateRoot(TEntity entity) - { - var state = CreateEntityState(entity); - if (_states.ContainsKey(state.Key)) _states[state.Key] = state; - else _states.Add(state.Key, state); - } #endregion #region Selectoriginal public virtual ISelect Select => SelectAggregateRoot; - ISelect SelectAggregateRoot + protected ISelect SelectAggregateRoot { get { @@ -149,6 +148,33 @@ namespace FreeSql return query; } } + protected void SelectAggregateRootTracking(object list) + { + if (list == null) return; + var ls = list as IEnumerable; + if (ls == null) + { + var ie = list as IEnumerable; + if (ie == null) return; + var isfirst = true; + foreach (var item in ie) + { + if (item == null) continue; + if (isfirst) + { + isfirst = false; + var itemType = item.GetType(); + if (itemType == typeof(object)) return; + if (itemType.FullName.Contains("FreeSqlLazyEntity__")) itemType = itemType.BaseType; + if (Orm.CodeFirst.GetTableByEntity(itemType)?.Primarys.Any() != true) return; + if (itemType.GetConstructor(Type.EmptyTypes) == null) return; + } + if (item is TEntity item2) Attach(item2); + else return; + } + return; + } + } void SelectAggregateRootNavigateReader(ISelect currentQuery, Type entityType, string navigatePath, Stack ignores) { if (ignores.Any(a => a == entityType)) return; @@ -182,32 +208,6 @@ namespace FreeSql } ignores.Pop(); } - void SelectAggregateRootTracking(object list) - { - if (list == null) return; - var ls = list as IEnumerable; - if (ls == null) - { - var ie = list as IEnumerable; - if (ie == null) return; - var isfirst = true; - foreach (var item in ie) - { - if (item == null) continue; - if (isfirst) - { - isfirst = false; - var itemType = item.GetType(); - if (itemType == typeof(object)) return; - if (itemType.FullName.Contains("FreeSqlLazyEntity__")) itemType = itemType.BaseType; - if (Orm.CodeFirst.GetTableByEntity(itemType)?.Primarys.Any() != true) return; - if (itemType.GetConstructor(Type.EmptyTypes) == null) return; - } - AttachAggregateRoot(item as TEntity); - } - return; - } - } #endregion } diff --git a/FreeSql.Repository/AggregateRootRepositorySync.cs b/FreeSql.Repository/AggregateRootRepositorySync.cs index 0826d3eb..e3d8dc6b 100644 --- a/FreeSql.Repository/AggregateRootRepositorySync.cs +++ b/FreeSql.Repository/AggregateRootRepositorySync.cs @@ -71,10 +71,15 @@ namespace FreeSql } List LocalInsertAggregateRoot(IBaseRepository repository, IEnumerable entitys) where T1 : class { + var table = repository.Orm.CodeFirst.GetTableByEntity(repository.EntityType); + if (table.Primarys.Any(col => col.Attribute.IsIdentity)) + { + foreach (var entity in entitys) + repository.Orm.ClearEntityPrimaryValueWithIdentity(repository.EntityType, entity); + } var ret = repository.Insert(entitys); foreach (var entity in entitys) LocalCanAggregateRoot(repository.EntityType, entity, true); - var table = repository.Orm.CodeFirst.GetTableByEntity(repository.EntityType); foreach (var prop in table.Properties.Values) { var tbref = table.GetTableRef(prop.Name, false); @@ -166,7 +171,7 @@ namespace FreeSql var stateKey = Orm.GetEntityKeyString(EntityType, entity, false); if (_states.TryGetValue(stateKey, out var state) == false) throw new Exception($"AggregateRootRepository 使用仓储对象查询后,才可以更新数据 {Orm.GetEntityString(EntityType, entity)}"); AggregateRootUtils.CompareEntityValue(Orm, EntityType, state.Value, entity, null, insertLog, updateLog, deleteLog); - AttachAggregateRoot(entity); + Attach(entity); } return insertLog.Count + updateLog.Count + deleteLog.Count; } @@ -193,7 +198,7 @@ namespace FreeSql var stateKey = Orm.GetEntityKeyString(EntityType, entity, false); if (_states.TryGetValue(stateKey, out var state) == false) throw new Exception($"AggregateRootRepository 使用仓储对象查询后,才可以保存数据 {Orm.GetEntityString(EntityType, entity)}"); AggregateRootUtils.CompareEntityValue(Orm, EntityType, state.Value, entity, propertyName, insertLog, updateLog, deleteLog); - AttachAggregateRoot(entity); + Attach(entity); } protected List _dataEditing; diff --git a/FreeSql.Repository/FreeSqlRepositoryExtensions.cs b/FreeSql.Repository/FreeSqlRepositoryExtensions.cs new file mode 100644 index 00000000..6707ad11 --- /dev/null +++ b/FreeSql.Repository/FreeSqlRepositoryExtensions.cs @@ -0,0 +1,12 @@ +using FreeSql; +using System; +using System.Linq; +using System.Linq.Expressions; + +public static class FreeSqlRepositoryExtensions +{ + public static IBaseRepository GetAggregateRootRepository(this IFreeSql that) where TEntity : class + { + return new AggregateRootRepository(that); + } +} \ No newline at end of file diff --git a/FreeSql.Tests/FreeSql.Tests.DbContext2/AggregateRootRepositoryTest.cs b/FreeSql.Tests/FreeSql.Tests.DbContext2/AggregateRootRepositoryTest.cs new file mode 100644 index 00000000..89dd09b0 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests.DbContext2/AggregateRootRepositoryTest.cs @@ -0,0 +1,101 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace FreeSql.Tests.DbContext2 +{ + public class AggregateRootRepositoryTest + { + [Fact] + public void Test1v1() + { + using (var fsql = g.CreateMemory()) + { + var repo = fsql.GetAggregateRootRepository(); + var user = new User + { + UserName = "admin01", + Password = "admin01_pwd", + Ext = new UserExt + { + Remark = "admin01_remark" + } + }; + repo.Insert(user); + Assert.Equal(1, user.Id); + Assert.Equal(1, user.Ext.UserId); + + user = repo.Where(a => a.Id == 1).First(); + Assert.NotNull(user); + Assert.Equal(1, user.Id); + Assert.Equal("admin01", user.UserName); + Assert.Equal("admin01_pwd", user.Password); + Assert.NotNull(user.Ext); + Assert.Equal(1, user.Ext.UserId); + Assert.Equal("admin01_remark", user.Ext.Remark); + + var users = new[]{ + new User + { + UserName = "admin02", + Password = "admin02_pwd", + Ext = new UserExt + { + Remark = "admin02_remark" + } + }, + new User + { + UserName = "admin03", + Password = "admin03_pwd", + Ext = new UserExt + { + Remark = "admin03_remark" + } + }, + }; + repo.Insert(users); + Assert.Equal(2, users[0].Id); + Assert.Equal(2, users[0].Ext.UserId); + Assert.Equal(3, users[1].Id); + Assert.Equal(3, users[1].Ext.UserId); + + users = repo.Where(a => a.Id > 1).ToList().ToArray(); + Assert.Equal(2, users.Length); + Assert.Equal(2, users[0].Id); + Assert.Equal("admin02", users[0].UserName); + Assert.Equal("admin02_pwd", users[0].Password); + Assert.NotNull(users[0].Ext); + Assert.Equal(2, users[0].Ext.UserId); + Assert.Equal("admin02_remark", users[0].Ext.Remark); + Assert.Equal(3, users[1].Id); + Assert.Equal("admin03", users[1].UserName); + Assert.Equal("admin03_pwd", users[1].Password); + Assert.NotNull(users[1].Ext); + Assert.Equal(3, users[1].Ext.UserId); + Assert.Equal("admin03_remark", users[1].Ext.Remark); + } + } + class User + { + [Column(IsIdentity = true)] + public int Id { get; set; } + public string UserName { get; set; } + public string Password { get; set; } + [Navigate(nameof(Id))] + public UserExt Ext { get; set; } + } + class UserExt + { + [Column(IsPrimary = true)] + public int UserId { get; set; } + public string Remark { get; set; } + [Navigate(nameof(UserId))] + public User Org { get; set; } + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests.DbContext2/FreeSql.Tests.DbContext2.csproj b/FreeSql.Tests/FreeSql.Tests.DbContext2/FreeSql.Tests.DbContext2.csproj new file mode 100644 index 00000000..8b4feaa1 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests.DbContext2/FreeSql.Tests.DbContext2.csproj @@ -0,0 +1,28 @@ + + + + net5.0 + false + + + + 3 + 1701;1702;1591 + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + diff --git a/FreeSql.Tests/FreeSql.Tests.DbContext2/g.cs b/FreeSql.Tests/FreeSql.Tests.DbContext2/g.cs new file mode 100644 index 00000000..9b56523d --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests.DbContext2/g.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +public class g +{ + static Lazy sqliteLazy = new Lazy(() => new FreeSql.FreeSqlBuilder() + .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|/document22.db;Attachs=xxxtb.db;Pooling=true;Max Pool Size=10") + .UseAutoSyncStructure(true) + .UseLazyLoading(true) + .UseMonitorCommand( + cmd => + { + Trace.WriteLine(cmd.CommandText); + }, //监听SQL命令对象,在执行前 + (cmd, traceLog) => + { + Console.WriteLine(traceLog); + }) //监听SQL命令对象,在执行后 + .UseNoneCommandParameter(true) + .Build()); + public static IFreeSql sqlite => sqliteLazy.Value; + + public static IFreeSql CreateMemory() + { + return new FreeSql.FreeSqlBuilder() + .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=:memory:") + .UseAutoSyncStructure(true) + .UseNoneCommandParameter(true) + .UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText)) + .Build(); + } + +}