示例#1
0
        internal readonly Func <Phase, int, PhaseStatus> _processingStatusSupplier; // internal to allow ReadOnlyCluster ctor (& record specific transform providers) use the same processingStatusSupplier

        //Note that KeyValCluster is constructed eagerly (recList will be consumed upon object creation)

        internal KeyValCluster(IEnumerable <IRecord> recList,
                               int clstrNo,
                               int startRecNo,
                               int startSourceNo,
                               IGlobalCache globalCache,
                               IDictionary <string, object> propertyBin,
                               TypeDefinitions typeDefinitions,
                               OrchestratorConfig config,
                               Func <Phase, int, PhaseStatus> processingStatusSupplier)
        {
            this.ClstrNo       = clstrNo;
            this.StartRecNo    = startRecNo;
            this.StartSourceNo = startSourceNo;
            //Note that StartSourceNo should match the 1st record, but to facilitate cloning, etc. it was decided to expose it
            // separately as ctor parm as opposed to reading it like this:  this.StartSourceNo = recList.Any() ? recList.First().SourceNo : 0;
            this._recordColl               = new RecordCollection(recList);
            this.GlobalCache               = globalCache;
            this._typeDefinitions          = typeDefinitions;
            this._config                   = config;
            this._processingStatusSupplier = processingStatusSupplier;

            //Make sure all records have the ClstrNo matching the cluster they belong to:
            this._recordColl.ForEach(r => (r as KeyValRecord)?.SetClstrNo(clstrNo));

            PropertyBin = (_config.PropertyBinEntities & PropertyBinAttachedTo.Clusters) == PropertyBinAttachedTo.Clusters
               ? propertyBin ?? new Dictionary <string, object>() //"reuse" PB in case of cloning, creation of ReadOnlyCluster wrapper, etc.
               : null;                                            //null if Clusters flag not set in PropertyBinEntities
        } //ctor
示例#2
0
        private readonly bool _fieldsCanBeAltered; //Reflects config.AllowTransformToAlterFields.
                                                   // If true, fields can be added to and removed from the record;
                                                   // if false, AddItem (flavors) and RemoveItem methods have no effect.

        /// <summary>
        /// Constructs a single record consisting of key value pairs.
        /// </summary>
        /// <param name="items">A collection of KeyValItems (a set of key value pairs) obtained from a single input record.</param>
        /// <param name="recNo">Record number, i.e. position in input data (1-based).</param>
        /// <param name="sourceNo">Index number of the source that supplied this record (1-based).</param>
        /// <param name="clstrNo">Sequential number (1-based) that the record is initially assigned (e.g. XML or JSON input); 0=undetermined;.</param>
        /// <param name="globalCache">A set of key value pairs that are common to all records and clusters throughout the process execution.</param>
        /// <param name="traceBin">The trace bin to be used by this record.</param>
        /// <param name="propertyBin">The property bin to be used by this record.</param>
        /// <param name="typeDefinitions">Field type definitions (name -> type translations).</param>
        /// <param name="config">Current orchestrator configuration.</param>
        /// <param name="processingStatusSupplier">Function to return the PhaseStatus object.</param>
        /// <param name="actionOnDuplicateKey">Action to take in case duplicate key is encountered; same as config.ActionOnDuplicateKey except for cloning.</param>
        internal KeyValRecord(IEnumerable <IItem> items,
                              int recNo,
                              int sourceNo,
                              int clstrNo,
                              IGlobalCache globalCache,
                              IReadOnlyDictionary <string, object> traceBin,
                              IDictionary <string, object> propertyBin,
                              TypeDefinitions typeDefinitions,
                              OrchestratorConfig config,
                              Func <Phase, int, PhaseStatus> processingStatusSupplier,
                              ActionOnDuplicateKey actionOnDuplicateKey)
        {
            _itemColl                 = new ItemCollection();
            GlobalCache               = globalCache;
            _typeDefinitions          = typeDefinitions;
            _config                   = config;
            _processingStatusSupplier = processingStatusSupplier;
            _fieldsCanBeAltered       = config.AllowTransformToAlterFields;
            RecNo    = recNo;
            SourceNo = sourceNo;
            TargetNo = 0; //not yet determined
            ClstrNo  = clstrNo;
            int fldNo = 0;

            foreach (IItem item in items)
            {
                fldNo++;
                var key = item.Key;
                if (_itemColl.Contains(key)) //not thread-safe, but we're in ctor so that nothing else can access _itemColl
                {
                    //Duplicate key encountered, the action is dictated by actionOnDuplicateKey
                    string msgOnDemand() => $"Duplicate key in field #{fldNo} of record #{recNo}: A key of '{item.Key.ToString()}' already exists in current record.";

                    switch (actionOnDuplicateKey)
                    {
                    case ActionOnDuplicateKey.IgnoreItem:
                        //Do nothing, except for reporting the error
                        _config.Logger.LogWarning(() => msgOnDemand() + $" Item containing value of '{item.Value.ToString()}' has been ignored.");
                        break;

                    case ActionOnDuplicateKey.ReplaceItem:
                        //remove existing item and then add the new item
                        _config.Logger.LogWarning(() => msgOnDemand() + $" Item has been replaced with a value of '{item.Value.ToString()}'.");
                        _itemColl.Remove(item.Key);
                        _itemColl.Add(item);
                        break;

                    case ActionOnDuplicateKey.ExcludeRecord:
                        //Clear the items constructed so far and exit; the caller will ignore such record
                        _itemColl.Clear();
                        _config.Logger.LogError(() => msgOnDemand() + "Record has been excluded from processing.");
                        return;

                    case ActionOnDuplicateKey.AssignDefaultKey:
                        var errMsg = "Feature to provide substitutes for duplicate keys (ActionOnDuplicateKey.AssignDefaultKey) has not been implemented.";
                        _config.Logger.LogError(() => msgOnDemand() + errMsg);
                        throw new NotImplementedException(errMsg);
                        //TODO: Implement this feature - note that any "default" value can also already exist
                    }
                    ;
                }
                else //The key is not a duplicate, so simply add the item
                {
                    _itemColl.Add(item);
                }
            } //foreach item

            TraceBin    = traceBin; //"reuse" TB in case of cloning, creation of ReadOnlyRecord wrapper, etc.
            PropertyBin = (_config.PropertyBinEntities & PropertyBinAttachedTo.Records) == PropertyBinAttachedTo.Records
                        ? propertyBin ?? new Dictionary <string, object>() //"reuse" PB in case of cloning, creation of ReadOnlyRecord wrapper, etc.
                        : null;                                            //null if Records flag not set in PropertyBinEntities
        } //ctor