Пример #1
0
 public MochaRelationship this[RelationshipKey key]
 {
     get
     {
         if (_itemsByKey.ContainsKey(key))
         {
             return(_itemsByKey[key]);
         }
         return(null);
     }
 }
Пример #2
0
        /// <summary>
        /// Try to load a relationship.
        /// </summary>
        /// <returns>True if the value was loaded, or if the value was originally requested. False if it was never originally loaded.</returns>
        public virtual bool TryGetRelationship(long entityId, long relTypeId, Direction direction, out IReadOnlyCollection <long> resultValues)
        {
            long            relTypeAndDir = direction == Direction.Forward ? relTypeId : -relTypeId;
            RelationshipKey key           = new RelationshipKey(entityId, relTypeAndDir);

            List <long> values;

            if (!_unsecuredGraphData.Relationships.TryGetValue(key, out values))
            {
                resultValues = Empty;
                bool wasRequested = WasRelationshipRequested(entityId, relTypeId, direction);
                return(wasRequested);
            }

            resultValues = values;
            return(true);
        }
Пример #3
0
        /// <summary>
        ///     Scan for document token fields.
        /// </summary>
        private void LoadDocumentCaches(IProcessingContext context)
        {
            _binaryCache   = new List <BinaryDataEntry>( );
            _documentCache = new List <DocumentDataEntry>( );

            HashSet <string> tokensDone = new HashSet <string>( );

            // GUID for fileDataHash field.
            long fileDataHash = new EntityRef("fileDataHash").Id;
            long isOfType     = WellKnownAliases.CurrentTenant.IsOfType;

            // Determine types that are 'binary'. Others are 'document'.
            ISet <long> fileTypes     = PerTenantEntityTypeCache.Instance.GetDescendantsAndSelf(new EntityRef("fileType").Id);
            ISet <long> binaryTypes   = PerTenantEntityTypeCache.Instance.GetDescendantsAndSelf(new EntityRef("imageFileType").Id);
            ISet <long> documentTypes = new HashSet <long>(fileTypes.Except(binaryTypes));

            // Callbacks to load data
            Func <string, byte[]> loadDocumentData = token => FileRepositoryUtils.LoadFileData(Factory.DocumentFileRepository, token, context);
            Func <string, byte[]> loadBinaryData   = token => FileRepositoryUtils.LoadFileData(Factory.BinaryFileRepository, token, context);

            foreach (KeyValuePair <FieldKey, FieldValue> field in _bulkResult.FieldValues)
            {
                if (field.Key.FieldId != fileDataHash)
                {
                    continue;
                }

                // Get token
                string token = field.Value?.RawValue as string;
                if (string.IsNullOrEmpty(token))
                {
                    continue;
                }

                if (tokensDone.Contains(token))
                {
                    continue;
                }
                tokensDone.Add(token);

                // Get entity type
                long            entityId   = field.Key.EntityId;
                RelationshipKey typeRelKey = new RelationshipKey(entityId, isOfType);
                List <long>     types;
                _bulkResult.Relationships.TryGetValue(typeRelKey, out types);
                long?singleType = types?.FirstOrDefault( );
                if (singleType == null)
                {
                    continue;
                }
                long typeId = singleType.Value;

                // Determine type
                bool isBinary = binaryTypes.Contains(typeId);
                bool isDoc    = documentTypes.Contains(typeId);

                // Create entry
                if (isBinary)
                {
                    var binaryDataEntry = new BinaryDataEntry
                    {
                        DataHash         = token,
                        LoadDataCallback = loadBinaryData
                    };

                    _binaryCache.Add(binaryDataEntry);
                }
                else if (isDoc)
                {
                    var docDataEntry = new DocumentDataEntry
                    {
                        DataHash         = token,
                        LoadDataCallback = loadDocumentData
                    };

                    _documentCache.Add(docDataEntry);
                }
            }
        }
