AggregateRootRepository

This commit is contained in:
2881099 2022-09-03 17:59:57 +08:00
parent 319467dcc4
commit a590b8aa7b
6 changed files with 577 additions and 494 deletions

View File

@ -0,0 +1,24 @@
using FreeSql;
using FreeSql.Extensions.EntityUtil;
using FreeSql.Internal;
using FreeSql.Internal.CommonProvider;
using FreeSql.Internal.Model;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
namespace FreeSql.Internal.Model
{
public class AggregateRootTrackingChangeInfo
{
public List<NativeTuple<Type, object>> InsertLog { get; } = new List<NativeTuple<Type, object>>();
public List<NativeTuple<Type, object, object, List<string>>> UpdateLog { get; } = new List<NativeTuple<Type, object, object, List<string>>>();
public List<NativeTuple<Type, object[]>> DeleteLog { get; } = new List<NativeTuple<Type, object[]>>();
}
}

View File

@ -17,18 +17,22 @@ namespace FreeSql
{ {
partial class AggregateRootRepository<TEntity> partial class AggregateRootRepository<TEntity>
{ {
public Task<TEntity> InsertAsync(TEntity entity, CancellationToken cancellationToken = default) => _repository.InsertAsync(entity, cancellationToken); //以下临时调用同步方法
public Task<List<TEntity>> InsertAsync(IEnumerable<TEntity> entitys, CancellationToken cancellationToken = default) => _repository.InsertAsync(entitys, cancellationToken); public Task<TEntity> InsertAsync(TEntity entity, CancellationToken cancellationToken = default) => Task.FromResult(Insert(entity));
public Task<TEntity> InsertOrUpdateAsync(TEntity entity, CancellationToken cancellationToken = default) => _repository.InsertOrUpdateAsync(entity, cancellationToken); public Task<List<TEntity>> InsertAsync(IEnumerable<TEntity> entitys, CancellationToken cancellationToken = default) => Task.FromResult(Insert(entitys));
public Task SaveManyAsync(TEntity entity, string propertyName, CancellationToken cancellationToken = default) => _repository.SaveManyAsync(entity, propertyName, cancellationToken); public Task<TEntity> InsertOrUpdateAsync(TEntity entity, CancellationToken cancellationToken = default) => Task.FromResult(InsertOrUpdate(entity));
async public Task SaveManyAsync(TEntity entity, string propertyName, CancellationToken cancellationToken = default)
{
SaveMany(entity, propertyName);
}
public Task<int> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default) => _repository.UpdateAsync(entity, cancellationToken); public Task<int> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default) => Task.FromResult(Update(entity));
public Task<int> UpdateAsync(IEnumerable<TEntity> entitys, CancellationToken cancellationToken = default) => _repository.UpdateAsync(entitys, cancellationToken); public Task<int> UpdateAsync(IEnumerable<TEntity> entitys, CancellationToken cancellationToken = default) => Task.FromResult(Update(entitys));
public Task<int> DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) => _repository.DeleteAsync(entity, cancellationToken); public Task<int> DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) => Task.FromResult(Delete(entity));
public Task<int> DeleteAsync(IEnumerable<TEntity> entitys, CancellationToken cancellationToken = default) => _repository.DeleteAsync(entitys, cancellationToken); public Task<int> DeleteAsync(IEnumerable<TEntity> entitys, CancellationToken cancellationToken = default) => Task.FromResult(Delete(entitys));
public Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) => _repository.DeleteAsync(predicate, cancellationToken); public Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) => Task.FromResult(Delete(predicate));
public Task<List<object>> DeleteCascadeByDatabaseAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) => _repository.DeleteCascadeByDatabaseAsync(predicate, cancellationToken); public Task<List<object>> DeleteCascadeByDatabaseAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) => Task.FromResult(DeleteCascadeByDatabase(predicate));
} }
} }

View File

