mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 02:32:50 +08:00
AggregateRootRepository Boundary
This commit is contained in:
parent
5d12e1c436
commit
9db121d531
28
FreeSql.Repository/AggregateRootBoundaryAttribute.cs
Normal file
28
FreeSql.Repository/AggregateRootBoundaryAttribute.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace FreeSql.DataAnnotations
|
||||||
|
{
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
|
||||||
|
public class AggregateRootBoundaryAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 边界是否终止
|
||||||
|
/// </summary>
|
||||||
|
public bool Break { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 边界是否终止向下探测
|
||||||
|
/// </summary>
|
||||||
|
public bool BreakThen { get; set; }
|
||||||
|
|
||||||
|
public AggregateRootBoundaryAttribute(string name)
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
}
|
||||||
|
public AggregateRootBoundaryAttribute()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using FreeSql.Extensions.EntityUtil;
|
using FreeSql.Extensions.EntityUtil;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -7,7 +8,12 @@ using System.Linq.Expressions;
|
|||||||
|
|
||||||
namespace FreeSql
|
namespace FreeSql
|
||||||
{
|
{
|
||||||
public partial class AggregateRootRepository<TEntity> : IBaseRepository<TEntity> where TEntity : class
|
public interface IAggregateRootRepository<TEntity>: IBaseRepository<TEntity> where TEntity : class
|
||||||
|
{
|
||||||
|
IBaseRepository<TEntity> ChangeBoundary(string name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class AggregateRootRepository<TEntity> : IAggregateRootRepository<TEntity> where TEntity : class
|
||||||
{
|
{
|
||||||
readonly IBaseRepository<TEntity> _repository;
|
readonly IBaseRepository<TEntity> _repository;
|
||||||
public AggregateRootRepository(IFreeSql fsql)
|
public AggregateRootRepository(IFreeSql fsql)
|
||||||
@ -23,10 +29,21 @@ namespace FreeSql
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
DisposeChildRepositorys();
|
DisposeChildRepositorys();
|
||||||
|
_repository.FlushState();
|
||||||
_repository.Dispose();
|
_repository.Dispose();
|
||||||
FlushState();
|
FlushState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string _boundaryName = "";
|
||||||
|
public IBaseRepository<TEntity> ChangeBoundary(string name)
|
||||||
|
{
|
||||||
|
DisposeChildRepositorys();
|
||||||
|
_repository.FlushState();
|
||||||
|
FlushState();
|
||||||
|
_boundaryName = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public IFreeSql Orm => _repository.Orm;
|
public IFreeSql Orm => _repository.Orm;
|
||||||
public IUnitOfWork UnitOfWork { get => _repository.UnitOfWork; set => _repository.UnitOfWork = value; }
|
public IUnitOfWork UnitOfWork { get => _repository.UnitOfWork; set => _repository.UnitOfWork = value; }
|
||||||
public DbContextOptions DbContextOptions
|
public DbContextOptions DbContextOptions
|
||||||
@ -61,9 +78,26 @@ namespace FreeSql
|
|||||||
Attach(item);
|
Attach(item);
|
||||||
}
|
}
|
||||||
public IBaseRepository<TEntity> AttachOnlyPrimary(TEntity data) => _repository.AttachOnlyPrimary(data);
|
public IBaseRepository<TEntity> AttachOnlyPrimary(TEntity data) => _repository.AttachOnlyPrimary(data);
|
||||||
public Dictionary<string, object[]> CompareState(TEntity newdata) => _repository.CompareState(newdata);
|
public Dictionary<string, object[]> CompareState(TEntity newdata)
|
||||||
|
{
|
||||||
|
if (newdata == null) return null;
|
||||||
|
var _table = Orm.CodeFirst.GetTableByEntity(EntityType);
|
||||||
|
if (_table.Primarys.Any() == false) throw new Exception(DbContextStrings.Incomparable_EntityHasNo_PrimaryKey(Orm.GetEntityString(EntityType, newdata)));
|
||||||
|
var key = Orm.GetEntityKeyString(EntityType, newdata, false);
|
||||||
|
if (string.IsNullOrEmpty(key)) throw new Exception(DbContextStrings.Incomparable_PrimaryKey_NotSet(Orm.GetEntityString(EntityType, newdata)));
|
||||||
|
if (_states.TryGetValue(key, out var oldState) == false || oldState == null) throw new Exception($"不可对比,数据未被跟踪:{Orm.GetEntityString(EntityType, newdata)}");
|
||||||
|
AggregateRootTrackingChangeInfo tracking = new AggregateRootTrackingChangeInfo();
|
||||||
|
AggregateRootUtils.CompareEntityValue(_boundaryName, Orm, EntityType, oldState, newdata, null, tracking);
|
||||||
|
return new Dictionary<string, object[]>
|
||||||
|
{
|
||||||
|
["Insert"] = tracking.InsertLog.Select(a => new object[] { a.Item1, a.Item2 }).ToArray(),
|
||||||
|
["Delete"] = tracking.DeleteLog.Select(a => new object[] { a.Item1, a.Item2 }).ToArray(),
|
||||||
|
["Update"] = tracking.UpdateLog.Select(a => new object[] { a.Item1, a.Item2, a.Item3, a.Item4 }).ToArray(),
|
||||||
|
};
|
||||||
|
}
|
||||||
public void FlushState()
|
public void FlushState()
|
||||||
{
|
{
|
||||||
|
DisposeChildRepositorys();
|
||||||
_repository.FlushState();
|
_repository.FlushState();
|
||||||
_states.Clear();
|
_states.Clear();
|
||||||
}
|
}
|
||||||
@ -117,7 +151,7 @@ namespace FreeSql
|
|||||||
if (data == null) throw new ArgumentNullException(nameof(data));
|
if (data == null) throw new ArgumentNullException(nameof(data));
|
||||||
var key = Orm.GetEntityKeyString(EntityType, data, false);
|
var key = Orm.GetEntityKeyString(EntityType, data, false);
|
||||||
var state = new EntityState((TEntity)EntityType.CreateInstanceGetDefaultValue(), key);
|
var state = new EntityState((TEntity)EntityType.CreateInstanceGetDefaultValue(), key);
|
||||||
AggregateRootUtils.MapEntityValue(Orm, EntityType, data, state.Value);
|
AggregateRootUtils.MapEntityValue(_boundaryName, Orm, EntityType, data, state.Value);
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
bool? ExistsInStates(object data)
|
bool? ExistsInStates(object data)
|
||||||
@ -139,9 +173,9 @@ namespace FreeSql
|
|||||||
/// 创建查询对象(纯净)<para></para>
|
/// 创建查询对象(纯净)<para></para>
|
||||||
/// _<para></para>
|
/// _<para></para>
|
||||||
/// 聚合根内关系较复杂时,获取 Include/IncludeMany 字符串代码,方便二次开发<para></para>
|
/// 聚合根内关系较复杂时,获取 Include/IncludeMany 字符串代码,方便二次开发<para></para>
|
||||||
/// string code = AggregateRootUtils.GetAutoIncludeQueryStaicCode(fsql, typeof(Order))
|
/// string code = AggregateRootUtils.GetAutoIncludeQueryStaicCode(null, fsql, typeof(Order))
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected ISelect<TEntity> SelectDiy => _repository.Select;
|
protected ISelect<TEntity> SelectDiy => _repository.Select.TrackToList(SelectAggregateRootTracking);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建查询对象(递归包含 Include/IncludeMany 边界之内的导航属性)
|
/// 创建查询对象(递归包含 Include/IncludeMany 边界之内的导航属性)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -151,7 +185,7 @@ namespace FreeSql
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
var query = _repository.Select.TrackToList(SelectAggregateRootTracking);
|
var query = _repository.Select.TrackToList(SelectAggregateRootTracking);
|
||||||
query = AggregateRootUtils.GetAutoIncludeQuery(query);
|
query = AggregateRootUtils.GetAutoIncludeQuery(_boundaryName, query);
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -214,7 +248,8 @@ namespace FreeSql
|
|||||||
// currentQuery.IncludeByPropertyName(navigateExpression);
|
// currentQuery.IncludeByPropertyName(navigateExpression);
|
||||||
// break;
|
// break;
|
||||||
// case TableRefType.PgArrayToMany:
|
// case TableRefType.PgArrayToMany:
|
||||||
// case TableRefType.ManyToOne: //不属于聚合根
|
// break;
|
||||||
|
// case TableRefType.ManyToOne:
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
@ -25,7 +25,7 @@ namespace FreeSql
|
|||||||
var repos = new Dictionary<Type, object>();
|
var repos = new Dictionary<Type, object>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var ret = await InsertWithinBoundaryStaticAsync(_repository, GetChildRepository, entitys, out var affrows, cancellationToken);
|
var ret = await InsertWithinBoundaryStaticAsync(_boundaryName, _repository, GetChildRepository, entitys, out var affrows, cancellationToken);
|
||||||
Attach(ret);
|
Attach(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -35,112 +35,9 @@ namespace FreeSql
|
|||||||
_repository.FlushState();
|
_repository.FlushState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Task<List<T1>> InsertWithinBoundaryStaticAsync<T1>(IBaseRepository<T1> rootRepository, Func<Type, IBaseRepository<object>> getChildRepository, IEnumerable<T1> rootEntitys, out int affrows, CancellationToken cancellationToken) where T1 : class
|
Task<List<T1>> InsertWithinBoundaryStaticAsync<T1>(string boundaryName, IBaseRepository<T1> rootRepository, Func<Type, IBaseRepository<object>> getChildRepository, IEnumerable<T1> rootEntitys, out int affrows, CancellationToken cancellationToken) where T1 : class
|
||||||
{
|
{
|
||||||
Dictionary<Type, Dictionary<string, bool>> ignores = new Dictionary<Type, Dictionary<string, bool>>();
|
return Task.FromResult(InsertWithinBoundaryStatic(boundaryName, rootRepository, getChildRepository, rootEntitys, out affrows));
|
||||||
Dictionary<Type, IBaseRepository<object>> repos = new Dictionary<Type, IBaseRepository<object>>();
|
|
||||||
var localAffrows = 0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return LocalInsertAsync(rootRepository, rootEntitys);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
affrows = localAffrows;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LocalCanInsert(Type entityType, object entity, bool isadd)
|
|
||||||
{
|
|
||||||
var stateKey = rootRepository.Orm.GetEntityKeyString(entityType, entity, false);
|
|
||||||
if (stateKey == null) return true;
|
|
||||||
if (ignores.TryGetValue(entityType, out var stateKeys) == false)
|
|
||||||
{
|
|
||||||
if (isadd)
|
|
||||||
{
|
|
||||||
ignores.Add(entityType, stateKeys = new Dictionary<string, bool>());
|
|
||||||
stateKeys.Add(stateKey, true);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (stateKeys.ContainsKey(stateKey) == false)
|
|
||||||
{
|
|
||||||
if (isadd) stateKeys.Add(stateKey, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
async Task<List<T2>> LocalInsertAsync<T2>(IBaseRepository<T2> repository, IEnumerable<T2> entitys) where T2 : 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 = await repository.InsertAsync(entitys, cancellationToken);
|
|
||||||
localAffrows += ret.Count;
|
|
||||||
foreach (var entity in entitys) LocalCanInsert(repository.EntityType, entity, true);
|
|
||||||
|
|
||||||
foreach (var tr in table.GetAllTableRef().OrderBy(a => a.Value.RefType).ThenBy(a => a.Key))
|
|
||||||
{
|
|
||||||
var tbref = tr.Value;
|
|
||||||
if (tbref.Exception != null) continue;
|
|
||||||
if (table.Properties.TryGetValue(tr.Key, out var prop) == false) continue;
|
|
||||||
switch (tbref.RefType)
|
|
||||||
{
|
|
||||||
case TableRefType.OneToOne:
|
|
||||||
var otoList = ret.Select(entity =>
|
|
||||||
{
|
|
||||||
var otoItem = table.GetPropertyValue(entity, prop.Name);
|
|
||||||
if (LocalCanInsert(tbref.RefEntityType, otoItem, false) == false) return null;
|
|
||||||
AggregateRootUtils.SetNavigateRelationshipValue(repository.Orm, tbref, table.Type, entity, otoItem);
|
|
||||||
return otoItem;
|
|
||||||
}).Where(entity => entity != null).ToArray();
|
|
||||||
if (otoList.Any())
|
|
||||||
{
|
|
||||||
var repo = getChildRepository(tbref.RefEntityType);
|
|
||||||
await LocalInsertAsync(repo, otoList);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TableRefType.OneToMany:
|
|
||||||
var otmList = ret.Select(entity =>
|
|
||||||
{
|
|
||||||
var otmEach = table.GetPropertyValue(entity, prop.Name) as IEnumerable;
|
|
||||||
if (otmEach == null) return null;
|
|
||||||
var otmItems = new List<object>();
|
|
||||||
foreach (var otmItem in otmEach)
|
|
||||||
{
|
|
||||||
if (LocalCanInsert(tbref.RefEntityType, otmItem, false) == false) continue;
|
|
||||||
otmItems.Add(otmItem);
|
|
||||||
}
|
|
||||||
AggregateRootUtils.SetNavigateRelationshipValue(repository.Orm, tbref, table.Type, entity, otmItems);
|
|
||||||
return otmItems;
|
|
||||||
}).Where(entity => entity != null).SelectMany(entity => entity).ToArray();
|
|
||||||
if (otmList.Any())
|
|
||||||
{
|
|
||||||
var repo = getChildRepository(tbref.RefEntityType);
|
|
||||||
await LocalInsertAsync(repo, otmList);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TableRefType.ManyToMany:
|
|
||||||
var mtmMidList = new List<object>();
|
|
||||||
ret.ForEach(entity =>
|
|
||||||
{
|
|
||||||
var mids = AggregateRootUtils.GetManyToManyObjects(repository.Orm, table, tbref, entity, prop);
|
|
||||||
if (mids != null) mtmMidList.AddRange(mids);
|
|
||||||
});
|
|
||||||
if (mtmMidList.Any())
|
|
||||||
{
|
|
||||||
var repo = getChildRepository(tbref.RefMiddleEntityType);
|
|
||||||
await LocalInsertAsync(repo, mtmMidList);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TableRefType.PgArrayToMany:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -178,7 +75,7 @@ namespace FreeSql
|
|||||||
{
|
{
|
||||||
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, tracking);
|
AggregateRootUtils.CompareEntityValue(_boundaryName, Orm, EntityType, state.Value, entity, null, tracking);
|
||||||
}
|
}
|
||||||
foreach (var entity in entitys)
|
foreach (var entity in entitys)
|
||||||
Attach(entity);
|
Attach(entity);
|
||||||
@ -202,7 +99,7 @@ namespace FreeSql
|
|||||||
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, tracking);
|
AggregateRootUtils.CompareEntityValue(_boundaryName, Orm, EntityType, entity, null, null, tracking);
|
||||||
_states.Remove(stateKey);
|
_states.Remove(stateKey);
|
||||||
}
|
}
|
||||||
var affrows = 0;
|
var affrows = 0;
|
||||||
@ -227,7 +124,7 @@ namespace FreeSql
|
|||||||
var tracking = new AggregateRootTrackingChangeInfo();
|
var tracking = new AggregateRootTrackingChangeInfo();
|
||||||
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, tracking);
|
AggregateRootUtils.CompareEntityValue(_boundaryName, Orm, EntityType, state.Value, entity, propertyName, tracking);
|
||||||
Attach(entity); //应该只存储 propertyName 内容
|
Attach(entity); //应该只存储 propertyName 内容
|
||||||
await SaveTrackingChangeAsync(tracking, cancellationToken);
|
await SaveTrackingChangeAsync(tracking, cancellationToken);
|
||||||
}
|
}
|
||||||
@ -241,7 +138,7 @@ namespace FreeSql
|
|||||||
foreach (var il in insertLogDict)
|
foreach (var il in insertLogDict)
|
||||||
{
|
{
|
||||||
var repo = GetChildRepository(il.Key);
|
var repo = GetChildRepository(il.Key);
|
||||||
await InsertWithinBoundaryStaticAsync(repo, GetChildRepository, il.Value, out var affrowsOut, cancellationToken);
|
await InsertWithinBoundaryStaticAsync(_boundaryName, repo, GetChildRepository, il.Value, out var affrowsOut, cancellationToken);
|
||||||
affrows += affrowsOut;
|
affrows += affrowsOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ namespace FreeSql
|
|||||||
|
|
||||||
_statesEditing.AddOrUpdate(key, k => CreateEntityState(item), (k, ov) =>
|
_statesEditing.AddOrUpdate(key, k => CreateEntityState(item), (k, ov) =>
|
||||||
{
|
{
|
||||||
AggregateRootUtils.MapEntityValue(Orm, EntityType, item, ov.Value);
|
AggregateRootUtils.MapEntityValue(_boundaryName, Orm, EntityType, item, ov.Value);
|
||||||
ov.Time = DateTime.Now;
|
ov.Time = DateTime.Now;
|
||||||
return ov;
|
return ov;
|
||||||
});
|
});
|
||||||
@ -57,10 +57,10 @@ namespace FreeSql
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_states[key] = state;
|
_states[key] = state;
|
||||||
AggregateRootUtils.CompareEntityValue(Orm, EntityType, state.Value, item, null, tracking);
|
AggregateRootUtils.CompareEntityValue(_boundaryName, 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(_boundaryName, Orm, EntityType, item, null, null, tracking);
|
||||||
|
|
||||||
return SaveTrackingChange(tracking);
|
return SaveTrackingChange(tracking);
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ namespace FreeSql
|
|||||||
var repos = new Dictionary<Type, object>();
|
var repos = new Dictionary<Type, object>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var ret = InsertWithinBoundaryStatic(_repository, GetChildRepository, entitys, out var affrows);
|
var ret = InsertWithinBoundaryStatic(_boundaryName, _repository, GetChildRepository, entitys, out var affrows);
|
||||||
Attach(ret);
|
Attach(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -89,13 +89,13 @@ namespace FreeSql
|
|||||||
_repository.FlushState();
|
_repository.FlushState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static List<T1> InsertWithinBoundaryStatic<T1>(IBaseRepository<T1> rootRepository, Func<Type, IBaseRepository<object>> getChildRepository, IEnumerable<T1> rootEntitys, out int affrows) where T1 : class {
|
static List<T1> InsertWithinBoundaryStatic<T1>(string boundaryName, IBaseRepository<T1> rootRepository, Func<Type, IBaseRepository<object>> getChildRepository, IEnumerable<T1> rootEntitys, out int affrows) where T1 : class {
|
||||||
Dictionary<Type, Dictionary<string, bool>> ignores = new Dictionary<Type, Dictionary<string, bool>>();
|
Dictionary<Type, Dictionary<string, bool>> ignores = new Dictionary<Type, Dictionary<string, bool>>();
|
||||||
Dictionary<Type, IBaseRepository<object>> repos = new Dictionary<Type, IBaseRepository<object>>();
|
Dictionary<Type, IBaseRepository<object>> repos = new Dictionary<Type, IBaseRepository<object>>();
|
||||||
var localAffrows = 0;
|
var localAffrows = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return LocalInsert(rootRepository, rootEntitys);
|
return LocalInsert(rootRepository, rootEntitys, true);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -122,7 +122,7 @@ namespace FreeSql
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
List<T2> LocalInsert<T2>(IBaseRepository<T2> repository, IEnumerable<T2> entitys) where T2 : class
|
List<T2> LocalInsert<T2>(IBaseRepository<T2> repository, IEnumerable<T2> entitys, bool cascade) where T2 : class
|
||||||
{
|
{
|
||||||
var table = repository.Orm.CodeFirst.GetTableByEntity(repository.EntityType);
|
var table = repository.Orm.CodeFirst.GetTableByEntity(repository.EntityType);
|
||||||
if (table.Primarys.Any(col => col.Attribute.IsIdentity))
|
if (table.Primarys.Any(col => col.Attribute.IsIdentity))
|
||||||
@ -130,15 +130,76 @@ namespace FreeSql
|
|||||||
foreach (var entity in entitys)
|
foreach (var entity in entitys)
|
||||||
repository.Orm.ClearEntityPrimaryValueWithIdentity(repository.EntityType, entity);
|
repository.Orm.ClearEntityPrimaryValueWithIdentity(repository.EntityType, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cascade)
|
||||||
|
{
|
||||||
|
foreach (var tr in table.GetAllTableRef().OrderBy(a => a.Value.RefType).ThenBy(a => a.Key))
|
||||||
|
{
|
||||||
|
var tbref = tr.Value;
|
||||||
|
if (tbref.Exception != null) continue;
|
||||||
|
if (table.Properties.TryGetValue(tr.Key, out var prop) == false) continue;
|
||||||
|
var boundaryAttr = AggregateRootUtils.GetPropertyBoundaryAttribute(prop, boundaryName);
|
||||||
|
if (boundaryAttr?.Break == true) continue;
|
||||||
|
switch (tbref.RefType)
|
||||||
|
{
|
||||||
|
case TableRefType.ManyToMany:
|
||||||
|
if (boundaryAttr?.Break == false)
|
||||||
|
{
|
||||||
|
var mtmList = entitys.Select(entity =>
|
||||||
|
{
|
||||||
|
var mtmEach = table.GetPropertyValue(entity, prop.Name) as IEnumerable;
|
||||||
|
if (mtmEach == null) return null;
|
||||||
|
var mtmItems = new List<object>();
|
||||||
|
foreach (var mtmItem in mtmEach)
|
||||||
|
{
|
||||||
|
if (LocalCanInsert(tbref.RefEntityType, mtmItem, false) == false) continue;
|
||||||
|
mtmItems.Add(mtmItem);
|
||||||
|
}
|
||||||
|
return mtmItems;
|
||||||
|
}).Where(entity => entity != null).SelectMany(entity => entity).ToArray();
|
||||||
|
if (mtmList.Any())
|
||||||
|
{
|
||||||
|
var repo = getChildRepository(tbref.RefEntityType);
|
||||||
|
LocalInsert(repo, mtmList, boundaryAttr?.BreakThen == false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TableRefType.PgArrayToMany:
|
||||||
|
break;
|
||||||
|
case TableRefType.ManyToOne:
|
||||||
|
if (boundaryAttr?.Break == false)
|
||||||
|
{
|
||||||
|
var mtoList = entitys.Select(entity =>
|
||||||
|
{
|
||||||
|
var mtoItem = table.GetPropertyValue(entity, prop.Name);
|
||||||
|
if (LocalCanInsert(tbref.RefEntityType, mtoItem, false) == false) return null;
|
||||||
|
return NativeTuple.Create(entity, mtoItem);
|
||||||
|
}).Where(entity => entity != null).ToArray();
|
||||||
|
if (mtoList.Any())
|
||||||
|
{
|
||||||
|
var repo = getChildRepository(tbref.RefEntityType);
|
||||||
|
LocalInsert(repo, mtoList.Select(a => a.Item2), boundaryAttr?.BreakThen != true);
|
||||||
|
foreach (var mtoItem in mtoList)
|
||||||
|
AggregateRootUtils.SetNavigateRelationshipValue(repository.Orm, tbref, table.Type, mtoItem.Item1, mtoItem.Item2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var ret = repository.Insert(entitys);
|
var ret = repository.Insert(entitys);
|
||||||
localAffrows += ret.Count;
|
localAffrows += ret.Count;
|
||||||
foreach (var entity in entitys) LocalCanInsert(repository.EntityType, entity, true);
|
foreach (var entity in entitys) LocalCanInsert(repository.EntityType, entity, true);
|
||||||
|
if (cascade == false) return ret;
|
||||||
|
|
||||||
foreach (var tr in table.GetAllTableRef().OrderBy(a => a.Value.RefType).ThenBy(a => a.Key))
|
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;
|
||||||
if (table.Properties.TryGetValue(tr.Key, out var prop) == false) continue;
|
if (table.Properties.TryGetValue(tr.Key, out var prop) == false) continue;
|
||||||
|
var boundaryAttr = AggregateRootUtils.GetPropertyBoundaryAttribute(prop, boundaryName);
|
||||||
|
if (boundaryAttr?.Break == true) continue;
|
||||||
switch (tbref.RefType)
|
switch (tbref.RefType)
|
||||||
{
|
{
|
||||||
case TableRefType.OneToOne:
|
case TableRefType.OneToOne:
|
||||||
@ -152,7 +213,7 @@ namespace FreeSql
|
|||||||
if (otoList.Any())
|
if (otoList.Any())
|
||||||
{
|
{
|
||||||
var repo = getChildRepository(tbref.RefEntityType);
|
var repo = getChildRepository(tbref.RefEntityType);
|
||||||
LocalInsert(repo, otoList);
|
LocalInsert(repo, otoList, boundaryAttr?.BreakThen != true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TableRefType.OneToMany:
|
case TableRefType.OneToMany:
|
||||||
@ -172,7 +233,7 @@ namespace FreeSql
|
|||||||
if (otmList.Any())
|
if (otmList.Any())
|
||||||
{
|
{
|
||||||
var repo = getChildRepository(tbref.RefEntityType);
|
var repo = getChildRepository(tbref.RefEntityType);
|
||||||
LocalInsert(repo, otmList);
|
LocalInsert(repo, otmList, boundaryAttr?.BreakThen != true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TableRefType.ManyToMany:
|
case TableRefType.ManyToMany:
|
||||||
@ -185,10 +246,11 @@ namespace FreeSql
|
|||||||
if (mtmMidList.Any())
|
if (mtmMidList.Any())
|
||||||
{
|
{
|
||||||
var repo = getChildRepository(tbref.RefMiddleEntityType);
|
var repo = getChildRepository(tbref.RefMiddleEntityType);
|
||||||
LocalInsert(repo, mtmMidList);
|
LocalInsert(repo, mtmMidList, false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TableRefType.PgArrayToMany:
|
case TableRefType.PgArrayToMany:
|
||||||
|
case TableRefType.ManyToOne: //在插入前处理
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,7 +293,7 @@ namespace FreeSql
|
|||||||
{
|
{
|
||||||
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, tracking);
|
AggregateRootUtils.CompareEntityValue(_boundaryName, Orm, EntityType, state.Value, entity, null, tracking);
|
||||||
}
|
}
|
||||||
foreach (var entity in entitys)
|
foreach (var entity in entitys)
|
||||||
Attach(entity);
|
Attach(entity);
|
||||||
@ -254,7 +316,7 @@ namespace FreeSql
|
|||||||
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, tracking);
|
AggregateRootUtils.CompareEntityValue(_boundaryName, Orm, EntityType, entity, null, null, tracking);
|
||||||
_states.Remove(stateKey);
|
_states.Remove(stateKey);
|
||||||
}
|
}
|
||||||
var affrows = 0;
|
var affrows = 0;
|
||||||
@ -279,7 +341,7 @@ namespace FreeSql
|
|||||||
var tracking = new AggregateRootTrackingChangeInfo();
|
var tracking = new AggregateRootTrackingChangeInfo();
|
||||||
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, tracking);
|
AggregateRootUtils.CompareEntityValue(_boundaryName, Orm, EntityType, state.Value, entity, propertyName, tracking);
|
||||||
Attach(entity); //应该只存储 propertyName 内容
|
Attach(entity); //应该只存储 propertyName 内容
|
||||||
SaveTrackingChange(tracking);
|
SaveTrackingChange(tracking);
|
||||||
}
|
}
|
||||||
@ -293,7 +355,7 @@ namespace FreeSql
|
|||||||
foreach (var il in insertLogDict)
|
foreach (var il in insertLogDict)
|
||||||
{
|
{
|
||||||
var repo = GetChildRepository(il.Key);
|
var repo = GetChildRepository(il.Key);
|
||||||
InsertWithinBoundaryStatic(repo, GetChildRepository, il.Value, out var affrowsOut);
|
InsertWithinBoundaryStatic(_boundaryName, repo, GetChildRepository, il.Value, out var affrowsOut);
|
||||||
affrows += affrowsOut;
|
affrows += affrowsOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using FreeSql;
|
using FreeSql;
|
||||||
|
using FreeSql.DataAnnotations;
|
||||||
using FreeSql.Extensions.EntityUtil;
|
using FreeSql.Extensions.EntityUtil;
|
||||||
using FreeSql.Internal;
|
using FreeSql.Internal;
|
||||||
using FreeSql.Internal.CommonProvider;
|
using FreeSql.Internal.CommonProvider;
|
||||||
@ -15,15 +16,23 @@ using System.Text;
|
|||||||
|
|
||||||
namespace FreeSql
|
namespace FreeSql
|
||||||
{
|
{
|
||||||
public static class AggregateRootUtils
|
public class AggregateRootUtils
|
||||||
{
|
{
|
||||||
public static void CompareEntityValue(IFreeSql fsql, Type rootEntityType, object rootEntityBefore, object rootEntityAfter, string rootNavigatePropertyName, AggregateRootTrackingChangeInfo tracking)
|
public static AggregateRootBoundaryAttribute GetPropertyBoundaryAttribute(PropertyInfo prop, string boundaryName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(boundaryName)) return null;
|
||||||
|
var attrs = prop.GetCustomAttributes(typeof(AggregateRootBoundaryAttribute), false);
|
||||||
|
if (attrs == null || attrs.Any() == false) return null;
|
||||||
|
return attrs.Select(a => a as AggregateRootBoundaryAttribute).Where(a => a.Name == boundaryName).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CompareEntityValue(string boundaryName, IFreeSql fsql, Type rootEntityType, object rootEntityBefore, object rootEntityAfter, string rootNavigatePropertyName, AggregateRootTrackingChangeInfo tracking)
|
||||||
{
|
{
|
||||||
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, true);
|
||||||
ignores.Clear();
|
ignores.Clear();
|
||||||
|
|
||||||
void LocalCompareEntityValue(Type entityType, object entityBefore, object entityAfter, string navigatePropertyName)
|
void LocalCompareEntityValue(Type entityType, object entityBefore, object entityAfter, string navigatePropertyName, bool cascade)
|
||||||
{
|
{
|
||||||
if (entityType == null) entityType = entityBefore?.GetType() ?? entityAfter?.GetType();
|
if (entityType == null) entityType = entityBefore?.GetType() ?? entityAfter?.GetType();
|
||||||
|
|
||||||
@ -53,7 +62,7 @@ namespace FreeSql
|
|||||||
if (entityBefore != null && entityAfter == null)
|
if (entityBefore != null && entityAfter == null)
|
||||||
{
|
{
|
||||||
tracking.DeleteLog.Add(NativeTuple.Create(entityType, new[] { entityBefore }));
|
tracking.DeleteLog.Add(NativeTuple.Create(entityType, new[] { entityBefore }));
|
||||||
NavigateReader(fsql, entityType, entityBefore, (path, tr, ct, stackvs) =>
|
NavigateReader(boundaryName, fsql, entityType, entityBefore, (path, tr, ct, stackvs) =>
|
||||||
{
|
{
|
||||||
var dellist = stackvs.Last() as object[] ?? new[] { stackvs.Last() };
|
var dellist = stackvs.Last() as object[] ?? new[] { stackvs.Last() };
|
||||||
tracking.DeleteLog.Add(NativeTuple.Create(ct, dellist));
|
tracking.DeleteLog.Add(NativeTuple.Create(ct, dellist));
|
||||||
@ -74,14 +83,16 @@ namespace FreeSql
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (changes.Any())
|
if (changes.Any()) tracking.UpdateLog.Add(NativeTuple.Create(entityType, entityBefore, entityAfter, changes));
|
||||||
tracking.UpdateLog.Add(NativeTuple.Create(entityType, entityBefore, entityAfter, changes));
|
if (cascade == false) return;
|
||||||
|
|
||||||
foreach (var tr in table.GetAllTableRef().OrderBy(a => a.Value.RefType).ThenBy(a => a.Key))
|
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;
|
||||||
if (table.Properties.TryGetValue(tr.Key, out var prop) == false) continue;
|
if (table.Properties.TryGetValue(tr.Key, out var prop) == false) continue;
|
||||||
|
var boundaryAttr = GetPropertyBoundaryAttribute(prop, boundaryName);
|
||||||
|
if (boundaryAttr?.Break == true) continue;
|
||||||
if (navigatePropertyName != null && prop.Name != navigatePropertyName) continue;
|
if (navigatePropertyName != null && prop.Name != navigatePropertyName) continue;
|
||||||
var propvalBefore = table.GetPropertyValue(entityBefore, prop.Name);
|
var propvalBefore = table.GetPropertyValue(entityBefore, prop.Name);
|
||||||
var propvalAfter = table.GetPropertyValue(entityAfter, prop.Name);
|
var propvalAfter = table.GetPropertyValue(entityAfter, prop.Name);
|
||||||
@ -90,27 +101,35 @@ namespace FreeSql
|
|||||||
case TableRefType.OneToOne:
|
case TableRefType.OneToOne:
|
||||||
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityBefore, propvalBefore);
|
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityBefore, propvalBefore);
|
||||||
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityAfter, propvalAfter);
|
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityAfter, propvalAfter);
|
||||||
LocalCompareEntityValue(tbref.RefEntityType, propvalBefore, propvalAfter, null);
|
LocalCompareEntityValue(tbref.RefEntityType, propvalBefore, propvalAfter, null, boundaryAttr?.BreakThen != true);
|
||||||
break;
|
break;
|
||||||
case TableRefType.OneToMany:
|
case TableRefType.OneToMany:
|
||||||
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityBefore, propvalBefore);
|
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityBefore, propvalBefore);
|
||||||
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityAfter, propvalAfter);
|
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityAfter, propvalAfter);
|
||||||
LocalCompareEntityValueCollection(tbref, propvalBefore as IEnumerable, propvalAfter as IEnumerable);
|
LocalCompareEntityValueCollection(tbref.RefEntityType, propvalBefore as IEnumerable, propvalAfter as IEnumerable, boundaryAttr?.BreakThen != true);
|
||||||
break;
|
break;
|
||||||
case TableRefType.ManyToMany:
|
case TableRefType.ManyToMany:
|
||||||
var middleValuesBefore = GetManyToManyObjects(fsql, table, tbref, entityBefore, prop);
|
var middleValuesBefore = GetManyToManyObjects(fsql, table, tbref, entityBefore, prop);
|
||||||
var middleValuesAfter = GetManyToManyObjects(fsql, table, tbref, entityAfter, prop);
|
var middleValuesAfter = GetManyToManyObjects(fsql, table, tbref, entityAfter, prop);
|
||||||
LocalCompareEntityValueCollection(tbref, middleValuesBefore as IEnumerable, middleValuesAfter as IEnumerable);
|
LocalCompareEntityValueCollection(tbref.RefMiddleEntityType, middleValuesBefore as IEnumerable, middleValuesAfter as IEnumerable, false);
|
||||||
|
if (boundaryAttr?.BreakThen == false)
|
||||||
|
LocalCompareEntityValueCollection(tbref.RefEntityType, propvalBefore as IEnumerable, propvalAfter as IEnumerable, boundaryAttr?.BreakThen == false);
|
||||||
break;
|
break;
|
||||||
case TableRefType.PgArrayToMany:
|
case TableRefType.PgArrayToMany:
|
||||||
case TableRefType.ManyToOne: //不属于聚合根
|
break;
|
||||||
|
case TableRefType.ManyToOne:
|
||||||
|
if (boundaryAttr?.BreakThen == false)
|
||||||
|
{
|
||||||
|
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityBefore, propvalBefore);
|
||||||
|
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityAfter, propvalAfter);
|
||||||
|
LocalCompareEntityValue(tbref.RefEntityType, propvalBefore, propvalAfter, null, boundaryAttr?.BreakThen == false);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void LocalCompareEntityValueCollection(TableRef tbref, IEnumerable collectionBefore, IEnumerable collectionAfter)
|
void LocalCompareEntityValueCollection(Type elementType, IEnumerable collectionBefore, IEnumerable collectionAfter, bool cascade)
|
||||||
{
|
{
|
||||||
var elementType = tbref.RefType == TableRefType.ManyToMany ? tbref.RefMiddleEntityType : tbref.RefEntityType;
|
|
||||||
if (collectionBefore == null && collectionAfter == null) return;
|
if (collectionBefore == null && collectionAfter == null) return;
|
||||||
if (collectionBefore == null && collectionAfter != null)
|
if (collectionBefore == null && collectionAfter != null)
|
||||||
{
|
{
|
||||||
@ -154,7 +173,7 @@ namespace FreeSql
|
|||||||
{
|
{
|
||||||
var value = dictBefore[key];
|
var value = dictBefore[key];
|
||||||
tracking.DeleteLog.Add(NativeTuple.Create(elementType, new[] { value }));
|
tracking.DeleteLog.Add(NativeTuple.Create(elementType, new[] { value }));
|
||||||
NavigateReader(fsql, elementType, value, (path, tr, ct, stackvs) =>
|
NavigateReader(boundaryName, fsql, elementType, value, (path, tr, ct, stackvs) =>
|
||||||
{
|
{
|
||||||
var dellist = stackvs.Last() as object[] ?? new[] { stackvs.Last() };
|
var dellist = stackvs.Last() as object[] ?? new[] { stackvs.Last() };
|
||||||
tracking.DeleteLog.Add(NativeTuple.Create(ct, dellist));
|
tracking.DeleteLog.Add(NativeTuple.Create(ct, dellist));
|
||||||
@ -171,7 +190,7 @@ namespace FreeSql
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var key in dictBefore.Keys)
|
foreach (var key in dictBefore.Keys)
|
||||||
LocalCompareEntityValue(elementType, dictBefore[key], dictAfter[key], null);
|
LocalCompareEntityValue(elementType, dictBefore[key], dictAfter[key], null, cascade);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,7 +278,7 @@ namespace FreeSql
|
|||||||
return object.Equals(propvalBefore, propvalAfter);
|
return object.Equals(propvalBefore, propvalAfter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void NavigateReader(IFreeSql fsql, Type rootType, object rootEntity, Action<string, TableRef, Type, List<object>> callback)
|
public static void NavigateReader(string boundaryName, IFreeSql fsql, Type rootType, object rootEntity, Action<string, TableRef, Type, List<object>> callback)
|
||||||
{
|
{
|
||||||
Dictionary<Type, Dictionary<string, bool>> ignores = new Dictionary<Type, Dictionary<string, bool>>();
|
Dictionary<Type, Dictionary<string, bool>> ignores = new Dictionary<Type, Dictionary<string, bool>>();
|
||||||
var statckPath = new Stack<string>();
|
var statckPath = new Stack<string>();
|
||||||
@ -286,6 +305,8 @@ namespace FreeSql
|
|||||||
var tbref = tr.Value;
|
var tbref = tr.Value;
|
||||||
if (tbref.Exception != null) continue;
|
if (tbref.Exception != null) continue;
|
||||||
if (table.Properties.TryGetValue(tr.Key, out var prop) == false) continue;
|
if (table.Properties.TryGetValue(tr.Key, out var prop) == false) continue;
|
||||||
|
var boundaryAttr = GetPropertyBoundaryAttribute(prop, boundaryName);
|
||||||
|
if (boundaryAttr?.Break == true) continue;
|
||||||
switch (tbref.RefType)
|
switch (tbref.RefType)
|
||||||
{
|
{
|
||||||
case TableRefType.OneToOne:
|
case TableRefType.OneToOne:
|
||||||
@ -295,49 +316,70 @@ namespace FreeSql
|
|||||||
stackValues.Add(propval);
|
stackValues.Add(propval);
|
||||||
SetNavigateRelationshipValue(fsql, tbref, table.Type, entity, propval);
|
SetNavigateRelationshipValue(fsql, tbref, table.Type, entity, propval);
|
||||||
callback?.Invoke(string.Join(".", statckPath), tbref, tbref.RefEntityType, stackValues);
|
callback?.Invoke(string.Join(".", statckPath), tbref, tbref.RefEntityType, stackValues);
|
||||||
LocalNavigateReader(tbref.RefEntityType, propval);
|
if (boundaryAttr?.BreakThen != true)
|
||||||
|
LocalNavigateReader(tbref.RefEntityType, propval);
|
||||||
stackValues.RemoveAt(stackValues.Count - 1);
|
stackValues.RemoveAt(stackValues.Count - 1);
|
||||||
statckPath.Pop();
|
statckPath.Pop();
|
||||||
break;
|
break;
|
||||||
case TableRefType.OneToMany:
|
case TableRefType.OneToMany:
|
||||||
var propvalOtm = table.GetPropertyValue(entity, prop.Name);
|
var propvalOtm = table.GetPropertyValue(entity, prop.Name) as IEnumerable;
|
||||||
if (propvalOtm == null) continue;
|
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)
|
||||||
propvalOtmList.Add(val);
|
propvalOtmList.Add(val);
|
||||||
statckPath.Push($"{prop.Name}[]");
|
statckPath.Push($"{prop.Name}[]");
|
||||||
stackValues.Add(propvalOtmList.ToArray());
|
stackValues.Add(propvalOtmList.ToArray());
|
||||||
callback?.Invoke(string.Join(".", statckPath), tbref, tbref.RefEntityType, stackValues);
|
callback?.Invoke(string.Join(".", statckPath), tbref, tbref.RefEntityType, stackValues);
|
||||||
foreach (var val in propvalOtm as IEnumerable)
|
if (boundaryAttr?.BreakThen != true)
|
||||||
LocalNavigateReader(tbref.RefEntityType, val);
|
foreach (var val in propvalOtm)
|
||||||
|
LocalNavigateReader(tbref.RefEntityType, val);
|
||||||
stackValues.RemoveAt(stackValues.Count - 1);
|
stackValues.RemoveAt(stackValues.Count - 1);
|
||||||
statckPath.Pop();
|
statckPath.Pop();
|
||||||
break;
|
break;
|
||||||
case TableRefType.ManyToMany:
|
case TableRefType.ManyToMany:
|
||||||
|
var propvalMtm = table.GetPropertyValue(entity, prop.Name) as IEnumerable;
|
||||||
|
if (propvalMtm == null) continue;
|
||||||
var middleValues = GetManyToManyObjects(fsql, table, tbref, entity, prop).ToArray();
|
var middleValues = GetManyToManyObjects(fsql, table, tbref, entity, prop).ToArray();
|
||||||
if (middleValues == null) continue;
|
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.RefMiddleEntityType, stackValues);
|
callback?.Invoke(string.Join(".", statckPath), tbref, tbref.RefMiddleEntityType, stackValues);
|
||||||
|
if (boundaryAttr?.BreakThen == false)
|
||||||
|
foreach (var val in propvalMtm)
|
||||||
|
LocalNavigateReader(tbref.RefEntityType, val);
|
||||||
stackValues.RemoveAt(stackValues.Count - 1);
|
stackValues.RemoveAt(stackValues.Count - 1);
|
||||||
statckPath.Pop();
|
statckPath.Pop();
|
||||||
break;
|
break;
|
||||||
case TableRefType.PgArrayToMany:
|
case TableRefType.PgArrayToMany:
|
||||||
case TableRefType.ManyToOne: //不属于聚合根
|
break;
|
||||||
|
case TableRefType.ManyToOne:
|
||||||
|
if (boundaryAttr?.Break == false)
|
||||||
|
{
|
||||||
|
var propvalMto = table.GetPropertyValue(entity, prop.Name);
|
||||||
|
if (propvalMto == null) continue;
|
||||||
|
statckPath.Push(prop.Name);
|
||||||
|
stackValues.Add(propvalMto);
|
||||||
|
SetNavigateRelationshipValue(fsql, tbref, table.Type, entity, propvalMto);
|
||||||
|
callback?.Invoke(string.Join(".", statckPath), tbref, tbref.RefEntityType, stackValues);
|
||||||
|
if (boundaryAttr?.BreakThen == false)
|
||||||
|
LocalNavigateReader(tbref.RefEntityType, propvalMto);
|
||||||
|
stackValues.RemoveAt(stackValues.Count - 1);
|
||||||
|
statckPath.Pop();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void MapEntityValue(IFreeSql fsql, Type rootEntityType, object rootEntityFrom, object rootEntityTo)
|
public static void MapEntityValue(string boundaryName, IFreeSql fsql, Type rootEntityType, object rootEntityFrom, object rootEntityTo)
|
||||||
{
|
{
|
||||||
Dictionary<Type, Dictionary<string, bool>> ignores = new Dictionary<Type, Dictionary<string, bool>>();
|
Dictionary<Type, Dictionary<string, bool>> ignores = new Dictionary<Type, Dictionary<string, bool>>();
|
||||||
LocalMapEntityValue(rootEntityType, rootEntityFrom, rootEntityTo);
|
LocalMapEntityValue(rootEntityType, rootEntityFrom, rootEntityTo, true);
|
||||||
ignores.Clear();
|
ignores.Clear();
|
||||||
|
|
||||||
void LocalMapEntityValue(Type entityType, object entityFrom, object entityTo)
|
void LocalMapEntityValue(Type entityType, object entityFrom, object entityTo, bool cascade)
|
||||||
{
|
{
|
||||||
if (entityFrom == null || entityTo == null) return;
|
if (entityFrom == null || entityTo == null) return;
|
||||||
if (entityType == null) entityType = entityFrom?.GetType() ?? entityTo?.GetType();
|
if (entityType == null) entityType = entityFrom?.GetType() ?? entityTo?.GetType();
|
||||||
@ -357,8 +399,11 @@ namespace FreeSql
|
|||||||
table.SetPropertyValue(entityTo, prop.Name, table.GetPropertyValue(entityFrom, prop.Name));
|
table.SetPropertyValue(entityTo, prop.Name, table.GetPropertyValue(entityFrom, prop.Name));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (cascade == false) continue;
|
||||||
var tbref = table.GetTableRef(prop.Name, false);
|
var tbref = table.GetTableRef(prop.Name, false);
|
||||||
if (tbref == null) continue;
|
if (tbref == null) continue;
|
||||||
|
var boundaryAttr = GetPropertyBoundaryAttribute(prop, boundaryName);
|
||||||
|
if (boundaryAttr?.Break == true) continue;
|
||||||
var propvalFrom = EntityUtilExtensions.GetEntityValueWithPropertyName(fsql, entityType, entityFrom, prop.Name);
|
var propvalFrom = EntityUtilExtensions.GetEntityValueWithPropertyName(fsql, entityType, entityFrom, prop.Name);
|
||||||
if (propvalFrom == null)
|
if (propvalFrom == null)
|
||||||
{
|
{
|
||||||
@ -370,18 +415,26 @@ namespace FreeSql
|
|||||||
case TableRefType.OneToOne:
|
case TableRefType.OneToOne:
|
||||||
var propvalTo = tbref.RefEntityType.CreateInstanceGetDefaultValue();
|
var propvalTo = tbref.RefEntityType.CreateInstanceGetDefaultValue();
|
||||||
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityFrom, propvalFrom);
|
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityFrom, propvalFrom);
|
||||||
LocalMapEntityValue(tbref.RefEntityType, propvalFrom, propvalTo);
|
LocalMapEntityValue(tbref.RefEntityType, propvalFrom, propvalTo, boundaryAttr?.BreakThen != true);
|
||||||
EntityUtilExtensions.SetEntityValueWithPropertyName(fsql, entityType, entityTo, prop.Name, propvalTo);
|
EntityUtilExtensions.SetEntityValueWithPropertyName(fsql, entityType, entityTo, prop.Name, propvalTo);
|
||||||
break;
|
break;
|
||||||
case TableRefType.OneToMany:
|
case TableRefType.OneToMany:
|
||||||
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityFrom, propvalFrom);
|
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityFrom, propvalFrom);
|
||||||
LocalMapEntityValueCollection(entityType, entityFrom, entityTo, tbref, propvalFrom as IEnumerable, prop, true);
|
LocalMapEntityValueCollection(entityType, entityFrom, entityTo, tbref, propvalFrom as IEnumerable, prop, boundaryAttr?.BreakThen != true);
|
||||||
break;
|
break;
|
||||||
case TableRefType.ManyToMany:
|
case TableRefType.ManyToMany:
|
||||||
LocalMapEntityValueCollection(entityType, entityFrom, entityTo, tbref, propvalFrom as IEnumerable, prop, false);
|
LocalMapEntityValueCollection(entityType, entityFrom, entityTo, tbref, propvalFrom as IEnumerable, prop, boundaryAttr?.BreakThen == false);
|
||||||
break;
|
break;
|
||||||
case TableRefType.PgArrayToMany:
|
case TableRefType.PgArrayToMany:
|
||||||
case TableRefType.ManyToOne: //不属于聚合根
|
break;
|
||||||
|
case TableRefType.ManyToOne:
|
||||||
|
if (boundaryAttr?.Break == false)
|
||||||
|
{
|
||||||
|
var propvalTo2 = tbref.RefEntityType.CreateInstanceGetDefaultValue();
|
||||||
|
SetNavigateRelationshipValue(fsql, tbref, table.Type, entityFrom, propvalFrom);
|
||||||
|
LocalMapEntityValue(tbref.RefEntityType, propvalFrom, propvalTo2, boundaryAttr?.BreakThen == false);
|
||||||
|
EntityUtilExtensions.SetEntityValueWithPropertyName(fsql, entityType, entityTo, prop.Name, propvalTo2);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -393,8 +446,7 @@ namespace FreeSql
|
|||||||
foreach (var fromItem in propvalFrom)
|
foreach (var fromItem in propvalFrom)
|
||||||
{
|
{
|
||||||
var toItem = tbref.RefEntityType.CreateInstanceGetDefaultValue();
|
var toItem = tbref.RefEntityType.CreateInstanceGetDefaultValue();
|
||||||
if (cascade) LocalMapEntityValue(tbref.RefEntityType, fromItem, toItem);
|
LocalMapEntityValue(tbref.RefEntityType, fromItem, toItem, cascade);
|
||||||
else EntityUtilExtensions.MapEntityValue(fsql, tbref.RefEntityType, fromItem, toItem);
|
|
||||||
propvalToIList.Add(toItem);
|
propvalToIList.Add(toItem);
|
||||||
}
|
}
|
||||||
var propvalType = prop.PropertyType.GetGenericTypeDefinition();
|
var propvalType = prop.PropertyType.GetGenericTypeDefinition();
|
||||||
@ -409,12 +461,14 @@ namespace FreeSql
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConcurrentDictionary<Type, ConcurrentDictionary<Type, Action<ISelect0>>> _dicGetAutoIncludeQuery = new ConcurrentDictionary<Type, ConcurrentDictionary<Type, Action<ISelect0>>>();
|
static ConcurrentDictionary<string, ConcurrentDictionary<Type, ConcurrentDictionary<Type, Action<ISelect0>>>> _dicGetAutoIncludeQuery = new ConcurrentDictionary<string, ConcurrentDictionary<Type, ConcurrentDictionary<Type, Action<ISelect0>>>>();
|
||||||
public static ISelect<TEntity> GetAutoIncludeQuery<TEntity>(ISelect<TEntity> select)
|
public static ISelect<TEntity> GetAutoIncludeQuery<TEntity>(string boundaryName, ISelect<TEntity> select)
|
||||||
{
|
{
|
||||||
var select0p = select as Select0Provider;
|
var select0p = select as Select0Provider;
|
||||||
var table0Type = select0p._tables[0].Table.Type;
|
var table0Type = select0p._tables[0].Table.Type;
|
||||||
var func = _dicGetAutoIncludeQuery.GetOrAdd(typeof(TEntity), t => new ConcurrentDictionary<Type, Action<ISelect0>>()).GetOrAdd(table0Type, t =>
|
var func = _dicGetAutoIncludeQuery.GetOrAdd(boundaryName ?? "", bn => new ConcurrentDictionary<Type, ConcurrentDictionary<Type, Action<ISelect0>>>())
|
||||||
|
.GetOrAdd(typeof(TEntity), t => new ConcurrentDictionary<Type, Action<ISelect0>>())
|
||||||
|
.GetOrAdd(table0Type, t =>
|
||||||
{
|
{
|
||||||
var parmExp1 = Expression.Parameter(typeof(ISelect0));
|
var parmExp1 = Expression.Parameter(typeof(ISelect0));
|
||||||
var parmNavigateParameterExp = Expression.Parameter(typeof(TEntity), "a");
|
var parmNavigateParameterExp = Expression.Parameter(typeof(TEntity), "a");
|
||||||
@ -435,6 +489,8 @@ namespace FreeSql
|
|||||||
var tbref = tr.Value;
|
var tbref = tr.Value;
|
||||||
if (tbref.Exception != null) continue;
|
if (tbref.Exception != null) continue;
|
||||||
if (table.Properties.TryGetValue(tr.Key, out var prop) == false) continue;
|
if (table.Properties.TryGetValue(tr.Key, out var prop) == false) continue;
|
||||||
|
var boundaryAttr = GetPropertyBoundaryAttribute(prop, boundaryName);
|
||||||
|
if (boundaryAttr?.Break == true) continue;
|
||||||
Expression navigateExp = Expression.MakeMemberAccess(navigatePathExp, prop);
|
Expression navigateExp = Expression.MakeMemberAccess(navigatePathExp, prop);
|
||||||
//var lambdaAlias = (char)((byte)'a' + (depth - 1));
|
//var lambdaAlias = (char)((byte)'a' + (depth - 1));
|
||||||
switch (tbref.RefType)
|
switch (tbref.RefType)
|
||||||
@ -442,17 +498,24 @@ namespace FreeSql
|
|||||||
case TableRefType.OneToOne:
|
case TableRefType.OneToOne:
|
||||||
if (ignores.Any(a => a == tbref.RefEntityType)) break;
|
if (ignores.Any(a => a == tbref.RefEntityType)) break;
|
||||||
LocalInclude(tbref, navigateExp);
|
LocalInclude(tbref, navigateExp);
|
||||||
queryExp = LocalGetAutoIncludeQuery(queryExp, depth, tbref.RefEntityType, navigateParameterExp, navigateExp, ignores);
|
if (boundaryAttr?.BreakThen != true)
|
||||||
|
queryExp = LocalGetAutoIncludeQuery(queryExp, depth, tbref.RefEntityType, navigateParameterExp, navigateExp, ignores);
|
||||||
break;
|
break;
|
||||||
case TableRefType.OneToMany:
|
case TableRefType.OneToMany:
|
||||||
LocalIncludeMany(tbref, navigateExp, true);
|
LocalIncludeMany(tbref, navigateExp, boundaryAttr?.BreakThen != true);
|
||||||
break;
|
break;
|
||||||
case TableRefType.ManyToMany:
|
case TableRefType.ManyToMany:
|
||||||
LocalIncludeMany(tbref, navigateExp, false);
|
LocalIncludeMany(tbref, navigateExp, boundaryAttr?.BreakThen == false);
|
||||||
break;
|
break;
|
||||||
case TableRefType.PgArrayToMany:
|
case TableRefType.PgArrayToMany:
|
||||||
break;
|
break;
|
||||||
case TableRefType.ManyToOne: //不属于聚合根
|
case TableRefType.ManyToOne:
|
||||||
|
if (boundaryAttr?.Break == false)
|
||||||
|
{
|
||||||
|
LocalInclude(tbref, navigateExp);
|
||||||
|
if (boundaryAttr?.BreakThen == false)
|
||||||
|
queryExp = LocalGetAutoIncludeQuery(queryExp, depth, tbref.RefEntityType, navigateParameterExp, navigateExp, ignores);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -482,7 +545,8 @@ namespace FreeSql
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static string GetAutoIncludeQueryStaicCode(IFreeSql fsql, Type rootEntityType)
|
|
||||||
|
public static string GetAutoIncludeQueryStaicCode(string boundaryName, IFreeSql fsql, Type rootEntityType)
|
||||||
{
|
{
|
||||||
return $"//fsql.Select<{rootEntityType.Name}>()\r\nSelectDiy{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)
|
||||||
@ -497,6 +561,9 @@ namespace FreeSql
|
|||||||
{
|
{
|
||||||
var tbref = tr.Value;
|
var tbref = tr.Value;
|
||||||
if (tbref.Exception != null) continue;
|
if (tbref.Exception != null) continue;
|
||||||
|
if (table.Properties.TryGetValue(tr.Key, out var prop) == false) continue;
|
||||||
|
var boundaryAttr = GetPropertyBoundaryAttribute(prop, boundaryName);
|
||||||
|
if (boundaryAttr?.Break == true) continue;
|
||||||
var navigateExpression = $"{navigatePath}{tr.Key}";
|
var navigateExpression = $"{navigatePath}{tr.Key}";
|
||||||
var depthTab = "".PadLeft(depth * 4);
|
var depthTab = "".PadLeft(depth * 4);
|
||||||
var lambdaAlias = (char)((byte)'a' + (depth - 1));
|
var lambdaAlias = (char)((byte)'a' + (depth - 1));
|
||||||
@ -506,22 +573,33 @@ namespace FreeSql
|
|||||||
case TableRefType.OneToOne:
|
case TableRefType.OneToOne:
|
||||||
if (ignores.Any(a => a == tbref.RefEntityType)) break;
|
if (ignores.Any(a => a == tbref.RefEntityType)) break;
|
||||||
code.Append("\r\n").Append(depthTab).Append(".Include(").Append(lambdaStr).Append(navigateExpression).Append(")");
|
code.Append("\r\n").Append(depthTab).Append(".Include(").Append(lambdaStr).Append(navigateExpression).Append(")");
|
||||||
code.Append(LocalGetAutoIncludeQueryStaicCode(depth, tbref.RefEntityType, navigateExpression, ignores));
|
if (boundaryAttr?.BreakThen != true)
|
||||||
|
code.Append(LocalGetAutoIncludeQueryStaicCode(depth, tbref.RefEntityType, navigateExpression, ignores));
|
||||||
break;
|
break;
|
||||||
case TableRefType.OneToMany:
|
case TableRefType.OneToMany:
|
||||||
code.Append("\r\n").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression);
|
code.Append("\r\n").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression);
|
||||||
var thencode = LocalGetAutoIncludeQueryStaicCode(depth + 1, tbref.RefEntityType, "", new Stack<Type>(ignores.ToArray()));
|
if (boundaryAttr?.BreakThen != true)
|
||||||
if (thencode.Length > 0) code.Append(", then => then").Append(thencode);
|
{
|
||||||
|
var thencode = LocalGetAutoIncludeQueryStaicCode(depth + 1, tbref.RefEntityType, "", new Stack<Type>(ignores.ToArray()));
|
||||||
|
if (thencode.Length > 0) code.Append(", then => then").Append(thencode);
|
||||||
|
}
|
||||||
code.Append(")");
|
code.Append(")");
|
||||||
break;
|
break;
|
||||||
case TableRefType.ManyToMany:
|
case TableRefType.ManyToMany:
|
||||||
code.Append("\r\n").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression).Append(")");
|
code.Append("\r\n").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression);
|
||||||
|
if (boundaryAttr?.BreakThen == false)
|
||||||
|
{
|
||||||
|
var thencode2 = LocalGetAutoIncludeQueryStaicCode(depth + 1, tbref.RefEntityType, "", new Stack<Type>(ignores.ToArray()));
|
||||||
|
if (thencode2.Length > 0) code.Append(", then => then").Append(thencode2);
|
||||||
|
}
|
||||||
|
code.Append(")");
|
||||||
break;
|
break;
|
||||||
case TableRefType.PgArrayToMany:
|
case TableRefType.PgArrayToMany:
|
||||||
code.Append("\r\n//").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression).Append(")");
|
|
||||||
break;
|
break;
|
||||||
case TableRefType.ManyToOne: //不属于聚合根
|
case TableRefType.ManyToOne:
|
||||||
code.Append("\r\n//").Append(depthTab).Append(".Include(").Append(lambdaStr).Append(navigateExpression).Append(")");
|
code.Append("\r\n").Append(boundaryAttr != null ? "" : "//").Append(depthTab).Append(".Include(").Append(lambdaStr).Append(navigateExpression).Append(")");
|
||||||
|
if (boundaryAttr?.BreakThen == false)
|
||||||
|
code.Append(LocalGetAutoIncludeQueryStaicCode(depth, tbref.RefEntityType, navigateExpression, ignores));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -557,6 +635,7 @@ namespace FreeSql
|
|||||||
}
|
}
|
||||||
return middles;
|
return middles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetNavigateRelationshipValue(IFreeSql orm, TableRef tbref, Type leftType, object leftItem, object rightItem)
|
public static void SetNavigateRelationshipValue(IFreeSql orm, TableRef tbref, Type leftType, object leftItem, object rightItem)
|
||||||
{
|
{
|
||||||
if (rightItem == null) return;
|
if (rightItem == null) return;
|
||||||
|
@ -26,7 +26,7 @@ namespace FreeSql.Tests.DbContext2
|
|||||||
{
|
{
|
||||||
new UserRepository(fsql, null);
|
new UserRepository(fsql, null);
|
||||||
|
|
||||||
var code = AggregateRootUtils.GetAutoIncludeQueryStaicCode(fsql, typeof(User));
|
var code = AggregateRootUtils.GetAutoIncludeQueryStaicCode(null, fsql, typeof(User));
|
||||||
Assert.Equal(@"//fsql.Select<User>()
|
Assert.Equal(@"//fsql.Select<User>()
|
||||||
SelectDiy
|
SelectDiy
|
||||||
.Include(a => a.Ext)", code);
|
.Include(a => a.Ext)", code);
|
||||||
@ -147,7 +147,6 @@ SelectDiy
|
|||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string UserName { get; set; }
|
public string UserName { get; set; }
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
[Navigate(nameof(Id))]
|
|
||||||
public UserExt Ext { get; set; }
|
public UserExt Ext { get; set; }
|
||||||
}
|
}
|
||||||
class UserExt
|
class UserExt
|
||||||
@ -155,7 +154,6 @@ SelectDiy
|
|||||||
[Column(IsPrimary = true)]
|
[Column(IsPrimary = true)]
|
||||||
public int UserId { get; set; }
|
public int UserId { get; set; }
|
||||||
public string Remark { get; set; }
|
public string Remark { get; set; }
|
||||||
[Navigate(nameof(UserId))]
|
|
||||||
public User Org { get; set; }
|
public User Org { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using FreeSql.DataAnnotations;
|
using FreeSql.DataAnnotations;
|
||||||
|
using FreeSql.Internal;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
@ -27,7 +28,16 @@ namespace FreeSql.Tests.DbContext2
|
|||||||
{
|
{
|
||||||
new OrderRepository(fsql, null);
|
new OrderRepository(fsql, null);
|
||||||
|
|
||||||
var code = AggregateRootUtils.GetAutoIncludeQueryStaicCode(fsql, typeof(Order));
|
|
||||||
|
fsql.Aop.CommandAfter += (_, e) =>
|
||||||
|
{
|
||||||
|
if (e.Exception is DbUpdateVersionException)
|
||||||
|
{
|
||||||
|
throw new Exception(e.Exception.Message, e.Exception);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var code = AggregateRootUtils.GetAutoIncludeQueryStaicCode(null, fsql, typeof(Order));
|
||||||
Assert.Equal(@"//fsql.Select<Order>()
|
Assert.Equal(@"//fsql.Select<Order>()
|
||||||
SelectDiy
|
SelectDiy
|
||||||
.Include(a => a.Extdata)
|
.Include(a => a.Extdata)
|
||||||
@ -165,7 +175,6 @@ SelectDiy
|
|||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Field2 { get; set; }
|
public string Field2 { get; set; }
|
||||||
|
|
||||||
[Navigate(nameof(Id))]
|
|
||||||
public OrderExt Extdata { get; set; }
|
public OrderExt Extdata { get; set; }
|
||||||
[Navigate(nameof(OrderDetail.OrderId))]
|
[Navigate(nameof(OrderDetail.OrderId))]
|
||||||
public List<OrderDetail> Details { get; set; }
|
public List<OrderDetail> Details { get; set; }
|
||||||
@ -178,7 +187,6 @@ SelectDiy
|
|||||||
public int OrderId { get; set; }
|
public int OrderId { get; set; }
|
||||||
public string Field3 { get; set; }
|
public string Field3 { get; set; }
|
||||||
|
|
||||||
[Navigate(nameof(OrderId))]
|
|
||||||
public Order Order { get; set; }
|
public Order Order { get; set; }
|
||||||
}
|
}
|
||||||
class OrderDetail
|
class OrderDetail
|
||||||
@ -188,7 +196,7 @@ SelectDiy
|
|||||||
public int OrderId { get; set; }
|
public int OrderId { get; set; }
|
||||||
public string Field4 { get; set; }
|
public string Field4 { get; set; }
|
||||||
|
|
||||||
[Navigate(nameof(Id))]
|
[AggregateRootBoundary("name1", Break = true)]
|
||||||
public OrderDetailExt Extdata { get; set; }
|
public OrderDetailExt Extdata { get; set; }
|
||||||
}
|
}
|
||||||
class OrderDetailExt
|
class OrderDetailExt
|
||||||
@ -197,7 +205,6 @@ SelectDiy
|
|||||||
public int OrderDetailId { get; set; }
|
public int OrderDetailId { get; set; }
|
||||||
public string Field5 { get; set; }
|
public string Field5 { get; set; }
|
||||||
|
|
||||||
[Navigate(nameof(OrderDetailId))]
|
|
||||||
public OrderDetail OrderDetail { get; set; }
|
public OrderDetail OrderDetail { get; set; }
|
||||||
}
|
}
|
||||||
class OrderTag
|
class OrderTag
|
||||||
|
Loading…
x
Reference in New Issue
Block a user