using FreeSql.Extensions.EntityUtil; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace FreeSql { public partial class AggregateRootRepository : IBaseRepository where TEntity : class { readonly IBaseRepository _repository; public AggregateRootRepository(IFreeSql fsql) { if (fsql == null) throw new ArgumentNullException(nameof(fsql)); _repository = fsql.GetRepository(); _repository.DbContextOptions.EnableCascadeSave = false; } public AggregateRootRepository(IFreeSql fsql, UnitOfWorkManager uowManager) : this(uowManager?.Orm ?? fsql) { uowManager?.Binding(_repository); } public void Dispose() { DisposeChildRepositorys(); _repository.Dispose(); FlushState(); } public IFreeSql Orm => _repository.Orm; public IUnitOfWork UnitOfWork { get => _repository.UnitOfWork; set => _repository.UnitOfWork = value; } public DbContextOptions DbContextOptions { get => _repository.DbContextOptions; set { if (value == null) throw new ArgumentNullException(nameof(DbContextOptions)); _repository.DbContextOptions = value; _repository.DbContextOptions.EnableCascadeSave = false; } } public void AsType(Type entityType) => _repository.AsType(entityType); Func _asTableRule; public void AsTable(Func rule) { _repository.AsTable(rule); _asTableRule = rule; } public Type EntityType => _repository.EntityType; public IDataFilter DataFilter => _repository.DataFilter; public void Attach(TEntity entity) { var state = CreateEntityState(entity); if (_states.ContainsKey(state.Key)) _states[state.Key] = state; else _states.Add(state.Key, state); } public void Attach(IEnumerable entity) { foreach (var item in entity) Attach(item); } public IBaseRepository AttachOnlyPrimary(TEntity data) => _repository.AttachOnlyPrimary(data); public Dictionary CompareState(TEntity newdata) => _repository.CompareState(newdata); public void FlushState() { _repository.FlushState(); _states.Clear(); } public IUpdate UpdateDiy => _repository.UpdateDiy; public ISelect Where(Expression> exp) => Select.Where(exp); public ISelect WhereIf(bool condition, Expression> exp) => Select.WhereIf(condition, exp); readonly Dictionary> _childRepositorys = new Dictionary>(); IBaseRepository GetChildRepository(Type type) { if (_childRepositorys.TryGetValue(type, out var repo) == false) { repo = Orm.GetRepository(); repo.AsType(type); _childRepositorys.Add(type, repo); } repo.UnitOfWork = UnitOfWork; repo.DbContextOptions = DbContextOptions; repo.DbContextOptions.EnableCascadeSave = false; repo.AsTable(_asTableRule); return repo; } void DisposeChildRepositorys() { foreach (var repo in _childRepositorys.Values) { repo.FlushState(); repo.Dispose(); } _childRepositorys.Clear(); } #region 状态管理 protected Dictionary _states = new Dictionary(); protected class EntityState { public EntityState(TEntity value, string key) { this.Value = value; this.Key = key; this.Time = DateTime.Now; } public TEntity OldValue { get; set; } public TEntity Value { get; set; } public string Key { get; set; } public DateTime Time { get; set; } } EntityState CreateEntityState(TEntity data) { if (data == null) throw new ArgumentNullException(nameof(data)); var key = Orm.GetEntityKeyString(EntityType, data, false); var state = new EntityState((TEntity)EntityType.CreateInstanceGetDefaultValue(), key); AggregateRootUtils.MapEntityValue(Orm, EntityType, data, state.Value); return state; } bool? ExistsInStates(object data) { if (data == null) throw new ArgumentNullException(nameof(data)); var key = Orm.GetEntityKeyString(EntityType, data, false); if (string.IsNullOrEmpty(key)) return null; return _states.ContainsKey(key); } #endregion #region 查询数据 /// /// 默认:创建查询对象(递归包含 Include/IncludeMany 边界之内的导航属性) /// 重写:使用 /// public virtual ISelect Select => SelectAggregateRoot; /// /// 创建查询对象(纯净) /// 当聚合根内关系复杂时,使用 this.SelectAggregateRootStaticCode 可以生成边界以内的 Include/IncludeMany 代码块 /// protected ISelect SelectDiy => _repository.Select; /// /// 创建查询对象(递归包含 Include/IncludeMany 边界之内的导航属性) /// /// protected ISelect SelectAggregateRoot { get { var query = _repository.Select.TrackToList(SelectAggregateRootTracking); query = AggregateRootUtils.GetAutoIncludeQuery(query); return query; } } /// /// 按默认边界规则,返回 c# 静态代码 /// 1、聚合根内关系复杂手工编写 Include/IncludeMany 会很蛋疼 /// 2、返回的内容用,可用于配合重写仓储 override Select 属性 /// 返回内容:fsql.Select<T>().Include(...).IncludeMany(...) /// protected string SelectAggregateRootStaticCode => $"//fsql.Select<{EntityType.Name}>()\r\nthis.SelectDiy{AggregateRootUtils.GetAutoIncludeQueryStaicCode(Orm, EntityType)}"; /// /// ISelect.TrackToList 委托,数据返回后自动 Attach /// /// protected void SelectAggregateRootTracking(object list) { if (list == null) return; var ls = list as IEnumerable; if (ls == null) { var ie = list as IEnumerable; if (ie == null) return; var isfirst = true; foreach (var item in ie) { if (item == null) continue; if (isfirst) { isfirst = false; var itemType = item.GetType(); if (itemType == typeof(object)) return; if (itemType.FullName.Contains("FreeSqlLazyEntity__")) itemType = itemType.BaseType; if (Orm.CodeFirst.GetTableByEntity(itemType)?.Primarys.Any() != true) return; if (itemType.GetConstructor(Type.EmptyTypes) == null) return; } if (item is TEntity item2) Attach(item2); else return; } return; } } //void SelectAggregateRootNavigateReader(ISelect currentQuery, Type entityType, string navigatePath, Stack ignores) //{ // if (ignores.Any(a => a == entityType)) return; // ignores.Push(entityType); // var table = Orm.CodeFirst.GetTableByEntity(entityType); // if (table == null) return; // if (!string.IsNullOrWhiteSpace(navigatePath)) navigatePath = $"{navigatePath}."; // foreach (var tr in table.GetAllTableRef()) // { // var tbref = tr.Value; // if (tbref.Exception != null) continue; // var navigateExpression = $"{navigatePath}{tr.Key}"; // switch (tbref.RefType) // { // case TableRefType.OneToOne: // if (ignores.Any(a => a == tbref.RefEntityType)) break; // currentQuery.IncludeByPropertyName(navigateExpression); // SelectAggregateRootNavigateReader(currentQuery, tbref.RefEntityType, navigateExpression, ignores); // break; // case TableRefType.OneToMany: // var ignoresCopy = new Stack(ignores.ToArray()); // currentQuery.IncludeByPropertyName(navigateExpression, then => // SelectAggregateRootNavigateReader(then, tbref.RefEntityType, "", ignoresCopy)); //variable 'then' of type 'FreeSql.ISelect`1[System.Object]' referenced from scope '', but it is not defined // break; // case TableRefType.ManyToMany: // currentQuery.IncludeByPropertyName(navigateExpression); // break; // case TableRefType.PgArrayToMany: // case TableRefType.ManyToOne: //不属于聚合根 // break; // } // } // ignores.Pop(); //} #endregion } }