@ -91,7 +91,7 @@ namespace FreeSql
localAffrows += ret.Count; localAffrows += ret.Count;
foreach (var entity in entitys) LocalCanAggregateRoot(repository.EntityType, entity, true); foreach (var entity in entitys) LocalCanAggregateRoot(repository.EntityType, entity, true);
foreach (var tr in table.GetAllTableRef()) foreach (var tr in table.GetAllTableRef().OrderBy(a => a.Value.RefType).ThenBy(a => a.Key))
{ {
var tbref = tr.Value; var tbref = tr.Value;
if (tbref.Exception != null) continue; if (tbref.Exception != null) continue;
@ -180,36 +180,35 @@ namespace FreeSql
} }
protected virtual int UpdateAggregateRoot(IEnumerable<TEntity> entitys) protected virtual int UpdateAggregateRoot(IEnumerable<TEntity> entitys)
{ {
List<NativeTuple<Type, object>> insertLog = new List<NativeTuple<Type, object>>(); var tracking = new AggregateRootTrackingChangeInfo();
List<NativeTuple<Type, object, object, List<string>>> updateLog = new List<NativeTuple<Type, object, object, List<string>>>();
List<NativeTuple<Type, object[]>> deleteLog = new List<NativeTuple<Type, object[]>>();
foreach(var entity in entitys) foreach(var entity in entitys)
{ {
var stateKey = Orm.GetEntityKeyString(EntityType, entity, false); var stateKey = Orm.GetEntityKeyString(EntityType, entity, false);
if (_states.TryGetValue(stateKey, out var state) == false) throw new Exception($"AggregateRootRepository 使用仓储对象查询后,才可以更新数据 {Orm.GetEntityString(EntityType, entity)}"); 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); AggregateRootUtils.CompareEntityValue(Orm, EntityType, state.Value, entity, null, tracking);
} }
var affrows = 0; var affrows = 0;
DisposeChildRepositorys(); DisposeChildRepositorys();
var insertLogDict = insertLog.GroupBy(a => a.Item1).ToDictionary(a => a.Key, a => insertLog.Where(b => b.Item1 == a.Key).Select(b => b.Item2).ToArray()); var insertLogDict = tracking.InsertLog.GroupBy(a => a.Item1).ToDictionary(a => a.Key, a => tracking.InsertLog.Where(b => b.Item1 == a.Key).Select(b => b.Item2).ToArray());
foreach (var il in insertLogDict) foreach (var il in insertLogDict)
{ {
InsertAggregateRootStatic(GetChildRepository(il.Key), GetChildRepository, il.Value, out var affrowsOut); var repo = GetChildRepository(il.Key);
InsertAggregateRootStatic(repo, GetChildRepository, il.Value, out var affrowsOut);
affrows += affrowsOut; affrows += affrowsOut;
} }
for (var a = 0; a < deleteLog.Count - 1; a++) for (var a = tracking.DeleteLog.Count - 1; a >= 0; a--)
affrows += Orm.Delete<object>().AsType(deleteLog[a].Item1).WhereDynamic(deleteLog[a].Item2).ExecuteAffrows(); affrows += Orm.Delete<object>().AsType(tracking.DeleteLog[a].Item1).AsTable(_asTableRule)
.WhereDynamic(tracking.DeleteLog[a].Item2).ExecuteAffrows();
var updateLogDict = updateLog.GroupBy(a => a.Item1).ToDictionary(a => a.Key, a => updateLog.Where(b => b.Item1 == a.Key).Select(b => var updateLogDict = tracking.UpdateLog.GroupBy(a => a.Item1).ToDictionary(a => a.Key, a => tracking.UpdateLog.Where(b => b.Item1 == a.Key).Select(b =>
NativeTuple.Create(b.Item2, b.Item3, string.Join(",", b.Item4.OrderBy(c => c)), b.Item4)).ToArray()); NativeTuple.Create(b.Item2, b.Item3, string.Join(",", b.Item4.OrderBy(c => c)), b.Item4)).ToArray());
var updateLogDict2 = updateLogDict.ToDictionary(a => a.Key, a => a.Value.ToDictionary(b => b.Item3, b => a.Value.Where(c => c.Item3 == b.Item3).ToArray())); var updateLogDict2 = updateLogDict.ToDictionary(a => a.Key, a => a.Value.ToDictionary(b => b.Item3, b => a.Value.Where(c => c.Item3 == b.Item3).ToArray()));
foreach (var dl in updateLogDict2) foreach (var dl in updateLogDict2)
{ {
foreach (var dl2 in dl.Value) foreach (var dl2 in dl.Value)
{ {
affrows += Orm.Update<object>().AsType(dl.Key) affrows += Orm.Update<object>().AsType(dl.Key).AsTable(_asTableRule)
.SetSource(dl2.Value.Select(a => a.Item2).ToArray()) .SetSource(dl2.Value.Select(a => a.Item2).ToArray())
.UpdateColumns(dl2.Value.First().Item4.ToArray()) .UpdateColumns(dl2.Value.First().Item4.ToArray())
.ExecuteAffrows(); .ExecuteAffrows();
@ -223,27 +222,29 @@ namespace FreeSql
} }
protected virtual int DeleteAggregateRoot(IEnumerable<TEntity> entitys, List<object> deletedOutput = null) protected virtual int DeleteAggregateRoot(IEnumerable<TEntity> entitys, List<object> deletedOutput = null)
{ {
List<NativeTuple<Type, object>> insertLog = new List<NativeTuple<Type, object>>(); var tracking = new AggregateRootTrackingChangeInfo();
List<NativeTuple<Type, object, object, List<string>>> updateLog = new List<NativeTuple<Type, object, object, List<string>>>();
List<NativeTuple<Type, object[]>> deleteLog = new List<NativeTuple<Type, object[]>>();
foreach (var entity in entitys) foreach (var entity in entitys)
{ {
var stateKey = Orm.GetEntityKeyString(EntityType, entity, false); var stateKey = Orm.GetEntityKeyString(EntityType, entity, false);
AggregateRootUtils.CompareEntityValue(Orm, EntityType, entity, null, null, insertLog, updateLog, deleteLog); AggregateRootUtils.CompareEntityValue(Orm, EntityType, entity, null, null, tracking);
_states.Remove(stateKey); _states.Remove(stateKey);
} }
if (deletedOutput != null) deletedOutput.AddRange(deleteLog.Select(a => a.Item2)); var affrows = 0;
return deleteLog.Count; for (var a = tracking.DeleteLog.Count - 1; a >= 0; a--)
{
affrows += Orm.Delete<object>().AsType(tracking.DeleteLog[a].Item1).AsTable(_asTableRule)
.WhereDynamic(tracking.DeleteLog[a].Item2).ExecuteAffrows();
if (deletedOutput != null) deletedOutput.AddRange(tracking.DeleteLog[a].Item2);
}
return affrows;
} }
protected virtual void SaveManyAggregateRoot(TEntity entity, string propertyName) protected virtual void SaveManyAggregateRoot(TEntity entity, string propertyName)
{ {
List<NativeTuple<Type, object>> insertLog = new List<NativeTuple<Type, object>>(); var tracking = new AggregateRootTrackingChangeInfo();
List<NativeTuple<Type, object, object, List<string>>> updateLog = new List<NativeTuple<Type, object, object, List<string>>>();
List<NativeTuple<Type, object[]>> deleteLog = new List<NativeTuple<Type, object[]>>();
var stateKey = Orm.GetEntityKeyString(EntityType, entity, false); var stateKey = Orm.GetEntityKeyString(EntityType, entity, false);
if (_states.TryGetValue(stateKey, out var state) == false) throw new Exception($"AggregateRootRepository 使用仓储对象查询后,才可以保存数据 {Orm.GetEntityString(EntityType, entity)}"); 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); AggregateRootUtils.CompareEntityValue(Orm, EntityType, state.Value, entity, propertyName, tracking);
Attach(entity); Attach(entity);
} }
@ -273,9 +274,7 @@ namespace FreeSql
{ {
if (data == null) data = _dataEditing; if (data == null) data = _dataEditing;
if (data == null) return 0; if (data == null) return 0;
List<NativeTuple<Type, object>> insertLog = new List<NativeTuple<Type, object>>(); var tracking = new AggregateRootTrackingChangeInfo();
List<NativeTuple<Type, object, object, List<string>>> updateLog = new List<NativeTuple<Type, object, object, List<string>>>();
List<NativeTuple<Type, object[]>> deleteLog = new List<NativeTuple<Type, object[]>>();
try try
{ {
var addList = new List<TEntity>(); var addList = new List<TEntity>();
@ -285,23 +284,23 @@ namespace FreeSql
var key = Orm.GetEntityKeyString(EntityType, item, false); var key = Orm.GetEntityKeyString(EntityType, item, false);
if (_statesEditing.TryRemove(key, out var state) == false) if (_statesEditing.TryRemove(key, out var state) == false)
{ {
insertLog.Add(NativeTuple.Create(EntityType, (object)item)); tracking.InsertLog.Add(NativeTuple.Create(EntityType, (object)item));
continue; continue;
} }
_states[key] = state; _states[key] = state;
AggregateRootUtils.CompareEntityValue(Orm, EntityType, state.Value, item, null, insertLog, updateLog, deleteLog); AggregateRootUtils.CompareEntityValue(Orm, EntityType, state.Value, item, null, tracking);
} }
foreach (var item in _statesEditing.Values.OrderBy(a => a.Time)) foreach (var item in _statesEditing.Values.OrderBy(a => a.Time))
{ AggregateRootUtils.CompareEntityValue(Orm, EntityType, item, null, null, tracking);
AggregateRootUtils.CompareEntityValue(Orm, EntityType, item, null, null, insertLog, updateLog, deleteLog);
}
} }
finally finally
{ {
_dataEditing = null; _dataEditing = null;
_statesEditing.Clear(); _statesEditing.Clear();
} }
return insertLog.Count + updateLog.Count + deleteLog.Count; return tracking.InsertLog.Count + tracking.UpdateLog.Count + tracking.DeleteLog.Count;
} }
} }

