AggregateRootRepository

This commit is contained in:
2881099 2022-09-02 16:14:48 +08:00
parent df18373ee5
commit ab9db8270d
7 changed files with 268 additions and 38 deletions

49
FreeSql-DbContext.sln Normal file
View File

@ -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

View File

@ -57,11 +57,16 @@ namespace FreeSql
public Type EntityType => _repository.EntityType;
public IDataFilter<TEntity> 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<TEntity> entity)
{
foreach (var item in entity)
AttachAggregateRoot(item);
Attach(item);
}
public IBaseRepository<TEntity> AttachOnlyPrimary(TEntity data) => _repository.AttachOnlyPrimary(data);
public Dictionary<string, object[]> 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<TEntity> Select => SelectAggregateRoot;
ISelect<TEntity> SelectAggregateRoot
protected ISelect<TEntity> SelectAggregateRoot
{
get
{
@ -149,6 +148,33 @@ namespace FreeSql
return query;
}
}
protected void SelectAggregateRootTracking(object list)
{
if (list == null) return;
var ls = list as IEnumerable<TEntity>;
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<T1>(ISelect<T1> currentQuery, Type entityType, string navigatePath, Stack<Type> 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<TEntity>;
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
}

View File

@ -71,10 +71,15 @@ namespace FreeSql
}
List<T1> LocalInsertAggregateRoot<T1>(IBaseRepository<T1> repository, IEnumerable<T1> 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<TEntity> _dataEditing;

View File

@ -0,0 +1,12 @@
using FreeSql;
using System;
using System.Linq;
using System.Linq.Expressions;
public static class FreeSqlRepositoryExtensions
{
public static IBaseRepository<TEntity> GetAggregateRootRepository<TEntity>(this IFreeSql that) where TEntity : class
{
return new AggregateRootRepository<TEntity>(that);
}
}

View File

@ -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<User>();
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; }
}
}
}

View File

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<WarningLevel>3</WarningLevel>
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\FreeSql.DbContext\FreeSql.DbContext.csproj" />
<ProjectReference Include="..\..\FreeSql.Repository\FreeSql.Repository.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
public class g
{
static Lazy<IFreeSql> sqliteLazy = new Lazy<IFreeSql>(() => 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();
}
}