Пример #4
0
        /// <summary>
        ///     Load relationships.
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public IEnumerable <RelationshipEntry> GetRelationships(IProcessingContext context)
        {
            if (_relationshipCache != null)
            {
                return(_relationshipCache);
            }

            // Create relationship entries
            _relationshipCache = new List <RelationshipEntry>( );
            foreach (var pair in _bulkResult.Relationships)
            {
                long        originId     = pair.Key.EntityId;
                long        relTypeId    = pair.Key.TypeId;
                Direction   direction    = pair.Key.Direction;
                List <long> destinations = pair.Value;

                // Security check source
                if (!_canRead(originId))
                {
                    continue;
                }

                // Determine the clone action
                RelationshipInfo relInfo;
                if (!_bulkResult.BulkSqlQuery.Relationships.TryGetValue(pair.Key.TypeIdAndDirection, out relInfo))
                {
                    continue; // assert false
                }
                var effectiveCloneAction = direction == Direction.Forward ? relInfo.CloneAction : relInfo.ReverseCloneAction;

                // If the cloneAction is a drop, then the export action is ordinarily also a drop
                // However, if the cloneAction is the other direction is a clone entities, then it must actually be a single component, and this is
                // the scenario where export&clone behave differently. Clone drops because it must to maintain cardinality, but the reference
                // still makes sense for an export. See #28790
                if (effectiveCloneAction == CloneActionEnum_Enumeration.Drop)
                {
                    var oppCloneAction = direction == Direction.Forward ? relInfo.ReverseCloneAction : relInfo.CloneAction;
                    if (oppCloneAction == CloneActionEnum_Enumeration.CloneEntities)
                    {
                        effectiveCloneAction = CloneActionEnum_Enumeration.CloneReferences;
                    }
                }

                bool isDrop = effectiveCloneAction == CloneActionEnum_Enumeration.Drop;

                // Prepare to handle duplicate entries
                bool wouldDiscardIfDuplicate = WouldDiscardIfDuplicate(relInfo, direction);

                // Resolve IDs
                Guid originUid;
                Guid relTypeUid;
                if (!_idToUpgradeId.TryGetValue(originId, out originUid))
                {
                    continue;
                }
                if (!_idToUpgradeId.TryGetValue(relTypeId, out relTypeUid))
                {
                    continue;
                }

                // Add each entry
                foreach (long destId in destinations)
                {
                    // If clone action is 'drop' then only include the relationship if the target is also present in the dataset
                    if (isDrop)
                    {
                        EntityValue entityValue;
                        if (!_bulkResult.AllEntities.TryGetValue(destId, out entityValue))
                        {
                            continue; // assert false
                        }
                        if (IsReferenceOnly(entityValue))
                        {
                            continue; // external node when cloneAction is drop
                        }
                    }

                    // If relationship is present in both directions, then drop the reverse
                    if (wouldDiscardIfDuplicate)
                    {
                        RelationshipKey reverseKey = new RelationshipKey(destId, -pair.Key.TypeIdAndDirection);
                        List <long>     reverseIds;
                        if (_bulkResult.Relationships.TryGetValue(reverseKey, out reverseIds))
                        {
                            if (reverseIds.Contains(originId))
                            {
                                continue;
                            }
                        }
                    }

                    Guid destUid;
                    if (!_idToUpgradeId.TryGetValue(destId, out destUid))
                    {
                        continue;
                    }

                    RelationshipEntry entry;
                    if (direction == Direction.Forward)
                    {
                        entry = new RelationshipEntry(relTypeUid, originUid, destUid);
                    }
                    else
                    {
                        entry = new RelationshipEntry(relTypeUid, destUid, originUid);
                    }
                    _relationshipCache.Add(entry);
                }
            }

            return(_relationshipCache);
        }
    /*==========================================================================================================================
    | CONSTRUCTOR
    \-------------------------------------------------------------------------------------------------------------------------*/
    /// <summary>
    ///   Given a <see cref="PropertyInfo"/> instance, exposes a set of properties associated with known <see cref="Attribute"/>
    ///   instances.
    /// </summary>
    /// <param name="property">The <see cref="PropertyInfo"/> instance to check for <see cref="Attribute"/> values.</param>
    /// <param name="attributePrefix">The prefix to apply to the attributes.</param>
    public PropertyConfiguration(PropertyInfo property, string? attributePrefix = "") {

      /*------------------------------------------------------------------------------------------------------------------------
      | Validate parameters
      \-----------------------------------------------------------------------------------------------------------------------*/
      Contract.Requires(property, nameof(property));

      /*------------------------------------------------------------------------------------------------------------------------
      | Set backing property
      \-----------------------------------------------------------------------------------------------------------------------*/
      Property = property;

      /*------------------------------------------------------------------------------------------------------------------------
      | Set default values
      \-----------------------------------------------------------------------------------------------------------------------*/
      AttributeKey              = attributePrefix + property.Name;
      AttributePrefix           = attributePrefix;
      DefaultValue              = null;
      InheritValue              = false;
      RelationshipKey           = AttributeKey;
      RelationshipType          = RelationshipType.Any;
      CrawlRelationships        = Relationships.None;
      MetadataKey               = null;
      DisableMapping            = false;
      AttributeFilters          = new();
      FlattenChildren           = false;

      /*------------------------------------------------------------------------------------------------------------------------
      | Attributes: Retrieve basic attributes
      \-----------------------------------------------------------------------------------------------------------------------*/
      GetAttributeValue<DefaultValueAttribute>(property,        a => DefaultValue = a.Value);
      GetAttributeValue<InheritAttribute>(property,             a => InheritValue = true);
      GetAttributeValue<AttributeKeyAttribute>(property,        a => AttributeKey = attributePrefix + a.Value);
      GetAttributeValue<MapToParentAttribute>(property,         a => MapToParent = true);
      GetAttributeValue<MapToParentAttribute>(property,         a => AttributePrefix += (a.AttributePrefix?? property.Name));
      GetAttributeValue<FollowAttribute>(property,              a => CrawlRelationships = a.Relationships);
      GetAttributeValue<FlattenAttribute>(property,             a => FlattenChildren = true);
      GetAttributeValue<MetadataAttribute>(property,            a => MetadataKey = a.Key);
      GetAttributeValue<DisableMappingAttribute>(property,      a => DisableMapping = true);

      /*------------------------------------------------------------------------------------------------------------------------
      | Attributes: Determine relationship key and type
      \-----------------------------------------------------------------------------------------------------------------------*/
      GetAttributeValue<RelationshipAttribute>(
        property,
        a => {
          RelationshipKey = a.Key ?? RelationshipKey;
          RelationshipType = a.Type;
        }
      );

      if (
        RelationshipType is RelationshipType.Any &&
        RelationshipKey.Equals("Children", StringComparison.InvariantCultureIgnoreCase)
      ) {
        RelationshipType = RelationshipType.Children;
      }

      /*------------------------------------------------------------------------------------------------------------------------
      | Attributes: Set attribute filters
      \-----------------------------------------------------------------------------------------------------------------------*/
      var filterByAttribute = property.GetCustomAttributes<FilterByAttributeAttribute>(true);
      if (filterByAttribute is not null && filterByAttribute.Any()) {
        foreach (var filter in filterByAttribute) {
          AttributeFilters.Add(filter.Key, filter.Value);
        }
      }

    }