View File

@ -13,12 +13,11 @@ using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
static class AggregateRootUtils namespace FreeSql
{ {
public static void CompareEntityValue(IFreeSql fsql, Type rootEntityType, object rootEntityBefore, object rootEntityAfter, string rootNavigatePropertyName, public static class AggregateRootUtils
List<NativeTuple<Type, object>> insertLog, {
List<NativeTuple<Type, object, object, List<string>>> updateLog, public static void CompareEntityValue(IFreeSql fsql, Type rootEntityType, object rootEntityBefore, object rootEntityAfter, string rootNavigatePropertyName, AggregateRootTrackingChangeInfo tracking)
List<NativeTuple<Type, object[]>> deleteLog)
{ {
Dictionary<Type, Dictionary<string, bool>> ignores = new Dictionary<Type, Dictionary<string, bool>>(); Dictionary<Type, Dictionary<string, bool>> ignores = new Dictionary<Type, Dictionary<string, bool>>();
LocalCompareEntityValue(rootEntityType, rootEntityBefore, rootEntityAfter, rootNavigatePropertyName); LocalCompareEntityValue(rootEntityType, rootEntityBefore, rootEntityAfter, rootNavigatePropertyName);
@ -48,16 +47,16 @@ static class AggregateRootUtils
if (entityBefore == null && entityAfter == null) return; if (entityBefore == null && entityAfter == null) return;
if (entityBefore == null && entityAfter != null) if (entityBefore == null && entityAfter != null)
{ {
insertLog.Add(NativeTuple.Create(entityType, entityAfter)); tracking.InsertLog.Add(NativeTuple.Create(entityType, entityAfter));
return; return;
} }
if (entityBefore != null && entityAfter == null) if (entityBefore != null && entityAfter == null)
{ {
deleteLog.Add(NativeTuple.Create(entityType, new[] { entityBefore })); tracking.DeleteLog.Add(NativeTuple.Create(entityType, new[] { entityBefore }));
NavigateReader(fsql, entityType, entityBefore, (path, tr, ct, stackvs) => NavigateReader(fsql, entityType, entityBefore, (path, tr, ct, stackvs) =>
{ {
var dellist = stackvs.First() as object[] ?? new[] { stackvs.First() }; var dellist = stackvs.Last() as object[] ?? new[] { stackvs.Last() };
deleteLog.Add(NativeTuple.Create(ct, dellist)); tracking.DeleteLog.Add(NativeTuple.Create(ct, dellist));
}); });
return; return;
} }
@ -75,9 +74,9 @@ static class AggregateRootUtils
} }
} }
if (changes.Any()) if (changes.Any())
updateLog.Add(NativeTuple.Create(entityType, entityBefore, entityAfter, changes)); tracking.UpdateLog.Add(NativeTuple.Create(entityType, entityBefore, entityAfter, changes));
foreach (var tr in table.GetAllTableRef()) foreach (var tr in table.GetAllTableRef().OrderBy(a => a.Value.RefType).ThenBy(a => a.Key))
{ {
var tbref = tr.Value; var tbref = tr.Value;
if (tbref.Exception != null) continue; if (tbref.Exception != null) continue;
@ -115,18 +114,18 @@ static class AggregateRootUtils
if (collectionBefore == null && collectionAfter != null) if (collectionBefore == null && collectionAfter != null)
{ {
foreach (var item in collectionAfter) foreach (var item in collectionAfter)
insertLog.Add(NativeTuple.Create(elementType, item)); tracking.InsertLog.Add(NativeTuple.Create(elementType, item));
return; return;
} }
if (collectionBefore != null && collectionAfter == null) if (collectionBefore != null && collectionAfter == null)
{ {
//foreach (var item in collectionBefore as IEnumerable) //foreach (var item in collectionBefore as IEnumerable)
//{ //{
// deleteLog.Add(NativeTuple.Create(elementType, new[] { item })); // changelog.DeleteLog.Add(NativeTuple.Create(elementType, new[] { item }));
// NavigateReader(fsql, elementType, item, (path, tr, ct, stackvs) => // NavigateReader(fsql, elementType, item, (path, tr, ct, stackvs) =>
// { // {
// var dellist = stackvs.First() as object[] ?? new [] { stackvs.First() }; // var dellist = stackvs.Last() as object[] ?? new [] { stackvs.Last() };
// deleteLog.Add(NativeTuple.Create(ct, dellist)); // changelog.DeleteLog.Add(NativeTuple.Create(ct, dellist));
// }); // });
//} //}
return; return;
@ -141,7 +140,7 @@ static class AggregateRootUtils
foreach (var item in collectionAfter as IEnumerable) foreach (var item in collectionAfter as IEnumerable)
{ {
var key = fsql.GetEntityKeyString(elementType, item, false); var key = fsql.GetEntityKeyString(elementType, item, false);
if (key != null) insertLog.Add(NativeTuple.Create(elementType, item)); if (key != null) tracking.InsertLog.Add(NativeTuple.Create(elementType, item));
else dictAfter.Add(key, item); else dictAfter.Add(key, item);
} }
foreach (var key in dictBefore.Keys.ToArray()) foreach (var key in dictBefore.Keys.ToArray())
@ -149,11 +148,11 @@ static class AggregateRootUtils
if (dictAfter.ContainsKey(key) == false) if (dictAfter.ContainsKey(key) == false)
{ {
var value = dictBefore[key]; var value = dictBefore[key];
deleteLog.Add(NativeTuple.Create(elementType, new[] { value })); tracking.DeleteLog.Add(NativeTuple.Create(elementType, new[] { value }));
NavigateReader(fsql, elementType, value, (path, tr, ct, stackvs) => NavigateReader(fsql, elementType, value, (path, tr, ct, stackvs) =>
{ {
var dellist = stackvs.First() as object[] ?? new[] { stackvs.First() }; var dellist = stackvs.Last() as object[] ?? new[] { stackvs.Last() };
deleteLog.Add(NativeTuple.Create(ct, dellist)); tracking.DeleteLog.Add(NativeTuple.Create(ct, dellist));
}); });
dictBefore.Remove(key); dictBefore.Remove(key);
} }
@ -162,7 +161,7 @@ static class AggregateRootUtils
{ {
if (dictBefore.ContainsKey(key) == false) if (dictBefore.ContainsKey(key) == false)
{ {
insertLog.Add(NativeTuple.Create(elementType, dictAfter[key])); tracking.InsertLog.Add(NativeTuple.Create(elementType, dictAfter[key]));
dictAfter.Remove(key); dictAfter.Remove(key);
} }
} }
@ -193,7 +192,7 @@ static class AggregateRootUtils
if (stateKeys.ContainsKey(stateKey)) return; if (stateKeys.ContainsKey(stateKey)) return;
stateKeys.Add(stateKey, true); stateKeys.Add(stateKey, true);
foreach (var tr in table.GetAllTableRef()) foreach (var tr in table.GetAllTableRef().OrderBy(a => a.Value.RefType).ThenBy(a => a.Key))
{ {
var tbref = tr.Value; var tbref = tr.Value;
if (tbref.Exception != null) continue; if (tbref.Exception != null) continue;
@ -202,6 +201,7 @@ static class AggregateRootUtils
{ {
case TableRefType.OneToOne: case TableRefType.OneToOne:
var propval = table.GetPropertyValue(entity, prop.Name); var propval = table.GetPropertyValue(entity, prop.Name);
if (propval == null) continue;
statckPath.Push(prop.Name); statckPath.Push(prop.Name);
stackValues.Add(propval); stackValues.Add(propval);
SetNavigateRelationshipValue(fsql, tbref, table.Type, entity, propval); SetNavigateRelationshipValue(fsql, tbref, table.Type, entity, propval);
@ -212,6 +212,7 @@ static class AggregateRootUtils
break; break;
case TableRefType.OneToMany: case TableRefType.OneToMany:
var propvalOtm = table.GetPropertyValue(entity, prop.Name); var propvalOtm = table.GetPropertyValue(entity, prop.Name);
if (propvalOtm == null) continue;
SetNavigateRelationshipValue(fsql, tbref, table.Type, entity, propvalOtm); SetNavigateRelationshipValue(fsql, tbref, table.Type, entity, propvalOtm);
var propvalOtmList = new List<object>(); var propvalOtmList = new List<object>();
foreach (var val in propvalOtm as IEnumerable) foreach (var val in propvalOtm as IEnumerable)
@ -226,6 +227,7 @@ static class AggregateRootUtils
break; break;
case TableRefType.ManyToMany: case TableRefType.ManyToMany:
var middleValues = GetManyToManyObjects(fsql, table, tbref, entity, prop).ToArray(); var middleValues = GetManyToManyObjects(fsql, table, tbref, entity, prop).ToArray();
if (middleValues == null) continue;
statckPath.Push($"{prop.Name}[]"); statckPath.Push($"{prop.Name}[]");
stackValues.Add(middleValues); stackValues.Add(middleValues);
callback?.Invoke(string.Join(".", statckPath), tbref, tbref.RefEntityType, stackValues); callback?.Invoke(string.Join(".", statckPath), tbref, tbref.RefEntityType, stackValues);
@ -339,7 +341,7 @@ static class AggregateRootUtils
ignores.Push(entityType); ignores.Push(entityType);
var table = select0p._orm.CodeFirst.GetTableByEntity(entityType); var table = select0p._orm.CodeFirst.GetTableByEntity(entityType);
if (table == null) return queryExp; if (table == null) return queryExp;
foreach (var tr in table.GetAllTableRef()) foreach (var tr in table.GetAllTableRef().OrderBy(a => a.Value.RefType).ThenBy(a => a.Key))
{ {
var tbref = tr.Value; var tbref = tr.Value;
if (tbref.Exception != null) continue; if (tbref.Exception != null) continue;
@ -393,7 +395,7 @@ static class AggregateRootUtils
} }
public static string GetAutoIncludeQueryStaicCode(IFreeSql fsql, Type rootEntityType) public static string GetAutoIncludeQueryStaicCode(IFreeSql fsql, Type rootEntityType)
{ {
return LocalGetAutoIncludeQueryStaicCode(1, rootEntityType, "", new Stack<Type>()); return $"//fsql.Select<{rootEntityType.Name}>()\r\nSelectDiy{LocalGetAutoIncludeQueryStaicCode(1, rootEntityType, "", new Stack<Type>())}";
string LocalGetAutoIncludeQueryStaicCode(int depth, Type entityType, string navigatePath, Stack<Type> ignores) string LocalGetAutoIncludeQueryStaicCode(int depth, Type entityType, string navigatePath, Stack<Type> ignores)
{ {
var code = new StringBuilder(); var code = new StringBuilder();
@ -402,7 +404,7 @@ static class AggregateRootUtils
var table = fsql.CodeFirst.GetTableByEntity(entityType); var table = fsql.CodeFirst.GetTableByEntity(entityType);
if (table == null) return null; if (table == null) return null;
if (!string.IsNullOrWhiteSpace(navigatePath)) navigatePath = $"{navigatePath}."; if (!string.IsNullOrWhiteSpace(navigatePath)) navigatePath = $"{navigatePath}.";
foreach (var tr in table.GetAllTableRef()) foreach (var tr in table.GetAllTableRef().OrderBy(a => a.Value.RefType).ThenBy(a => a.Key))
{ {
var tbref = tr.Value; var tbref = tr.Value;
if (tbref.Exception != null) continue; if (tbref.Exception != null) continue;
@ -498,3 +500,4 @@ static class AggregateRootUtils
} }
} }
} }
}

View File

@ -14,7 +14,6 @@ namespace FreeSql.Tests.DbContext2
{ {
public UserRepository(IFreeSql fsql, UnitOfWorkManager uowManager) : base(uowManager?.Orm ?? fsql) public UserRepository(IFreeSql fsql, UnitOfWorkManager uowManager) : base(uowManager?.Orm ?? fsql)
{ {
var code = SelectAggregateRootStaticCode;
} }
public override ISelect<User> Select => base.SelectDiy; public override ISelect<User> Select => base.SelectDiy;
@ -27,6 +26,11 @@ namespace FreeSql.Tests.DbContext2
{ {
new UserRepository(fsql, null); new UserRepository(fsql, null);
var code = AggregateRootUtils.GetAutoIncludeQueryStaicCode(fsql, typeof(User));
Assert.Equal(@"//fsql.Select<User>()
SelectDiy
.Include(a => a.Ext)", code);
var repo = fsql.GetAggregateRootRepository<User>(); var repo = fsql.GetAggregateRootRepository<User>();
var user = new User var user = new User
{ {
@ -93,6 +97,48 @@ namespace FreeSql.Tests.DbContext2
user.Ext.Remark = "admin01_remark changed01"; user.Ext.Remark = "admin01_remark changed01";
repo.Update(user); repo.Update(user);
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 changed01", user.Ext.Remark);
var affrows = repo.Delete(user);
Assert.Equal(2, affrows);
Assert.False(fsql.Select<User>().Where(a => a.Id == 1).Any());
Assert.False(fsql.Select<UserExt>().Where(a => a.UserId == 1).Any());
var deleted = repo.DeleteCascadeByDatabase(a => a.Id == 2 || a.Id == 3);
Assert.NotNull(deleted);
Assert.Equal(4, deleted.Count);
Assert.False(fsql.Select<User>().Where(a => a.Id == 2).Any());
Assert.False(fsql.Select<UserExt>().Where(a => a.UserId == 2).Any());
Assert.False(fsql.Select<User>().Where(a => a.Id == 3).Any());
Assert.False(fsql.Select<UserExt>().Where(a => a.UserId == 3).Any());
users = new[]
{
(User)deleted[3],
(User)deleted[1],
};
users[0].Ext = (UserExt)deleted[2];
users[1].Ext = (UserExt)deleted[0];
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 class User

View File

@ -15,7 +15,6 @@ namespace FreeSql.Tests.DbContext2
{ {
public OrderRepository(IFreeSql fsql, UnitOfWorkManager uowManager) : base(uowManager?.Orm ?? fsql) public OrderRepository(IFreeSql fsql, UnitOfWorkManager uowManager) : base(uowManager?.Orm ?? fsql)
{ {
var code = SelectAggregateRootStaticCode;
} }
public override ISelect<Order> Select => base.SelectDiy; public override ISelect<Order> Select => base.SelectDiy;
@ -28,6 +27,14 @@ namespace FreeSql.Tests.DbContext2
{ {
new OrderRepository(fsql, null); new OrderRepository(fsql, null);
var code = AggregateRootUtils.GetAutoIncludeQueryStaicCode(fsql, typeof(Order));
Assert.Equal(@"//fsql.Select<Order>()
SelectDiy
.IncludeMany(a => a.Details, then => then
.Include(b => b.Extdata))
.IncludeMany(a => a.Tags)
.Include(a => a.Extdata)", code);
fsql.Insert(new[] fsql.Insert(new[]
{ {
new Tag { Name = "tag1" }, new Tag { Name = "tag1" },