private static void ThrowRefPropertyChangingConflict(IRefIdProperty property) { throw new InvalidOperationException( string.Format(@"{0} 属性的变更前事件与引用实体属性 {1} 的变更前事件设置的值冲突!", property.Name, property.RefEntityProperty.Name) ); }
/// <summary> /// 根据冗余路径从当前对象开始搜索,获取真实的属性值。 /// </summary> /// <param name="path"></param> /// <param name="from"> /// 本对象在路径中拥有的引用属性。 /// 在 D->C->B->A.Name 场景中,当前对象(this)可能是 C,那么 from 就是 C.BRefProperty. /// 如果没有指定此属性,则表示从第一个开始。 /// </param> /// <returns></returns> internal object GetRedundancyValue(RedundantPath path, IRefIdProperty from = null) { Entity refEntity = this; foreach (var refP in path.RefPathes) { if (from != null && refP.Property != from) { continue; } refEntity = refEntity.GetRefEntity((refP.Property as IRefProperty).RefEntityProperty); if (refEntity == null) { break; } } object value = null; if (refEntity != this && refEntity != null) { value = refEntity.GetProperty(path.ValueProperty.Property); } return(value); }
/// <summary> /// 设置指定引用 id 属性对应的 id 的可空类型值。 /// </summary> /// <param name="property"></param> /// <param name="value">本方法为兼容值类型而使用。不论外键是否为值类型,都可以传入 null。</param> /// <param name="source"></param> /// <returns></returns> public object SetRefNullableId(IRefIdProperty property, object value, ManagedPropertyChangedSource source = ManagedPropertyChangedSource.FromProperty) { if (value == null) { value = GetEmptyIdForRefIdProperty(property); } var finalValue = this.SetRefId(property, value, source); return(property.KeyProvider.ToNullableValue(finalValue)); }
public RefTableProperty(IRefIdProperty refProperty, Type propertyOwner) { this.PropertyOwner = propertyOwner; this.RefProperty = refProperty; var mainTable = RdbTableFinder.TableFor(propertyOwner); var refTable = RdbTableFinder.TableFor(refProperty.RefEntityType); this.OwnerTable = mainTable; this.RefTable = refTable; this.FKName = mainTable.Translate(refProperty); }
public RefTableProperty(IRefIdProperty refProperty, Type propertyOwner) { this.PropertyOwner = propertyOwner; this.RefProperty = refProperty; var mainTable = RdbTableFinder.TableFor(propertyOwner); var refTable = RdbTableFinder.TableFor(refProperty.RefEntityType); this.OwnerTable = mainTable; this.RefTable = refTable; this.FKName = mainTable.Translate(refProperty); }
/// <summary> /// 根据冗余路径从当前对象开始搜索,获取真实的属性值。 /// </summary> /// <param name="path"></param> /// <param name="from"> /// 本对象在路径中拥有的引用属性。 /// 在 D->C->B->A.Name 场景中,当前对象(this)可能是 C,那么 from 就是 C.BRefProperty. /// 如果没有指定此属性,则表示从第一个开始。 /// </param> /// <returns></returns> internal object GetRedundancyValue(RedundantPath path, IRefIdProperty from = null) { Entity refEntity = this; foreach (var refP in path.RefPathes) { if (from != null && refP.Property != from) continue; refEntity = refEntity.GetRefEntity((refP.Property as IRefProperty).RefEntityProperty); if (refEntity == null) break; } object value = null; if (refEntity != this && refEntity != null) value = refEntity.GetProperty(path.ValueProperty.Property); return value; }
private static bool HasRefId(IRefIdProperty refIdProperty, object id) { return(refIdProperty.KeyProvider.IsAvailable(id)); }
private static object GetEmptyIdForRefIdProperty(IRefIdProperty refIdProperty) { return(refIdProperty.KeyProvider.GetEmptyIdForRefIdProperty()); }
/// <summary> /// 设置指定引用 id 属性对应的 id 的值。 /// /// 在引用 id 变化时,会同步相应的引用实体属性。 /// </summary> /// <param name="property"></param> /// <param name="value">外键如果是值类型,则不能传入 null。</param> /// <param name="source"></param> /// <returns></returns> public object SetRefId(IRefIdProperty property, object value, ManagedPropertyChangedSource source = ManagedPropertyChangedSource.FromProperty) { //引用属性的托管属性类型是 object,这里需要强制为指定的主键类型。 value = TypeHelper.CoerceValue(property.KeyProvider.KeyType, value); var id = this.GetRefId(property); //设置 id 完成后的值。 object finalId = id; //确实需要改变 Id 时,才进行以下逻辑。 if (!object.Equals(id, value)) { var entityProperty = property.RefEntityProperty; //在设置 RefId 前先清空实体值,这样在回调 RefId 的外部 Changed 事件处理函数时, //外部看到的 RefEntity 也已经改变了,外部可以获得一致的 Entity 和 Id 值。 var entity = base.GetProperty(entityProperty) as Entity; if (entity != null && !object.Equals(entity.Id, value)) { base.ResetProperty(entityProperty); } try { //此时发生 OnIdChanged 事件。 finalId = base.SetProperty(property, value, source); } finally { //还原实体的值。 if (entity != null) { base.LoadProperty(entityProperty, entity); } } //如果二者相等,表示 Id 成功设置,没有被 cancel。 if (object.Equals(finalId, value)) { //如果之前的实体已经存在值,则需要设置为 null,并引发外部事件。 if (entity != null) { //重新设置 Entity 的值,此时发生 OnEntityChanged 事件。 var finalEntity = base.SetProperty(entityProperty, null, source) as Entity; //如果外部事件取消了属性的设置,那么实际使用的实体将不会为 null, if (finalEntity != null) { //此时,需要重设 Id 的值。 finalId = base.SetProperty(property, finalEntity.Id, source); if (!object.Equals(finalId, finalEntity.Id)) { ThrowRefPropertyChangingConflict(property); } } } } } return(finalId); }
/// <summary> /// 冗余路径中非首位的引用属的值作为值属性进行冗余,那么同样要进行值属性更新操作。 /// </summary> /// <param name="entity">The entity.</param> /// <param name="path">The path.</param> /// <param name="refChanged">该引用属性值变化了</param> private void UpdateRedundancyByRefValue(Entity entity, RedundantPath path, IRefIdProperty refChanged) { var newValue = entity.GetProperty(refChanged); this.UpdateRedundancy(entity, path.Redundancy, newValue, path.RefPathes, entity.Id); }
/// <summary> /// 获取指定引用 id 属性对应的 id 的可空类型返回值。 /// </summary> /// <param name="property"></param> /// <returns></returns> public new int?GetRefNullableId(IRefIdProperty property) { return((int?)base.GetRefNullableId(property)); }
/// <summary> /// 获取指定引用 id 属性对应的 id 的可空类型返回值。 /// </summary> /// <param name="property"></param> /// <returns>本方法为兼容值类型而使用。不论 Id 是值类型、还是引用类型,都可能返回 null。</returns> public object GetRefNullableId(IRefIdProperty property) { var value = this.GetProperty(property); return(property.KeyProvider.ToNullableValue(value)); }
/// <summary> /// 扩展一个引用实体属性。 /// </summary> /// <typeparam name="TRefEntity"></typeparam> /// <param name="propertyName">实体属性的名称。</param> /// <param name="declareType">声明此属性的类型。</param> /// <param name="refIdProperty">对应的引用 Id 属性,将为其建立关联。</param> /// <returns></returns> public static RefEntityProperty <TRefEntity> RegisterRefExtension <TRefEntity>(string propertyName, Type declareType, IRefIdProperty refIdProperty) where TRefEntity : Entity { if (refIdProperty == null) { throw new ArgumentNullException("refIdProperty", "必须指定引用 Id 属性,将为其建立关联。"); } var defaultMeta = new PropertyMetadata <Entity>(); var property = new RefEntityProperty <TRefEntity>(typeof(TEntity), declareType, propertyName, defaultMeta) { RefIdProperty = refIdProperty }; //默认只从服务端序列化到客户端。 defaultMeta.Serializable = RafyEnvironment.IsOnServer(); ManagedPropertyRepository.Instance.RegisterProperty(property); return(property); }
/// <summary> /// 声明一个引用实体属性。 /// </summary> /// <typeparam name="TRefEntity"></typeparam> /// <param name="propertyExp">指向引用实体属性的表达式。</param> /// <param name="refIdProperty">对应的引用 Id 属性,将为其建立关联。</param> /// <returns></returns> public static RefEntityProperty <TRefEntity> RegisterRef <TRefEntity>(Expression <Func <TEntity, TRefEntity> > propertyExp, IRefIdProperty refIdProperty) where TRefEntity : Entity { if (refIdProperty == null) { throw new ArgumentNullException("refIdProperty", "必须指定引用 Id 属性,将为其建立关联。"); } var defaultMeta = new PropertyMetadata <Entity>(); defaultMeta.AffectStatus = false; var property = new RefEntityProperty <TRefEntity>(typeof(TEntity), GetPropertyName(propertyExp), defaultMeta) { RefIdProperty = refIdProperty }; //默认只从服务端序列化到客户端。 defaultMeta.Serializable = RafyEnvironment.IsOnServer(); ManagedPropertyRepository.Instance.RegisterProperty(property); return(property); }
/// <summary> /// 冗余路径中非首位的引用属性变化时引发的冗余值更新操作。 /// </summary> /// <param name="entity">The entity.</param> /// <param name="path">The path.</param> /// <param name="refChanged">该引用属性值变化了</param> private void UpdateRedundancyByIntermidateRef(Entity entity, RedundantPath path, IRefIdProperty refChanged) { var newValue = entity.GetRedundancyValue(path, refChanged); //只要从开始到 refChanged 前一个 var refPathes = new List <ConcreteProperty>(5); foreach (var refProperty in path.RefPathes) { if (refProperty.Property == refChanged) { break; } refPathes.Add(refProperty); } this.UpdateRedundancy(entity, path.Redundancy, newValue, refPathes, entity.Id); }
/// <summary> /// 冗余路径中非首位的引用属的值作为值属性进行冗余,那么同样要进行值属性更新操作。 /// </summary> /// <param name="entity">The entity.</param> /// <param name="path">The path.</param> /// <param name="refChanged">该引用属性值变化了</param> private void UpdateRedundancyByRefValue(Entity entity, RedundantPath path, IRefIdProperty refChanged) { var newValue = entity.GetProperty(refChanged); this.UpdateRedundancy(entity, path.Redundancy, newValue, path.RefPathes, entity.Id); }
/// <summary> /// 获取指定引用 id 属性对应的 id 的返回值。 /// </summary> /// <param name="property"></param> /// <returns>如果 Id 是值类型,则这个函数的返回值不会是 null;如果是引用类型,则可能返回 null。</returns> public object GetRefId(IRefIdProperty property) { return(this.GetProperty(property)); }
/// <summary> /// 获取指定引用 id 属性对应的 id 的返回值。 /// </summary> /// <param name="property"></param> /// <returns></returns> public new int GetRefId(IRefIdProperty property) { return((int)base.GetRefId(property)); }
/// <summary> /// 冗余路径中非首位的引用属性变化时引发的冗余值更新操作。 /// </summary> /// <param name="entity">The entity.</param> /// <param name="path">The path.</param> /// <param name="refChanged">该引用属性值变化了</param> private void UpdateRedundancyByIntermidateRef(Entity entity, RedundantPath path, IRefIdProperty refChanged) { var newValue = entity.GetRedundancyValue(path, refChanged); //只要从开始到 refChanged 前一个 var refPathes = new List<ConcreteProperty>(5); foreach (var refProperty in path.RefPathes) { if (refProperty.Property == refChanged) break; refPathes.Add(refProperty); } this.UpdateRedundancy(entity, path.Redundancy, newValue, refPathes, entity.Id); }