mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 18:52:50 +08:00
AggregateRootRepository Boundary
This commit is contained in:
parent
9db121d531
commit
f601d9b9e0
@ -4,6 +4,12 @@ using System.Linq;
|
|||||||
namespace FreeSql.DataAnnotations
|
namespace FreeSql.DataAnnotations
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置 AggregateRootRepository 边界范围<para></para>
|
||||||
|
/// 在边界范围之内的规则 :<para></para>
|
||||||
|
/// 1、OneToOne/OneToMany/ManyToMany(中间表) 可以查询、可以增删改<para></para>
|
||||||
|
/// 2、ManyToOne/ManyToMany外部表/PgArrayToMany 只可以查询,不支持增删改(会被忽略)<para></para>
|
||||||
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
|
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
|
||||||
public class AggregateRootBoundaryAttribute : Attribute
|
public class AggregateRootBoundaryAttribute : Attribute
|
||||||
{
|
{
|
||||||
|
@ -3,10 +3,15 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace FreeSql.Internal.Model
|
namespace FreeSql.Internal.Model
|
||||||
{
|
{
|
||||||
|
|
||||||
public class AggregateRootTrackingChangeInfo
|
public class AggregateRootTrackingChangeInfo
|
||||||
{
|
{
|
||||||
|
|
||||||
public List<NativeTuple<Type, object>> InsertLog { get; } = new List<NativeTuple<Type, object>>();
|
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, 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[]>>();
|
public List<NativeTuple<Type, object[]>> DeleteLog { get; } = new List<NativeTuple<Type, object[]>>();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -40,7 +40,7 @@ namespace FreeSql
|
|||||||
DisposeChildRepositorys();
|
DisposeChildRepositorys();
|
||||||
_repository.FlushState();
|
_repository.FlushState();
|
||||||
FlushState();
|
FlushState();
|
||||||
_boundaryName = name;
|
_boundaryName = string.Concat(name).Trim();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ namespace FreeSql
|
|||||||
var repos = new Dictionary<Type, object>();
|
var repos = new Dictionary<Type, object>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var ret = await InsertWithinBoundaryStaticAsync(_boundaryName, _repository, GetChildRepository, entitys, out var affrows, cancellationToken);
|
var ret = await InsertWithinBoundaryStaticAsync(_boundaryName, _repository, GetChildRepository, entitys, null, cancellationToken);
|
||||||
Attach(ret);
|
Attach(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -35,9 +35,116 @@ namespace FreeSql
|
|||||||
_repository.FlushState();
|
_repository.FlushState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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
|
async Task<List<T1>> InsertWithinBoundaryStaticAsync<T1>(string boundaryName, IBaseRepository<T1> rootRepository, Func<Type, IBaseRepository<object>> getChildRepository, IEnumerable<T1> rootEntitys, int[] affrows, CancellationToken cancellationToken) where T1 : class
|
||||||
{
|
{
|
||||||
return Task.FromResult(InsertWithinBoundaryStatic(boundaryName, rootRepository, getChildRepository, rootEntitys, out affrows));
|
Dictionary<Type, Dictionary<string, bool>> ignores = new Dictionary<Type, Dictionary<string, bool>>();
|
||||||
|
Dictionary<Type, IBaseRepository<object>> repos = new Dictionary<Type, IBaseRepository<object>>();
|
||||||
|
var localAffrows = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await LocalInsertAsync(rootRepository, rootEntitys, true);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (affrows != null) affrows[0] = 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, bool cascade) 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);
|
||||||
|
if (cascade == false) return ret;
|
||||||
|
|
||||||
|
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.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, boundaryAttr?.BreakThen != true);
|
||||||
|
}
|
||||||
|
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, boundaryAttr?.BreakThen != true);
|
||||||
|
}
|
||||||
|
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, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TableRefType.PgArrayToMany:
|
||||||
|
case TableRefType.ManyToOne: //ManyToOne、ManyToMany外部表、PgArrayToMany 不属于聚合根成员,可以查询,不能增删改
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -138,8 +245,9 @@ namespace FreeSql
|
|||||||
foreach (var il in insertLogDict)
|
foreach (var il in insertLogDict)
|
||||||
{
|
{
|
||||||
var repo = GetChildRepository(il.Key);
|
var repo = GetChildRepository(il.Key);
|
||||||
await InsertWithinBoundaryStaticAsync(_boundaryName, repo, GetChildRepository, il.Value, out var affrowsOut, cancellationToken);
|
var affrowsOut = new int[1];
|
||||||
affrows += affrowsOut;
|
await InsertWithinBoundaryStaticAsync(_boundaryName, repo, GetChildRepository, il.Value, affrowsOut, cancellationToken);
|
||||||
|
affrows += affrowsOut[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var a = tracking.DeleteLog.Count - 1; a >= 0; a--)
|
for (var a = tracking.DeleteLog.Count - 1; a >= 0; a--)
|
||||||
|
@ -130,64 +130,6 @@ 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);
|
||||||
@ -250,7 +192,7 @@ namespace FreeSql
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TableRefType.PgArrayToMany:
|
case TableRefType.PgArrayToMany:
|
||||||
case TableRefType.ManyToOne: //在插入前处理
|
case TableRefType.ManyToOne: //ManyToOne、ManyToMany外部表、PgArrayToMany 不属于聚合根成员,可以查询,不能增删改
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,17 @@ namespace FreeSql
|
|||||||
{
|
{
|
||||||
public class AggregateRootUtils
|
public class AggregateRootUtils
|
||||||
{
|
{
|
||||||
|
static ConcurrentDictionary<PropertyInfo, ConcurrentDictionary<string, AggregateRootBoundaryAttribute>> _dicGetPropertyBoundaryAttribute = new ConcurrentDictionary<PropertyInfo, ConcurrentDictionary<string, AggregateRootBoundaryAttribute>>();
|
||||||
public static AggregateRootBoundaryAttribute GetPropertyBoundaryAttribute(PropertyInfo prop, string boundaryName)
|
public static AggregateRootBoundaryAttribute GetPropertyBoundaryAttribute(PropertyInfo prop, string boundaryName)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(boundaryName)) return null;
|
if (boundaryName == null) return null;
|
||||||
|
return _dicGetPropertyBoundaryAttribute.GetOrAdd(prop, tp => new ConcurrentDictionary<string, AggregateRootBoundaryAttribute>())
|
||||||
|
.GetOrAdd(boundaryName, bn =>
|
||||||
|
{
|
||||||
var attrs = prop.GetCustomAttributes(typeof(AggregateRootBoundaryAttribute), false);
|
var attrs = prop.GetCustomAttributes(typeof(AggregateRootBoundaryAttribute), false);
|
||||||
if (attrs == null || attrs.Any() == false) return null;
|
if (attrs == null || attrs.Any() == false) return null;
|
||||||
return attrs.Select(a => a as AggregateRootBoundaryAttribute).Where(a => a.Name == boundaryName).FirstOrDefault();
|
return attrs.Select(a => a as AggregateRootBoundaryAttribute).Where(a => a.Name == bn).FirstOrDefault();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CompareEntityValue(string boundaryName, IFreeSql fsql, Type rootEntityType, object rootEntityBefore, object rootEntityAfter, string rootNavigatePropertyName, AggregateRootTrackingChangeInfo tracking)
|
public static void CompareEntityValue(string boundaryName, IFreeSql fsql, Type rootEntityType, object rootEntityBefore, object rootEntityAfter, string rootNavigatePropertyName, AggregateRootTrackingChangeInfo tracking)
|
||||||
@ -112,18 +117,9 @@ namespace FreeSql
|
|||||||
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.RefMiddleEntityType, middleValuesBefore as IEnumerable, middleValuesAfter as IEnumerable, false);
|
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:
|
||||||
break;
|
case TableRefType.ManyToOne: //ManyToOne、ManyToMany外部表、PgArrayToMany 不属于聚合根成员,可以查询,不能增删改
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,7 +138,7 @@ namespace FreeSql
|
|||||||
//foreach (var item in collectionBefore as IEnumerable)
|
//foreach (var item in collectionBefore as IEnumerable)
|
||||||
//{
|
//{
|
||||||
// changelog.DeleteLog.Add(NativeTuple.Create(elementType, new[] { item }));
|
// changelog.DeleteLog.Add(NativeTuple.Create(elementType, new[] { item }));
|
||||||
// NavigateReader(fsql, elementType, item, (path, tr, ct, stackvs) =>
|
// NavigateReader(boundaryName, fsql, elementType, item, (path, tr, ct, stackvs) =>
|
||||||
// {
|
// {
|
||||||
// var dellist = stackvs.Last() as object[] ?? new [] { stackvs.Last() };
|
// var dellist = stackvs.Last() as object[] ?? new [] { stackvs.Last() };
|
||||||
// changelog.DeleteLog.Add(NativeTuple.Create(ct, dellist));
|
// changelog.DeleteLog.Add(NativeTuple.Create(ct, dellist));
|
||||||
@ -338,35 +334,16 @@ namespace FreeSql
|
|||||||
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:
|
||||||
break;
|
case TableRefType.ManyToOne: //ManyToOne、ManyToMany外部表、PgArrayToMany 不属于聚合根成员,可以查询,不能增删改
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -423,18 +400,10 @@ namespace FreeSql
|
|||||||
LocalMapEntityValueCollection(entityType, entityFrom, entityTo, tbref, propvalFrom as IEnumerable, prop, boundaryAttr?.BreakThen != 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, boundaryAttr?.BreakThen == false);
|
LocalMapEntityValueCollection(entityType, entityFrom, entityTo, tbref, propvalFrom as IEnumerable, prop, false);
|
||||||
break;
|
break;
|
||||||
case TableRefType.PgArrayToMany:
|
case TableRefType.PgArrayToMany:
|
||||||
break;
|
case TableRefType.ManyToOne: //ManyToOne、ManyToMany外部表、PgArrayToMany 不属于聚合根成员,可以查询,不能增删改
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,8 +477,10 @@ namespace FreeSql
|
|||||||
LocalIncludeMany(tbref, navigateExp, boundaryAttr?.BreakThen == false);
|
LocalIncludeMany(tbref, navigateExp, boundaryAttr?.BreakThen == false);
|
||||||
break;
|
break;
|
||||||
case TableRefType.PgArrayToMany:
|
case TableRefType.PgArrayToMany:
|
||||||
|
if (boundaryAttr?.Break == false)
|
||||||
|
LocalIncludeMany(tbref, navigateExp, boundaryAttr?.BreakThen == false);
|
||||||
break;
|
break;
|
||||||
case TableRefType.ManyToOne:
|
case TableRefType.ManyToOne: //ManyToOne、ManyToMany外部表、PgArrayToMany 不属于聚合根成员,可以查询,不能增删改
|
||||||
if (boundaryAttr?.Break == false)
|
if (boundaryAttr?.Break == false)
|
||||||
{
|
{
|
||||||
LocalInclude(tbref, navigateExp);
|
LocalInclude(tbref, navigateExp);
|
||||||
@ -589,14 +560,21 @@ namespace FreeSql
|
|||||||
code.Append("\r\n").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression);
|
code.Append("\r\n").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression);
|
||||||
if (boundaryAttr?.BreakThen == false)
|
if (boundaryAttr?.BreakThen == false)
|
||||||
{
|
{
|
||||||
var thencode2 = LocalGetAutoIncludeQueryStaicCode(depth + 1, tbref.RefEntityType, "", new Stack<Type>(ignores.ToArray()));
|
var thencode = LocalGetAutoIncludeQueryStaicCode(depth + 1, tbref.RefEntityType, "", new Stack<Type>(ignores.ToArray()));
|
||||||
if (thencode2.Length > 0) code.Append(", then => then").Append(thencode2);
|
if (thencode.Length > 0) code.Append(", then => then").Append(thencode);
|
||||||
}
|
}
|
||||||
code.Append(")");
|
code.Append(")");
|
||||||
break;
|
break;
|
||||||
case TableRefType.PgArrayToMany:
|
case TableRefType.PgArrayToMany:
|
||||||
|
code.Append("\r\n").Append(boundaryAttr != null ? "" : "//").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression);
|
||||||
|
if (boundaryAttr?.BreakThen == false)
|
||||||
|
{
|
||||||
|
var thencode = LocalGetAutoIncludeQueryStaicCode(depth + 1, tbref.RefEntityType, "", new Stack<Type>(ignores.ToArray()));
|
||||||
|
if (thencode.Length > 0) code.Append(", then => then").Append(thencode);
|
||||||
|
}
|
||||||
|
code.Append(")");
|
||||||
break;
|
break;
|
||||||
case TableRefType.ManyToOne:
|
case TableRefType.ManyToOne: //ManyToOne、ManyToMany外部表、PgArrayToMany 不属于聚合根成员,可以查询,不能增删改
|
||||||
code.Append("\r\n").Append(boundaryAttr != null ? "" : "//").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)
|
if (boundaryAttr?.BreakThen == false)
|
||||||
code.Append(LocalGetAutoIncludeQueryStaicCode(depth, tbref.RefEntityType, navigateExpression, ignores));
|
code.Append(LocalGetAutoIncludeQueryStaicCode(depth, tbref.RefEntityType, navigateExpression, ignores));
|
||||||
@ -638,10 +616,10 @@ namespace FreeSql
|
|||||||
|
|
||||||
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;
|
|
||||||
switch (tbref.RefType)
|
switch (tbref.RefType)
|
||||||
{
|
{
|
||||||
case TableRefType.OneToOne:
|
case TableRefType.OneToOne:
|
||||||
|
if (rightItem == null) return;
|
||||||
for (var idx = 0; idx < tbref.Columns.Count; idx++)
|
for (var idx = 0; idx < tbref.Columns.Count; idx++)
|
||||||
{
|
{
|
||||||
var colval = Utils.GetDataReaderValue(tbref.RefColumns[idx].CsType, EntityUtilExtensions.GetEntityValueWithPropertyName(orm, leftType, leftItem, tbref.Columns[idx].CsName));
|
var colval = Utils.GetDataReaderValue(tbref.RefColumns[idx].CsType, EntityUtilExtensions.GetEntityValueWithPropertyName(orm, leftType, leftItem, tbref.Columns[idx].CsName));
|
||||||
@ -649,6 +627,7 @@ namespace FreeSql
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TableRefType.OneToMany:
|
case TableRefType.OneToMany:
|
||||||
|
if (rightItem == null) return;
|
||||||
var rightEachOtm = rightItem as IEnumerable;
|
var rightEachOtm = rightItem as IEnumerable;
|
||||||
if (rightEachOtm == null) break;
|
if (rightEachOtm == null) break;
|
||||||
var leftColValsOtm = new object[tbref.Columns.Count];
|
var leftColValsOtm = new object[tbref.Columns.Count];
|
||||||
@ -661,7 +640,9 @@ namespace FreeSql
|
|||||||
case TableRefType.ManyToOne:
|
case TableRefType.ManyToOne:
|
||||||
for (var idx = 0; idx < tbref.RefColumns.Count; idx++)
|
for (var idx = 0; idx < tbref.RefColumns.Count; idx++)
|
||||||
{
|
{
|
||||||
var colval = Utils.GetDataReaderValue(tbref.Columns[idx].CsType, EntityUtilExtensions.GetEntityValueWithPropertyName(orm, tbref.RefEntityType, rightItem, tbref.RefColumns[idx].CsName));
|
var colval = rightItem == null ?
|
||||||
|
tbref.Columns[idx].CsType.CreateInstanceGetDefaultValue() :
|
||||||
|
Utils.GetDataReaderValue(tbref.Columns[idx].CsType, EntityUtilExtensions.GetEntityValueWithPropertyName(orm, tbref.RefEntityType, rightItem, tbref.RefColumns[idx].CsName));
|
||||||
EntityUtilExtensions.SetEntityValueWithPropertyName(orm, leftType, leftItem, tbref.Columns[idx].CsName, colval);
|
EntityUtilExtensions.SetEntityValueWithPropertyName(orm, leftType, leftItem, tbref.Columns[idx].CsName, colval);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -38,12 +38,25 @@ namespace FreeSql.Tests.DbContext2
|
|||||||
};
|
};
|
||||||
|
|
||||||
var code = AggregateRootUtils.GetAutoIncludeQueryStaicCode(null, fsql, typeof(Order));
|
var code = AggregateRootUtils.GetAutoIncludeQueryStaicCode(null, fsql, typeof(Order));
|
||||||
|
var code1 = AggregateRootUtils.GetAutoIncludeQueryStaicCode("code1", fsql, typeof(Order));
|
||||||
|
var code2 = AggregateRootUtils.GetAutoIncludeQueryStaicCode("code2", fsql, typeof(Order));
|
||||||
Assert.Equal(@"//fsql.Select<Order>()
|
Assert.Equal(@"//fsql.Select<Order>()
|
||||||
SelectDiy
|
SelectDiy
|
||||||
.Include(a => a.Extdata)
|
.Include(a => a.Extdata)
|
||||||
.IncludeMany(a => a.Details, then => then
|
.IncludeMany(a => a.Details, then => then
|
||||||
.Include(b => b.Extdata))
|
.Include(b => b.Extdata))
|
||||||
.IncludeMany(a => a.Tags)", code);
|
.IncludeMany(a => a.Tags)", code);
|
||||||
|
Assert.Equal(@"//fsql.Select<Order>()
|
||||||
|
SelectDiy
|
||||||
|
.Include(a => a.Extdata)
|
||||||
|
.IncludeMany(a => a.Details, then => then
|
||||||
|
.Include(b => b.Extdata))
|
||||||
|
.IncludeMany(a => a.Tags, then => then
|
||||||
|
.IncludeMany(b => b.Orders))", code1);
|
||||||
|
Assert.Equal(@"//fsql.Select<Order>()
|
||||||
|
SelectDiy
|
||||||
|
.IncludeMany(a => a.Details)
|
||||||
|
.IncludeMany(a => a.Tags)", code2);
|
||||||
|
|
||||||
fsql.Insert(new[]
|
fsql.Insert(new[]
|
||||||
{
|
{
|
||||||
@ -175,10 +188,11 @@ SelectDiy
|
|||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Field2 { get; set; }
|
public string Field2 { get; set; }
|
||||||
|
|
||||||
|
[AggregateRootBoundary("code2", Break = true)]
|
||||||
public OrderExt Extdata { get; set; }
|
public OrderExt Extdata { get; set; }
|
||||||
[Navigate(nameof(OrderDetail.OrderId))]
|
[Navigate(nameof(OrderDetail.OrderId)), AggregateRootBoundary("code2", BreakThen = true)]
|
||||||
public List<OrderDetail> Details { get; set; }
|
public List<OrderDetail> Details { get; set; }
|
||||||
[Navigate(ManyToMany = typeof(OrderTag))]
|
[Navigate(ManyToMany = typeof(OrderTag)), AggregateRootBoundary("code1", Break = false, BreakThen = false)]
|
||||||
public List<Tag> Tags { get; set; }
|
public List<Tag> Tags { get; set; }
|
||||||
}
|
}
|
||||||
class OrderExt
|
class OrderExt
|
||||||
|
Loading…
x
Reference in New Issue
Block a user