/// <summary> /// 在查询对象中查找或者创建指定引用属性对应的连接表对象。 /// </summary> /// <param name="ownerTable">引用属性对应外键所在的表。</param> /// <param name="refProperty">指定的引用属性。</param> /// <returns></returns> internal ITableSource FindOrCreateJoinTable(ITableSource ownerTable, IRefEntityProperty refProperty) { var query = this as IQuery; var refTableSource = _allJoinTables.FirstOrDefault( ts => ts.OwnerTable == ownerTable && ts.Property == refProperty ); if (refTableSource == null) { var f = QueryFactory.Instance; var refEntityType = refProperty.RefEntityType; var refRepo = RepositoryFactoryHost.Factory.FindByEntity(refEntityType); var refTable = f.Table(refRepo, this.NextJoinTableAlias()); var joinType = refProperty.Nullable ? JoinType.LeftOuter : JoinType.Inner; query.From = f.Join(query.From, refTable, f.Constraint( ownerTable.Column(refProperty.RefIdProperty), refTable.Column(Entity.IdProperty) ), joinType); refTableSource = new SqlTableSource { OwnerTable = ownerTable, Property = refProperty, RefTable = refTable, }; _allJoinTables.Add(refTableSource); } return(refTableSource.RefTable); }
internal void SetParentEntity(Entity parent, IRefEntityProperty parentRefProperty) { //由于有时父引用实体没有发生改变,但是父引用实体的 Id 变了,此时也可以调用此方法同步二者的 Id。 //例如:保存父实体后,它的 Id 生成了。这时会调用此方法来同步 Id。 this.SetRefNullableId(parentRefProperty.RefIdProperty, parent.Id); this.SetRefEntity(parentRefProperty, parent); //由于新的父实体可以还没有 Id,这时需要主动通知冗余属性变更。 //见测试:MPT_Redundancy_AddNewAggt if (parent != null && parent.PersistenceStatus == PersistenceStatus.New) { this.NotifyIfInRedundancyPath(parentRefProperty.RefIdProperty as IProperty); } }
//暂时去除 ///// <summary> ///// 在查询对象中查找或者创建指定引用属性对应的连接表对象。 ///// </summary> ///// <param name="propertyOwner">聚合子属性所在的实体对应的表。也是外键关系中主键表所在的表。</param> ///// <param name="childrenProperty">指定的聚合子属性。</param> ///// <returns></returns> //internal ITableSource FindOrCreateJoinTable(ITableSource propertyOwner, IListProperty childrenProperty) //{ // if (childrenProperty.HasManyType != HasManyType.Composition) throw new InvalidProgramException("只能对聚合子属性使用此方法。"); // //先找到这个关系对应的引用属性。 // var refEntityType = childrenProperty.ListEntityType; // var refRepo = RepositoryFactoryHost.Factory.FindByEntity(refEntityType); // var parentProperty = refRepo.FindParentPropertyInfo(true); // var parentRef = (parentProperty.ManagedProperty as IRefProperty).RefIdProperty; // var refTableSource = _allJoinTables.FirstOrDefault( // ts => ts.RefProperty == parentRef && ts.PrimaryKeyTable == propertyOwner // ); // if (refTableSource == null) // { // var f = QueryFactory.Instance; // var fkTable = f.Table(refRepo, QueryGenerationContext.Get(this).NextTableAlias()); // refTableSource = AddJoinTable(fkTable, parentRef, propertyOwner, fkTable); // } // return refTableSource.ForeignKeyTable; //} /// <summary> /// 在查询对象中查找或者创建指定引用属性对应的连接表对象。 /// </summary> /// <param name="propertyOwner">引用属性所在的实体对应的表。也是外键关系中外键列所在的表。</param> /// <param name="refProperty">指定的引用属性。</param> /// <returns></returns> internal ITableSource FindOrCreateJoinTable(ITableSource propertyOwner, IRefEntityProperty refProperty) { var refTableSource = _allJoinTables.FirstOrDefault( ts => ts.ForeignKeyTable == propertyOwner && ts.RefProperty == refProperty ); if (refTableSource == null) { var f = QueryFactory.Instance; var refEntityType = refProperty.RefEntityType; var refRepo = RepositoryFactoryHost.Factory.FindByEntity(refEntityType); var pkTable = f.Table(refRepo, QueryGenerationContext.Get(this).NextTableAlias()); refTableSource = AddJoinTable(propertyOwner, refProperty, pkTable, pkTable); } return(refTableSource.PrimaryKeyTable); }
/// <summary> /// 以懒加载的方式获取某个引用实体的值。 /// </summary> /// <param name="entityProperty"></param> /// <returns></returns> public Entity GetRefEntity(IRefEntityProperty entityProperty) { var value = base.GetProperty(entityProperty) as Entity; if (!this._settingEntity && value == null) { var idProperty = entityProperty.RefIdProperty; var id = this.GetRefId(idProperty); if (HasRefId(idProperty, id)) { value = (entityProperty as IRefEntityPropertyInternal).Load(id, this); if (value != null) { base.LoadProperty(entityProperty, value); } } } return(value); }
protected override Expression VisitMember(MemberExpression m) { //只能访问属性 var clrProperty = m.Member as PropertyInfo; if (clrProperty == null) throw OperationNotSupported(m.Member); var ownerExp = m.Expression; if (ownerExp == null) throw OperationNotSupported(m.Member); //exp 如果是: A 或者 A.B.C,都可以作为属性查询。 var nodeType = ownerExp.NodeType; if (nodeType != ExpressionType.Parameter && nodeType != ExpressionType.MemberAccess) throw OperationNotSupported(m.Member); //如果是 A.B.C.Name,则先读取 A.B.C,记录最后一个引用实体类型 C;剩下 .Name 给本行后面的代码读取。 VisitRefEntity(ownerExp); //属性的拥有类型对应的仓库。 //获取当前正在查询的实体对应的仓库对象。如果是级联引用表达式,则使用最后一个实体即可。 var ownerRepo = _query.Repo; if (_lastJoinRefResult != null) { //如果已经有引用属性在列表中,说明上层使用了 A.B.C.Name 这样的语法。 //这时,Name 应该是 C 这个实体的值属性。 ownerRepo = RepositoryFactoryHost.Factory.FindByEntity(_lastJoinRefResult.RefEntityType); _lastJoinRefResult = null; } //查询托管属性 var mp = FindProperty(ownerRepo, clrProperty); if (mp == null) throw OperationNotSupported("Linq 查询的属性必须是一个托管属性。"); if (mp is IListProperty) throw OperationNotSupported("暂时不支持面向组合子对象的查询。"); if (mp is IRefEntityProperty) { //如果是引用属性,说明需要使用关联查询。 var refProperty = mp as IRefEntityProperty; _query.JoinRef(refProperty, ownerRepo.EntityType); //存储到字段中,最后的值属性会使用这个引用属性对应的引用实体类型来查找对应仓库。 _lastJoinRefResult = refProperty; return m; } //访问值属性 VisitValueProperty(clrProperty, mp, ownerRepo); return m; }
/// <summary> /// 设置指定引用实体属性的值。 /// 在实体属性变化时,会同步相应的引用 Id 属性。 /// </summary> /// <param name="entityProperty">The entity property.</param> /// <param name="value">The value.</param> /// <param name="source">The source.</param> /// <returns></returns> public Entity SetRefEntity(IRefEntityProperty entityProperty, Entity value, ManagedPropertyChangedSource source = ManagedPropertyChangedSource.FromProperty) { var oldEntity = base.GetProperty(entityProperty) as Entity; Entity finalEntity = oldEntity; try { _settingEntity = true; var idProperty = entityProperty.RefIdProperty; var oldId = this.GetProperty(idProperty); //如果 实体变更 或者 (设置实体为 null 并且 id 不为 null),都需要设置值改变。 if (oldEntity != value || (value == null && HasRefId(idProperty, oldId))) { var newId = value == null?GetEmptyIdForRefIdProperty(idProperty) : value.Id; //在触发外界事件处理函数之前,先设置好 Id 的值 base.LoadProperty(idProperty, newId); try { //此时再发生 OnEntityChanged 事件,外界可以获取到一致的 id 和 entity 值。 finalEntity = base.SetProperty(entityProperty, value, source) as Entity; } finally { //还原 id 的值。 base.LoadProperty(idProperty, oldId); } //如果设置实体成功,则需要开始变更 Id 的值。 if (finalEntity == value) { //如果 id 发生了变化,则需要设置 id 的值。 if (!object.Equals(oldId, newId)) { //尝试设置 id 值,如果成功,则同时会发生 OnIdChanged 事件。 var finalId = base.SetProperty(idProperty, newId, source); //如果设置 id 值失败,则应该还原 entity 的值。 if (!object.Equals(finalId, newId)) { finalEntity = base.SetProperty(entityProperty, oldEntity, source) as Entity; //还原 entity 值失败,向个界抛出冲突的异常。 if (finalEntity != oldEntity) { ThrowRefPropertyChangingConflict(idProperty); } } } } } } finally { _settingEntity = false; } return(finalEntity); }
/// <summary> /// 加载某个指定的组合子属性。 /// </summary> /// <param name="refProperty">引用实体属性。</param> /// <param name="owner">该属性对应的具体类型。 /// 这个具体的类型必须是属性的拥有类型或者它的子类型。如果传入 null,则默认为属性的拥有类型。</param> /// <returns></returns> public EagerLoadOptions LoadWith(IRefEntityProperty refProperty, Type owner) { _eagerList.Add(new ConcreteProperty(refProperty, owner)); return(this); }
protected override Expression VisitMember(MemberExpression m) { //只能访问属性 var clrProperty = m.Member as PropertyInfo; if (clrProperty == null) { throw EntityQueryBuilder.OperationNotSupported(m.Member); } var ownerExp = m.Expression; if (ownerExp == null) { throw EntityQueryBuilder.OperationNotSupported(m.Member); } //exp 如果是: A 或者 A.B.C,都可以作为属性查询。 var nodeType = ownerExp.NodeType; if (nodeType != ExpressionType.Parameter && nodeType != ExpressionType.MemberAccess) { throw EntityQueryBuilder.OperationNotSupported(m.Member); } //如果是 A.B.C.Name,则先读取 A.B.C,记录最后一个引用实体类型 C;剩下 .Name 给本行后面的代码读取。 VisitRefEntity(ownerExp); //属性的拥有类型对应的仓库。 //获取当前正在查询的实体对应的仓库对象。如果是级联引用表达式,则使用最后一个实体即可。 var ownerTable = _query.MainTable; var ownerRepo = _repo; if (_lastJoinRefResult != null) { //如果已经有引用属性在列表中,说明上层使用了 A.B.C.Name 这样的语法。 //这时,Name 应该是 C 这个实体的值属性。 ownerRepo = RepositoryFactoryHost.Factory.FindByEntity(_lastJoinRefResult.RefEntityType); ownerTable = _lastJoinTable; _lastJoinRefResult = null; _lastJoinTable = null; } //查询托管属性 var mp = EntityQueryBuilder.FindProperty(ownerRepo, clrProperty); if (mp == null) { throw EntityQueryBuilder.OperationNotSupported("Linq 查询的属性必须是一个托管属性。"); } if (mp is IRefEntityProperty) { //如果是引用属性,说明需要使用关联查询。 var refProperty = mp as IRefEntityProperty; var refTable = f.FindOrCreateJoinTable(_query, ownerTable, refProperty); if (refProperty.Nullable) { var column = ownerTable.Column(refProperty.RefIdProperty); NullableRefConstraint = _reverseConstraint ? f.Or(NullableRefConstraint, column.Equal(null as object)) : f.And(NullableRefConstraint, column.NotEqual(null as object)); } //存储到字段中,最后的值属性会使用这个引用属性对应的引用实体类型来查找对应仓库。 _lastJoinRefResult = refProperty; _lastJoinTable = refTable; return(m); } if (_visitRefProperties) { throw EntityQueryBuilder.OperationNotSupported(string.Format("不支持使用属性:{0}。这是因为它的拥有者是一个值属性,值属性只支持直接对比。", mp.Name)); } //访问值属性 PropertyOwnerTable = ownerTable; Property = mp; return(m); }
protected override Expression VisitMember(MemberExpression m) { //只能访问属性 var clrProperty = m.Member as PropertyInfo; if (clrProperty == null) { throw OperationNotSupported(m.Member); } var ownerExp = m.Expression; if (ownerExp == null) { throw OperationNotSupported(m.Member); } //exp 如果是: A 或者 A.B.C,都可以作为属性查询。 var nodeType = ownerExp.NodeType; if (nodeType != ExpressionType.Parameter && nodeType != ExpressionType.MemberAccess) { throw OperationNotSupported(m.Member); } //如果是 A.B.C.Name,则先读取 A.B.C,记录最后一个引用实体类型 C;剩下 .Name 给本行后面的代码读取。 VisitRefEntity(ownerExp); //属性的拥有类型对应的仓库。 //获取当前正在查询的实体对应的仓库对象。如果是级联引用表达式,则使用最后一个实体即可。 var ownerTable = _query.MainTable; var ownerRepo = _repo; if (_lastJoinRefResult != null) { //如果已经有引用属性在列表中,说明上层使用了 A.B.C.Name 这样的语法。 //这时,Name 应该是 C 这个实体的值属性。 ownerRepo = RepositoryFactoryHost.Factory.FindByEntity(_lastJoinRefResult.RefEntityType); ownerTable = _lastJoinTable; _lastJoinRefResult = null; _lastJoinTable = null; } //查询托管属性 var mp = FindProperty(ownerRepo, clrProperty); if (mp == null) { throw OperationNotSupported("Linq 查询的属性必须是一个托管属性。"); } if (mp is IListProperty) { throw OperationNotSupported("暂时不支持面向组合子对象的查询。"); } if (mp is IRefEntityProperty) { //如果是引用属性,说明需要使用关联查询。 var refProperty = mp as IRefEntityProperty; var refTable = f.FindOrCreateJoinTable(_query, ownerTable, refProperty); //存储到字段中,最后的值属性会使用这个引用属性对应的引用实体类型来查找对应仓库。 _lastJoinRefResult = refProperty; _lastJoinTable = refTable; return(m); } //访问值属性 VisitValueProperty(mp, ownerTable); return(m); }
protected override Expression VisitMember(MemberExpression m) { //只能访问属性 var clrProperty = m.Member as PropertyInfo; if (clrProperty == null) throw EntityQueryBuilder.OperationNotSupported(m.Member); var ownerExp = m.Expression; if (ownerExp == null) throw EntityQueryBuilder.OperationNotSupported(m.Member); //exp 如果是: A 或者 A.B.C,都可以作为属性查询。 var nodeType = ownerExp.NodeType; if (nodeType != ExpressionType.Parameter && nodeType != ExpressionType.MemberAccess) throw EntityQueryBuilder.OperationNotSupported(m.Member); //如果是 A.B.C.Name,则先读取 A.B.C,记录最后一个引用实体类型 C;剩下 .Name 给本行后面的代码读取。 VisitRefEntity(ownerExp); //属性的拥有类型对应的仓库。 //获取当前正在查询的实体对应的仓库对象。如果是级联引用表达式,则使用最后一个实体即可。 var ownerTable = _query.MainTable; var ownerRepo = _repo; if (_lastJoinRefResult != null) { //如果已经有引用属性在列表中,说明上层使用了 A.B.C.Name 这样的语法。 //这时,Name 应该是 C 这个实体的值属性。 ownerRepo = RepositoryFactoryHost.Factory.FindByEntity(_lastJoinRefResult.RefEntityType); ownerTable = _lastJoinTable; _lastJoinRefResult = null; _lastJoinTable = null; } //查询托管属性 var mp = EntityQueryBuilder.FindProperty(ownerRepo, clrProperty); if (mp == null) throw EntityQueryBuilder.OperationNotSupported("Linq 查询的属性必须是一个托管属性。"); if (mp is IRefEntityProperty) { //如果是引用属性,说明需要使用关联查询。 var refProperty = mp as IRefEntityProperty; var refTable = f.FindOrCreateJoinTable(_query, ownerTable, refProperty); if (refProperty.Nullable) { var column = ownerTable.Column(refProperty.RefIdProperty); NullableRefConstraint = _reverseConstraint ? f.Or(NullableRefConstraint, column.Equal(null as object)) : f.And(NullableRefConstraint, column.NotEqual(null as object)); } //存储到字段中,最后的值属性会使用这个引用属性对应的引用实体类型来查找对应仓库。 _lastJoinRefResult = refProperty; _lastJoinTable = refTable; return m; } if (_visitRefProperties) { throw EntityQueryBuilder.OperationNotSupported(string.Format("不支持使用属性:{0}。这是因为它的拥有者是一个值属性,值属性只支持直接对比。", mp.Name)); } //访问值属性 PropertyOwnerTable = ownerTable; Property = mp; return m; }
/// <summary> /// 在查询对象中查找或者创建指定引用属性对应的连接表对象。 /// </summary> /// <param name="query">需要在这个查询对象中查找或创建连接表。</param> /// <param name="propertyOwner">引用属性对应外键所在的表。</param> /// <param name="refProperty">指定的引用属性。</param> /// <returns></returns> public ITableSource FindOrCreateJoinTable(IQuery query, ITableSource propertyOwner, IRefEntityProperty refProperty) { return((query as TableQuery).FindOrCreateJoinTable(propertyOwner, refProperty)); }
/// <summary> /// 加载某个指定的组合子属性。 /// </summary> /// <param name="refProperty">引用实体属性。</param> /// <param name="owner">该属性对应的具体类型。 /// 这个具体的类型必须是属性的拥有类型或者它的子类型。如果传入 null,则默认为属性的拥有类型。</param> /// <returns></returns> /// <returns></returns> public EagerLoadOptions LoadWith(IRefEntityProperty refProperty, Type owner) { _eagerList.Add(new ConcreteProperty(refProperty, owner)); return this; }
//暂时去除 ///// <summary> ///// 在查询对象中查找或者创建指定引用属性对应的连接表对象。 ///// </summary> ///// <param name="propertyOwner">聚合子属性所在的实体对应的表。也是外键关系中主键表所在的表。</param> ///// <param name="childrenProperty">指定的聚合子属性。</param> ///// <returns></returns> //internal ITableSource FindOrCreateJoinTable(ITableSource propertyOwner, IListProperty childrenProperty) //{ // if (childrenProperty.HasManyType != HasManyType.Composition) throw new InvalidProgramException("只能对聚合子属性使用此方法。"); // //先找到这个关系对应的引用属性。 // var refEntityType = childrenProperty.ListEntityType; // var refRepo = RepositoryFactoryHost.Factory.FindByEntity(refEntityType); // var parentProperty = refRepo.FindParentPropertyInfo(true); // var parentRef = (parentProperty.ManagedProperty as IRefProperty).RefIdProperty; // var refTableSource = _allJoinTables.FirstOrDefault( // ts => ts.RefProperty == parentRef && ts.PrimaryKeyTable == propertyOwner // ); // if (refTableSource == null) // { // var f = QueryFactory.Instance; // var fkTable = f.Table(refRepo, QueryGenerationContext.Get(this).NextTableAlias()); // refTableSource = AddJoinTable(fkTable, parentRef, propertyOwner, fkTable); // } // return refTableSource.ForeignKeyTable; //} /// <summary> /// 在查询对象中查找或者创建指定引用属性对应的连接表对象。 /// </summary> /// <param name="propertyOwner">引用属性所在的实体对应的表。也是外键关系中外键列所在的表。</param> /// <param name="refProperty">指定的引用属性。</param> /// <returns></returns> internal ITableSource FindOrCreateJoinTable(ITableSource propertyOwner, IRefEntityProperty refProperty) { var refTableSource = _allJoinTables.FirstOrDefault( ts => ts.ForeignKeyTable == propertyOwner && ts.RefProperty == refProperty ); if (refTableSource == null) { var f = QueryFactory.Instance; var refEntityType = refProperty.RefEntityType; var refRepo = RepositoryFactoryHost.Factory.FindByEntity(refEntityType); var pkTable = f.Table(refRepo, QueryGenerationContext.Get(this).NextTableAlias()); refTableSource = AddJoinTable(propertyOwner, refProperty, pkTable, pkTable); } return refTableSource.PrimaryKeyTable; }