protected override void VisitEntityRef(IEntityRef entityRef, Entity parent, PropertyInfo propertyInfo) { if (propertyInfo.GetCustomAttributes(typeof(CompositionAttribute), false).Any()) { Entity child = null; if (entityRef == null) { // If the EntityRef hasn't been accesssed before, it might // not be initialized yet. In this case we need to access // the property directly to force it to load. child = (Entity)propertyInfo.GetValue(parent, null); } else { child = entityRef.Entity; } if (child != null) { bool lastIsChild = this._isChild; this._isChild = true; this.Visit(child); this._isChild = lastIsChild; } } }
public RegisterShipEvent(DateTime occured, string eventId, IEntityRef <Ship> ship, Port port, string name, string code) : base(occured, eventId) { this.Ship = ship; this.Port = port; this.Name = name; this.Code = code; }
protected override void VisitEntityRef(IEntityRef entityRef, Entity parent, MetaMember member) { if (member.IsComposition) { Entity child = null; if (entityRef == null) { // If the EntityRef hasn't been accessed before, it might // not be initialized yet. In this case we need to access // the property directly to force it to load. child = (Entity)member.GetValue(parent); } else { child = entityRef.Entity; } if (child != null) { bool lastIsChild = this._isChild; this._isChild = true; this.Visit(child); this._isChild = lastIsChild; } } }
/// <summary> /// Invalidates the specified tenant. /// </summary> /// <param name="tenant">The tenant.</param> public static void Invalidate(IEntityRef tenant) { if (tenant == null) { return; } using (new SecurityBypassContext()) { using (new EntityTypeContext( )) { ///// // Invalidate all the caches that could possible hold this entity. ///// var ids = GetEntityIdentifiers(tenant.Id); using (new DeferredChannelMessageContext( )) { foreach (var id in ids) { ///// // EntityCache implicitly removes from the EntityFieldCache // as well as the EntityRelationshipCache (in both directions). ///// EntityCache.Instance.Remove(id); } } InvalidateLocalProcessImpl(tenant.Id); using (var channel = CreateMessageChannel( )) { if (channel != null) { var message = new TenantHelperMessage { MessageType = TenantHelperMessageType.InvalidateTenant, TenantId = tenant.Id }; message.EntityIds.UnionWith(ids); channel.Publish(message, PublishOptions.None, false, MergeMessages); } } } string tenantName; using (new TenantAdministratorContext(0)) { tenantName = Entity.GetName(tenant.Id); } UserAccountCache.Invalidate(tenantName); } }
/// <summary> /// Get the value of an access control field. /// </summary> /// <param name="entityId">The entityId</param> /// <param name="fieldId">The fieldId</param> /// <returns>A A typed value.</returns> internal static TypedValue TryGetAccessControlField(long entityId, IEntityRef fieldId) { var value = new TypedValue { Type = DatabaseType.BoolType }; if (entityId < 1) { throw new ArgumentNullException("entityId"); } if (fieldId == null || fieldId.Namespace != "core") { throw new ArgumentException("fieldId: invalid namespace"); } switch (fieldId.Alias) { case "canCreateType": { var entityType = Entity.Get <EntityType>(entityId); if (entityType == null) { throw new InvalidOperationException("Assert false: attempted to load an entity as an EntityType which is not a type."); } SecurityBypassContext.RunAsUser(() => { value.Value = AccessControlService.CanCreate(entityType); }); break; } case "canModify": { SecurityBypassContext.RunAsUser(() => { value.Value = AccessControlService.Check(entityId, new[] { Permissions.Modify }); }); break; } case "canDelete": { SecurityBypassContext.RunAsUser(() => { value.Value = AccessControlService.Check(entityId, new[] { Permissions.Delete }); }); break; } default: { // return null value break; } } return(value); }
/// <summary> /// Gets the entities field value. /// </summary> /// <typeparam name="T">The expected return type.</typeparam> /// <param name="entity">The entity.</param> /// <param name="field">The field.</param> /// <returns> /// The field value if found, null otherwise. /// </returns> public static T GetField <T>(this IEntity entity, IEntityRef field) { if (entity == null) { throw new ArgumentNullException("entity"); } return((T)entity.GetField(field)); }
/// <summary> /// Determine the type of entity that would be found in the context generated by this instruction. /// </summary> /// <param name="owner">The instruction that owns this data source.</param> /// <returns>An EntityType</returns> public override EntityType GetContextEntityType(Instruction owner) { if (_entityType == null) { IEntityRef entityType = Expression.ResultType.EntityType; _entityType = entityType.Entity.As <EntityType>(); } return(_entityType); }
/// <summary> /// Creates a string that represents the namespace:alias of an EntityRef. /// </summary> /// <param name="entityRef">The entity reference.</param> /// <returns></returns> public string GetAliasString(IEntityRef entityRef) { if (entityRef.Alias == null) { return(null); } string res = entityRef.Namespace + ":" + entityRef.Alias; return(res); }
/// <summary> /// Determines whether the specified field is applicable to the specified entity. /// </summary> /// <param name="fieldId">The field identifier.</param> /// <param name="entityId">The entity identifier.</param> /// <returns></returns> private static bool IsFieldApplicableToEntity(IEntityRef fieldId, long entityId) { Field field = fieldId.Entity.As <Field>( ); ///// // Note* If this becomes a performance bottleneck, having Entity.SetField not throw // when calling with non-applicable fields would achieve the same result. ///// bool isApplicable = field.IsApplicableToEntity(new EntityRef(entityId).Entity); return(isApplicable); }
/// <summary> /// Assigns the values to entity. /// </summary> /// <param name="storageDictionary">The storage dictionary containing field name and <see cref="StorageItem" /> pairs.</param> /// <exception cref="System.NotImplementedException">Only ColumnAttribute is supported. /// or /// IsLookupId must be true for lookup field. /// </exception> internal void AssignValues2Entity(Dictionary <string, StorageItem> storageDictionary) { TEntity _entity = (TEntity)this.TEntityGetter; foreach (KeyValuePair <string, object> _item in MyListItem.FieldValues) { if (!storageDictionary.ContainsKey(_item.Key)) { continue; } StorageItem _storage = storageDictionary[_item.Key]; if (_storage.Association) { Debug.Assert(_storage.IsLookup, "Unexpected assignment to reverse lookup"); IEntityRef _itemRef = (IEntityRef)_storage.Storage.GetValue(_entity); _itemRef.SetLookup(_item.Value == null ? null : (FieldLookupValue)_item.Value, m_DataContext, ((AssociationAttribute)_storage.Description).List); } else { ColumnAttribute _column = _storage.Description as ColumnAttribute; if (_column == null) { throw new NotImplementedException("Only ColumnAttribute is supported."); } if (_column.FieldType == "Lookup") { if (_item.Value == null) { continue; } if (_column.IsLookupId) { _storage.Storage.SetValue(_entity, ((Microsoft.SharePoint.Client.FieldLookupValue)_item.Value).LookupId); } else { throw new NotImplementedException("IsLookupId must be true for lookup field."); } } else if (_column.FieldType == "Choice") { Dictionary <string, string> _values = new Dictionary <string, string>(); Type _type = StorageItem.GetEnumValues(_storage, _values, false); object _enumValue = Enum.Parse(_type, _values[(string)_item.Value], true); _storage.Storage.SetValue(_entity, _enumValue); } else { _storage.Storage.SetValue(_entity, _item.Value); } } } }
/// <summary> /// Determine if the field is a virtual field. /// </summary> /// <param name="field">The field</param> public static bool IsVirtualField(IEntityRef field) { if (field == null) { throw new ArgumentNullException("field"); } var fieldEntity = Entity.Get <Field>(field.Id); if (fieldEntity == null) { throw new ArgumentException("Invalid field Id"); } return(fieldEntity.IsFieldVirtual == true); }
/// <summary> /// Verify that the current user is in the specified role. /// </summary> /// <param name="role">The security role.</param> /// <exception cref="PlatformSecurityException">Thrown if permission is denied.</exception> public void CheckUserInRole(IEntityRef role) { // Check user is in import/export role var userRoles = UserRoleRepository.GetUserRoles(RequestContext.UserId); if (!userRoles.Contains(role.Id)) { string roleName; using (new SecurityBypassContext( )) { roleName = EntityRepository.Get <Role>(role)?.Name ?? "specified"; } throw new PlatformSecurityException($"Must be a member of the '{roleName}' role."); } }
/// <summary> /// Aggregates the types. /// </summary> /// <param name="entity">The entity.</param> /// <param name="field">The field.</param> /// <param name="direction">The direction.</param> /// <param name="accumulator">The accumulator.</param> private static void AggregateTypes(IEntity entity, IEntityRef field, Direction direction, HashSet <long> accumulator) { ///// // Get the entities specified field. ///// IChangeTracker <IMutableIdKey> results = Entity.GetRelationships(entity, field, direction); if (results != null) { foreach (var result in results) { ///// // Stop infinite recursion. ///// if (!accumulator.Contains(result.Key)) { ///// // Add the entity id to the accumulator. ///// accumulator.Add(result.Key); IEntity destination; var localCache = Entity.GetLocalCache(); if (!localCache.TryGetValue(result.Key, out destination)) { EntityCache.Instance.TryGetValue(result.Key, out destination); } if (destination == null) { destination = Entity.Get(result.Key); } if (destination != null) { ///// // Aggregate the results from the result. ///// AggregateTypes(destination, field, direction, accumulator); } } } } }
protected override void VisitEntityRef(IEntityRef entityRef, Entity parent, MetaMember member) { // we don't want to cause any deferred loading of the EntityRef // in non-compositional cases Entity entity = null; if (entityRef != null && entityRef.HasValue) { entity = entityRef.Entity; } // look for any invalid updates made to composed children if (entity != null && member.IsComposition) { CheckInvalidChildUpdates(entity, member.AssociationAttribute); } }
public void ChangeSet_DontLoadUnloadedAssociations() { NorthwindEntityContainer entities = new NorthwindEntityContainer(); EntitySet <Order> orders = entities.GetEntitySet <Order>(); EntitySet <Order_Detail> details = entities.GetEntitySet <Order_Detail>(); // add a few existing entities Order order = new Order { OrderID = 1 }; Order_Detail detail = new Order_Detail { OrderID = 1, ProductID = 1 }; entities.LoadEntities(new Entity[] { order, detail }); // modify both entities order.Freight = 5; detail.Quantity = 5; IEntityRef er = detail.GetEntityRef("Order"); Assert.IsNull(er); IEntityCollection ec = order.Order_Details; Assert.IsFalse(ec.HasValues); EntityChangeSet cs = entities.GetChanges(); Assert.AreEqual(2, cs.ModifiedEntities.Count); // after computing the changeset, no association members // should have been loaded er = detail.GetEntityRef("Order"); Assert.IsNull(er); Assert.IsFalse(ec.HasValues); // after building the operation list, no association members // should have been loaded ChangeSetBuilder.Build(cs); er = detail.GetEntityRef("Order"); Assert.IsNull(er); Assert.IsFalse(ec.HasValues); }
/// <summary> /// Gets the value for a single field on a single entity. /// </summary> private static TypedValue GetFieldValueImpl(Context context, IEntityRef fieldId, long entityId) { FieldInfo fieldInfo; if (!context.BulkSqlQuery.FieldTypes.TryGetValue(fieldId.Id, out fieldInfo)) { throw new InvalidOperationException("Assert false: attempted to load type info for field that was not in query."); } FieldKey key = new FieldKey(entityId, fieldId.Id); DatabaseType type = fieldInfo.DatabaseType; // Get value FieldValue fieldValue; TypedValue typedValue; if (fieldInfo.IsVirtualAccessControlField) { return(TryGetAccessControlField(entityId, fieldId)); } else if (fieldInfo.IsWriteOnly) { typedValue = new WriteOnlyFieldReadValueGenerator().GenerateValue(fieldId.Id, type); } else if (fieldInfo.IsCalculated) { object calcValue = CalculatedFieldProvider.GetCalculatedFieldValue(fieldId.Id, entityId, CalculatedFieldSettings.Default); typedValue = new TypedValue(DateTimeKind.Utc); typedValue.Type = type; typedValue.Value = calcValue; } else if (context.RawData.FieldValues.TryGetValue(key, out fieldValue)) { // 'normal' scenario typedValue = fieldValue.TypedValue; } else { // No value, so create a null value with type information. typedValue = new TypedValue(); typedValue.Type = type; } return(typedValue); }
internal void AssignValue2Entity(DataContext dataContext, Object entity, object value) { if (this.m_Association) { Debug.Assert(this.IsLookup, "Unexpected assignment to reverse lookup"); IEntityRef _itemRef = (IEntityRef)this.m_Storage.GetValue(entity); _itemRef.SetLookup(value == null ? null : (FieldLookupValue)value, dataContext, ((AssociationAttribute)this.m_Description).List); } else { ColumnAttribute _ColumnAttribute = (ColumnAttribute)this.m_Description; if (_ColumnAttribute.IsLookupId) { this.m_Storage.SetValue(entity, value == null ? new Nullable <int>() : ((FieldUserValue)value).LookupId); } else if (_ColumnAttribute.FieldType.Equals(FieldType.Choice.ToString())) { if (value != null) { Dictionary <string, string> _enumValues = new Dictionary <string, string>(); Type _type = this.GetEnumValues(_enumValues, false); string _enumFieldValue = StorageItem.NormalizeEnum((string)value); if (!_enumValues.ContainsKey(_enumFieldValue)) { throw new ArgumentOutOfRangeException("SP Field Value", String.Format("Cannot convert the value {0} to enum of type {1}", value, _type.Name)); } object _enumValue = Enum.Parse(_type, _enumValues[_enumFieldValue], true); this.m_Storage.SetValue(entity, _enumValue); } } else if (_ColumnAttribute.FieldType.Equals(FieldType.User.ToString())) { Debug.Assert(_ColumnAttribute.IsLookupValue, "IsLookupValue must be true for user field."); this.m_Storage.SetValue(entity, value == null ? string.Empty : ((FieldUserValue)value).LookupValue); } else if (_ColumnAttribute.FieldType.Equals("SPFieldUserValue")) { this.m_Storage.SetValue(entity, value == null ? String.Empty : ((FieldUserValue)value).LookupValue); } else { this.m_Storage.SetValue(entity, value); } } }
protected override void VisitEntityRef(IEntityRef entityRef, Entity parent, PropertyInfo propertyInfo) { // we don't want to cause any deferred loading of the EntityRef // in non-compositional cases Entity entity = null; if (entityRef != null && entityRef.HasValue) { entity = entityRef.Entity; } // look for any invalid updates made to composed children if (entity != null && propertyInfo.GetCustomAttributes(typeof(CompositionAttribute), false).Length == 1) { AssociationAttribute assoc = (AssociationAttribute)propertyInfo.GetCustomAttributes(typeof(AssociationAttribute), false).SingleOrDefault(); CheckInvalidChildUpdates(entity, assoc); } }
/// <summary> /// Initializes a new instance of the <see cref="EntityRef"/> class. /// </summary> /// <param name="entityRef">The entity reference.</param> /// <exception cref="System.ArgumentNullException">entityRef</exception> public EntityRef(IEntityRef entityRef) { if (entityRef == null) { throw new ArgumentNullException("entityRef"); } if (entityRef.HasEntity) { _entity = entityRef.Entity; } else { Namespace = entityRef.Namespace; // we do not fetch the namespace and alias from entities as it may force a field fetch. Alias = entityRef.Alias; } Id = entityRef.Id; }
/// <summary> /// Invalidate the <paramref name="permission"/> in the cache. /// </summary> /// <param name="permission">The permission. This cannot be null.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="permission"/> cannot be null. /// </exception> public void InvalidatePermission(IEntityRef permission) { if (permission == null) { throw new ArgumentNullException("permission"); } Trace.TraceSecurityCacheInvalidatePermission(permission.Id); // TODO // Update performance counters AccessControlCacheInvalidationCounters.GetPerformanceCounter <NumberOfItems64PerformanceCounter>( AccessControlCacheInvalidationPerformanceCounters.CountCounterName, AccessControlCacheInvalidationPerformanceCounters.PermissionInstanceName).Increment(); AccessControlCacheInvalidationCounters.GetPerformanceCounter <RatePerSecond32PerformanceCounter>( AccessControlCacheInvalidationPerformanceCounters.RateCounterName, AccessControlCacheInvalidationPerformanceCounters.PermissionInstanceName).Increment(); }
/// <summary> /// Invalidates the user. /// </summary> /// <param name="user">The user. This cannot be null.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="user"/> cannot be null. /// </exception> public void InvalidateUser(IEntityRef user) { if (user == null || !user.HasId) { return; } Trace.TraceSecurityCacheInvalidateUser(user.Id); // TODO // Update performance counters AccessControlCacheInvalidationCounters.GetPerformanceCounter <NumberOfItems64PerformanceCounter>( AccessControlCacheInvalidationPerformanceCounters.CountCounterName, AccessControlCacheInvalidationPerformanceCounters.UserInstanceName).Increment(); AccessControlCacheInvalidationCounters.GetPerformanceCounter <RatePerSecond32PerformanceCounter>( AccessControlCacheInvalidationPerformanceCounters.RateCounterName, AccessControlCacheInvalidationPerformanceCounters.UserInstanceName).Increment(); }
/// <summary> /// Invalidates the role. /// </summary> /// <param name="role">The role. This cannot be null.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="role"/> cannot be null. /// </exception> public void InvalidateRole(IEntityRef role) { if (role == null) { return; } Trace.TraceSecurityCacheInvalidateRole(role.Id); // TODO // Update performance counters AccessControlCacheInvalidationCounters.GetPerformanceCounter <NumberOfItems64PerformanceCounter>( AccessControlCacheInvalidationPerformanceCounters.CountCounterName, AccessControlCacheInvalidationPerformanceCounters.RoleInstanceName).Increment(); AccessControlCacheInvalidationCounters.GetPerformanceCounter <RatePerSecond32PerformanceCounter>( AccessControlCacheInvalidationPerformanceCounters.RateCounterName, AccessControlCacheInvalidationPerformanceCounters.RoleInstanceName).Increment(); }
/// <summary> /// Gets the relationship values for a single relationship on a single entity. /// </summary> private static IEnumerable <long> GetRelationshipsImpl(Context context, IEntityRef relTypeId, Direction direction, long entityId) { long relTypeIdWithDir = relTypeId.Id; if (direction == Direction.Reverse) { relTypeIdWithDir = -relTypeIdWithDir; } RelationshipKey key = new RelationshipKey(entityId, relTypeIdWithDir); List <long> relList; if (!context.RawData.Relationships.TryGetValue(key, out relList)) { return(Enumerable.Empty <long>()); } return(relList); }
/// <summary> /// Visit members of the entity, calling the corresponding visit methods for each /// </summary> /// <param name="entity">The entity to visit</param> public virtual void Visit(Entity entity) { if (entity == null) { throw new ArgumentNullException("entity"); } foreach (PropertyInfo association in entity.MetaType.AssociationMembers) { if (typeof(IEntityCollection).IsAssignableFrom(association.PropertyType)) { this.VisitEntityCollection((IEntityCollection)association.GetValue(entity, null), association); } else { // Access the EntityRef - might be null if the ref hasn't been // accessed yet IEntityRef entityRef = entity.GetEntityRef(association.Name); this.VisitEntityRef(entityRef, entity, association); } } }
/// <summary> /// Invalidate the <paramref name="entity"/> in the cache. /// </summary> /// <param name="entity">The entity. This cannot be null.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="entity"/> cannot be null. /// </exception> public void InvalidateEntity(IEntityRef entity) { if (entity == null || !entity.HasId) { ///// // Ignore invalid entities. ///// return; } Trace.TraceSecurityCacheInvalidateEntity(entity.Id); // TODO // Update performance counters AccessControlCacheInvalidationCounters.GetPerformanceCounter <NumberOfItems64PerformanceCounter>( AccessControlCacheInvalidationPerformanceCounters.CountCounterName, AccessControlCacheInvalidationPerformanceCounters.EntityInstanceName).Increment(); AccessControlCacheInvalidationCounters.GetPerformanceCounter <RatePerSecond32PerformanceCounter>( AccessControlCacheInvalidationPerformanceCounters.RateCounterName, AccessControlCacheInvalidationPerformanceCounters.EntityInstanceName).Increment(); }
/// <summary> /// Maps field IDs to the database tables that they get stored in. /// </summary> /// <param name="fieldId"></param> /// <returns></returns> private FieldInfo RegisterFieldInfo(IEntityRef fieldId) { // Get/convert the type info for the field (and store for later, since we're already here) FieldInfo fieldInfo; if (!_result.FieldTypes.TryGetValue(fieldId.Id, out fieldInfo)) { // Get the field Field field = Entity.Get <Field>(fieldId.Id); fieldInfo = new FieldInfo(); _result.FieldTypes.Add(fieldId.Id, fieldInfo); fieldInfo.DatabaseType = field.ConvertToDatabaseType(); fieldInfo.IsWriteOnly = field.IsFieldWriteOnly ?? false; fieldInfo.IsCalculated = Factory.CalculatedFieldMetadataProvider.IsCalculatedField(fieldId.Id); fieldInfo.IsVirtualAccessControlField = BulkRequestHelper.IsVirtualAccessControlField(new EntityRef(fieldId)); FieldType fieldType = field.GetFieldType(); fieldInfo.DatabaseTable = string.Intern(fieldType.DbFieldTable); // intern to avoid lots of copies of the same database table names in memory } return(fieldInfo); }
void IEntityGeneric <IEntityRef> .SetField(IEntityRef field, object value) { throw new NotImplementedException( ); }
protected override void VisitEntityRef(IEntityRef entityRef, Entity parent, MetaMember member) { // Check for [ExternalReference] properties, if found we can skip visiting these // external entities so they will not be included in our change set. if (member.IsExternalReference) { return; } // We don't want to cause any deferred loading of the EntityRef in non-compositional // cases. Note that the UnmodifiedOperationAdder has already caused compositional // associations to load, so they will have values. Entity referenced = null; if (entityRef != null && entityRef.HasValue) { referenced = entityRef.Entity; } // Now determine the originally referenced entity if this association is a composition // and the child has been removed Entity prevReferenced = null; bool isComposition = member.IsComposition; if (isComposition && parent.EntityState != EntityState.New) { ChangeSetEntry entry = this.FindOriginalChildren(member.AssociationAttribute).SingleOrDefault(); if (entry != null) { prevReferenced = entry.Entity; } } if (isComposition && prevReferenced == null) { // if this is an unmodified composition, set the previously referenced entity // to the currently referenced entity prevReferenced = referenced; } // If the referenced entity is New and the parent is not Deleted or the referenced entity is a composed child and the target // is part of the changeset, set the association int refId = -1; bool shouldIncludeNewAssociation = referenced != null && (this._currentChangeSetEntry.Entity.EntityState != EntityState.Deleted && referenced.EntityState == EntityState.New); if (referenced != null && (shouldIncludeNewAssociation || isComposition) && this._entityIdMap.TryGetValue(referenced, out refId)) { // set the current reference Dictionary <string, int[]> associatedEntities = (Dictionary <string, int[]>) this._currentChangeSetEntry.Associations; if (associatedEntities == null) { associatedEntities = new Dictionary <string, int[]>(); this._currentChangeSetEntry.Associations = associatedEntities; } associatedEntities.Add(member.Name, new int[] { refId }); } // If the association is a composition, set the original reference if (prevReferenced != null && isComposition && this._entityIdMap.TryGetValue(prevReferenced, out refId)) { Dictionary <string, int[]> associatedEntities = (Dictionary <string, int[]>) this._currentChangeSetEntry.OriginalAssociations; if (associatedEntities == null) { associatedEntities = new Dictionary <string, int[]>(); this._currentChangeSetEntry.OriginalAssociations = associatedEntities; } associatedEntities.Add(member.Name, new int[] { refId }); } }
/// <summary> /// Associates and caches the provided <see cref="IEntityRef"/> for the /// specified EntityRef member. /// </summary> /// <remarks>This method is called when an EntityRef field is initialized, /// and allows us access to the field w/o resorting to private reflection.</remarks> /// <param name="memberName">The name of the EntityRef member.</param> /// <param name="entityRef">The <see cref="IEntityRef"/> to associate.</param> internal void SetEntityRef(string memberName, IEntityRef entityRef) { this.EntityRefs[memberName] = entityRef; }
/// <summary> /// Visit an <see cref="EntityRef<TEntity>"/> member /// </summary> /// <param name="entityRef">The EntityRef to visit.</param> /// <param name="parent">The parent of the reference member</param> /// <param name="propertyInfo">The <see cref="PropertyInfo"/> for the reference member</param> protected virtual void VisitEntityRef(IEntityRef entityRef, Entity parent, PropertyInfo propertyInfo) { }
protected override void VisitEntityRef(IEntityRef entityRef, Entity parent, PropertyInfo propertyInfo) { // Check for [ExternalReference] properties, if found we can skip visiting these // external entities so they will not be included in our change set. if (propertyInfo.GetCustomAttributes(typeof(ExternalReferenceAttribute), true).Any()) { return; } // We don't want to cause any deferred loading of the EntityRef in non-compositional // cases. Note that the UnmodifiedOperationAdder has already caused compositional // associations to load, so they will have values. Entity referenced = null; if (entityRef != null && entityRef.HasValue) { referenced = entityRef.Entity; } // Now determine the originally referenced entity if this association is a composition // and the child has been removed Entity prevReferenced = null; bool isComposition = propertyInfo.GetCustomAttributes(typeof(CompositionAttribute), false).Any(); if (isComposition && parent.EntityState != EntityState.New) { AssociationAttribute assocAttrib = (AssociationAttribute)propertyInfo.GetCustomAttributes(typeof(AssociationAttribute), false).Single(); ChangeSetEntry entry = this.FindOriginalChildren(assocAttrib).SingleOrDefault(); if (entry != null) { prevReferenced = entry.Entity; } } if (isComposition && prevReferenced == null) { // if this is an unmodified composition, set the previously referenced entity // to the currently referenced entity prevReferenced = referenced; } // If the referenced entity is New and the parent is not Deleted or the referenced entity is a composed child and the target // is part of the changeset, set the association int refId = -1; bool shouldIncludeNewAssociation = referenced != null && (this._currentChangeSetEntry.Entity.EntityState != EntityState.Deleted && referenced.EntityState == EntityState.New); if (referenced != null && (shouldIncludeNewAssociation || isComposition) && this._entityIdMap.TryGetValue(referenced, out refId)) { // set the current reference Dictionary<string, int[]> associatedEntities = (Dictionary<string, int[]>)this._currentChangeSetEntry.Associations; if (associatedEntities == null) { associatedEntities = new Dictionary<string, int[]>(); this._currentChangeSetEntry.Associations = associatedEntities; } associatedEntities.Add(propertyInfo.Name, new int[] { refId }); } // If the association is a composition, set the original reference if (prevReferenced != null && isComposition && this._entityIdMap.TryGetValue(prevReferenced, out refId)) { Dictionary<string, int[]> associatedEntities = (Dictionary<string, int[]>)this._currentChangeSetEntry.OriginalAssociations; if (associatedEntities == null) { associatedEntities = new Dictionary<string, int[]>(); this._currentChangeSetEntry.OriginalAssociations = associatedEntities; } associatedEntities.Add(propertyInfo.Name, new int[] { refId }); } }
void IEntityGeneric <IEntityRef> .SetRelationships(IEntityRef relationshipDefinition, IEntityRelationshipCollection relationships, Direction direction) { throw new NotImplementedException( ); }