/// <exception cref="NotSupportedException" /> protected ComparsionIndex(Expression <Func <T, TProperty> > lambda, KeyValueComparer comparer) : base(comparer) { MemberName = lambda.Body.GetMemberName(); _getKey = lambda.Body.CreateGetter <T, TProperty>(); }
/// <summary> /// If initializer is null, then every key initially maps to default(T). /// Otherwise every key k initially maps to initializer(k). /// /// If isThreadSafe = true, then reads / writes are protected by locks. /// Otherwise, reads are thread-safe as long as they are no intervening writes. /// </summary> public FixedDomMap(Set <S> keys, Func <S, T> initializer, bool isThreadSafe = false) { Contract.Requires(keys != null); keyValues = new KeyValue[keys.Count]; comparer = keys.Comparer; kvComparer = new KeyValueComparer(comparer); IsThreadSafe = isThreadSafe; int i = 0; if (initializer == null) { foreach (var k in keys) { keyValues[i++] = new KeyValue(k, default(T)); } } else { foreach (var k in keys) { keyValues[i++] = new KeyValue(k, initializer(k)); } } }
public void TestKeyValueComparer() { KeyValueComparer <int, int> cmp = new KeyValueComparer <int, int>(); Assert.IsTrue(ReferenceEquals(Comparer <int> .Default, cmp.Comparer)); Assert.IsTrue(ReferenceEquals(Comparer <int> .Default, KeyValueComparer <int, int> .Default.Comparer)); Assert.AreEqual(-1, cmp.Compare(new KeyValuePair <int, int>(1, 1), new KeyValuePair <int, int>(2, 1))); Assert.AreEqual(0, cmp.Compare(new KeyValuePair <int, int>(1, 1), new KeyValuePair <int, int>(1, 2))); Assert.AreEqual(1, cmp.Compare(new KeyValuePair <int, int>(2, 1), new KeyValuePair <int, int>(1, 1))); }
/// <summary> /// Gets all data rows which match a given key value. /// </summary> /// <param name="keyFields">Fields in the key on which the data rows should match.</param> /// <param name="data">Data from which to get data rows which match the key value.</param> /// <param name="matchingKeyValue">The key value which the data rows should match.</param> /// <returns>Data rows which match the key value.</returns> public static IEnumerable <IEnumerable <IDataObjectBase> > GetDataRowsForKeyValue(IEnumerable <IField> keyFields, IEnumerable <IEnumerable <IDataObjectBase> > data, string matchingKeyValue) { if (keyFields == null) { throw new ArgumentNullException("keyFields"); } if (data == null) { throw new ArgumentNullException("data"); } if (string.IsNullOrEmpty(matchingKeyValue)) { throw new ArgumentNullException("matchingKeyValue"); } var dataRows = data as IList <IEnumerable <IDataObjectBase> > ?? new List <IEnumerable <IDataObjectBase> >(data); var keyValues = new List <string>(GetKeyValues(keyFields, dataRows, false)); try { var keyValueComparer = new KeyValueComparer(); var matchingDataRows = new List <IEnumerable <IDataObjectBase> >(); for (var keyValueNo = 0; keyValueNo < keyValues.Count; keyValueNo++) { if (keyValueComparer.Equals(keyValues.ElementAt(keyValueNo), matchingKeyValue)) { matchingDataRows.Add(dataRows.ElementAt(keyValueNo)); } } return(matchingDataRows); } finally { while (keyValues.Count > 0) { keyValues.Clear(); } } }
public static Dictionary <String, Object> DiffGlobInfos(Dictionary <String, Object> glob1, Dictionary <String, Object> glob2) { var unique = new Dictionary <String, Object>(); var comparer = new KeyValueComparer(); var diff = ToDictionary(glob2.Except(glob1, comparer)); foreach (var pair in glob2) { if (diff.ContainsKey(pair.Key) && pair.Value != null) { if (pair.Value is Dictionary <String, Object> ) { var subdiff = glob1.ContainsKey(pair.Key) ? DiffGlobInfos((Dictionary <String, Object>)glob1[pair.Key], (Dictionary <String, Object>)pair.Value) : (Dictionary <String, Object>)pair.Value; if (subdiff.Count > 0) { //Debug.WriteLine("Replacing\n {0}\nwith\n {1}", _jss.Serialize(diff[pair.Key]), _jss.Serialize(subdiff)); diff[pair.Key] = subdiff; } else { //Debug.WriteLine("\nRemoving {0}\n", _jss.Serialize(pair.Key)); diff.Remove(pair.Key); } } else if (pair.Value is IList) { if (glob1.ContainsKey(pair.Key) && ListEquality((IList)pair.Value, (IList)glob1[pair.Key])) { diff.Remove(pair.Key); } } } } return(diff); }
/// <summary> /// Manipulates missing foreign key values for a given table. /// </summary> /// <param name="table">Tabel to manipulate data for missing foreign key values.</param> /// <param name="dataRepository">Data repository.</param> /// <param name="dataToManipulate">Data for the table where to manipulate data for missing foreign key values.</param> /// <returns>Manipulates data for the table.</returns> protected override IEnumerable <IEnumerable <IDataObjectBase> > Manipulate(ITable table, IDataRepository dataRepository, IList <IEnumerable <IDataObjectBase> > dataToManipulate) { var keyValueComparer = new KeyValueComparer(); var foreignKeyFields = _foreignKeyFields.Select(m => DataRepositoryHelper.GetTableField(table, m)).ToArray(); var foreignKeyValues = new List <string>(DataRepositoryHelper.GetKeyValues(foreignKeyFields, dataToManipulate, true).Distinct(keyValueComparer)); try { if (foreignKeyValues.Count == 0) { return(dataToManipulate); } // Try to manipulate using a data queryer. var dataQueryer = GetDataQueryer(dataRepository); if (dataQueryer != null) { var dictionaryName = GetDictionaryName(ForeignKeyTable.PrimaryKey); var keyValueFromCache = new List <string>(); var keyValuesToClear = new List <string>(); try { using (dataQueryer) { lock (SyncRoot) { if (DataCache.ContainsKey(dictionaryName) == false) { DataCache.Add(dictionaryName, new Tuple <List <string>, List <string> >(new List <string>(), new List <string>())); } if (DataCache[dictionaryName].Item1.Contains(WorkerId) == false) { DataCache[dictionaryName].Item1.Add(WorkerId); } keyValueFromCache.AddRange(DataCache[dictionaryName].Item2); } while (foreignKeyValues.Count > 0) { if (keyValueFromCache.Any(m => keyValueComparer.Equals(m, foreignKeyValues.ElementAt(0)))) { foreignKeyValues.RemoveAt(0); continue; } var dataObjects = new List <IDataObjectBase>(DataRepositoryHelper.GetDataRowsForKeyValue(foreignKeyFields, dataToManipulate, foreignKeyValues.ElementAt(0)).First()); var extraCriterias = new List <KeyValuePair <string, object> >(); try { for (var keyFieldNo = 0; keyFieldNo < Math.Min(foreignKeyFields.Count(), ForeignKeyTable.PrimaryKey.Fields.Count); keyFieldNo++) { var dataObject = DataRepositoryHelper.GetDataObject(dataObjects, foreignKeyFields.ElementAt(keyFieldNo)); var sourceValue = DataRepositoryHelper.GetSourceValue(dataObject); if (Equals(sourceValue, null)) { continue; } var nameSource = ForeignKeyTable.PrimaryKey.Fields.Select(m => m.Key).ElementAt(keyFieldNo).NameSource; var nameTarget = ForeignKeyTable.PrimaryKey.Fields.Select(m => m.Key).ElementAt(keyFieldNo).NameTarget; var foreignKeyFieldName = ForeignKeyTable.Fields.Count(m => string.Compare(m.NameSource, nameSource, StringComparison.OrdinalIgnoreCase) == 0) > 1 ? nameTarget : nameSource; extraCriterias.Add(new KeyValuePair <string, object>(foreignKeyFieldName, sourceValue)); } if (dataQueryer.GetNumberOfEqualKeyValues(ForeignKeyTable.PrimaryKey, extraCriterias, foreignKeyValues.ElementAt(0)) == 0) { keyValuesToClear.Add(foreignKeyValues.ElementAt(0)); foreignKeyValues.RemoveAt(0); continue; } lock (SyncRoot) { if (DataCache.ContainsKey(dictionaryName) == false) { foreignKeyValues.RemoveAt(0); continue; } var dataInCache = DataCache.Select(m => m.Value.Item2).Where(m => m != null).ToArray(); while (dataInCache.Sum(m => m.Count) >= MaxRowsInCache) { dataInCache.OrderByDescending(m => m.Count).First().RemoveAt(0); } DataCache[dictionaryName].Item2.Add(foreignKeyValues.ElementAt(0)); } } finally { while (extraCriterias.Count > 0) { extraCriterias.Clear(); } while (dataObjects.Count > 0) { dataObjects.Clear(); } } foreignKeyValues.RemoveAt(0); } dataQueryer.Dispose(); } return(keyValuesToClear.Count == 0 ? dataToManipulate : ClearDataRows(table, dataToManipulate, keyValuesToClear, foreignKeyFields, keyValueComparer)); } catch { RemoveFromCache(ForeignKeyTable.PrimaryKey); throw; } finally { while (keyValuesToClear.Count > 0) { keyValuesToClear.Clear(); } while (keyValueFromCache.Count > 0) { keyValueFromCache.Clear(); } } } // Manipulated without a data queryer. try { var primaryKeyValues = new List <string>(GetKeyValues(dataRepository, ForeignKeyTable.PrimaryKey, false)); try { var keyValuesToClear = new List <string>(); try { while (foreignKeyValues.Count > 0) { if (primaryKeyValues.Any(m => keyValueComparer.Equals(m, foreignKeyValues.ElementAt(0))) == false) { keyValuesToClear.Add(foreignKeyValues.ElementAt(0)); } foreignKeyValues.RemoveAt(0); } return(keyValuesToClear.Count == 0 ? dataToManipulate : ClearDataRows(table, dataToManipulate, keyValuesToClear, foreignKeyFields, keyValueComparer)); } finally { while (keyValuesToClear.Count > 0) { keyValuesToClear.Clear(); } } } finally { while (primaryKeyValues.Count > 0) { primaryKeyValues.Clear(); } } } catch { RemoveFromCache(ForeignKeyTable.PrimaryKey); throw; } } finally { while (foreignKeyValues.Count > 0) { foreignKeyValues.Clear(); } } }
/// <summary> /// Validates primary key on data for a target table. /// </summary> /// <param name="targetTable">Target table.</param> /// <param name="targetTableData">Data for the target table.</param> /// <param name="endOfData">Indicates whether this is the last data for the target table.</param> /// <param name="command">Command which to validate with.</param> protected override void ValidateData(ITable targetTable, IDictionary <ITable, IEnumerable <IEnumerable <IDataObjectBase> > > targetTableData, bool endOfData, ICommand command) { if (_disposed) { throw new ObjectDisposedException(GetType().Name); } foreach (var dataTable in targetTableData.Keys) { if (dataTable.CandidateKeys == null || dataTable.CandidateKeys.Count == 0) { throw new DeliveryEngineMetadataException(Resource.GetExceptionMessage(ExceptionMessage.MissingCandidateKeysOnTable, dataTable.NameSource), dataTable); } foreach (var candidateKey in dataTable.CandidateKeys) { if (candidateKey.Fields == null || candidateKey.Fields.Count == 0) { throw new DeliveryEngineMetadataException(Resource.GetExceptionMessage(ExceptionMessage.MissingFieldsOnCandidateKey, candidateKey.NameSource, dataTable.NameSource), candidateKey); } var keyValueComparer = new KeyValueComparer(); List <string> primaryKeyValues; // Try to validate using a data queryer. var dataQueryer = GetDataQueryer(DataRepository); if (dataQueryer != null) { using (dataQueryer) { primaryKeyValues = new List <string>(DataRepositoryHelper.GetKeyValues(candidateKey, targetTableData[dataTable], false)); try { for (var primaryKeyValueNo = 0; primaryKeyValueNo < primaryKeyValues.Count; primaryKeyValueNo++) { var dataRow = targetTableData[dataTable].ElementAt(primaryKeyValueNo); RaiseOnValidationEvent(this, new DataValidatorEventArgs(dataRow)); if (endOfData) { if (primaryKeyValues.Count(m => keyValueComparer.Equals(m, primaryKeyValues.ElementAt(primaryKeyValueNo))) == 1) { continue; } candidateKey.ValidateObjectData = dataRow; throw new DeliveryEngineValidateException(Resource.GetExceptionMessage(ExceptionMessage.UniqueConstraintViolationOnCandidateKey, candidateKey.NameSource), candidateKey); } var extraCriterias = GetExtraCriterias(candidateKey, new List <IDataObjectBase>(dataRow)); try { if (dataQueryer.GetNumberOfEqualKeyValues(candidateKey, extraCriterias, primaryKeyValues.ElementAt(primaryKeyValueNo)) == 1) { continue; } candidateKey.ValidateObjectData = dataRow; throw new DeliveryEngineValidateException(Resource.GetExceptionMessage(ExceptionMessage.UniqueConstraintViolationOnCandidateKey, candidateKey.NameSource), candidateKey); } finally { while (extraCriterias.Count > 0) { extraCriterias.Clear(); } } } } finally { while (primaryKeyValues.Count > 0) { primaryKeyValues.Clear(); } } dataQueryer.Dispose(); } continue; } // Validate without a data queryer. var dictionaryName = GetDictionaryName(candidateKey); lock (_syncRoot) { if (_dataCache.TryGetValue(dictionaryName, out primaryKeyValues) == false) { primaryKeyValues = new List <string>(); _dataCache.Add(dictionaryName, primaryKeyValues); } } var keyValues = new List <string>(DataRepositoryHelper.GetKeyValues(candidateKey, targetTableData[dataTable], false)); try { for (var keyValueNo = 0; keyValueNo < keyValues.Count; keyValueNo++) { RaiseOnValidationEvent(this, new DataValidatorEventArgs(targetTableData[dataTable].ElementAt(keyValueNo))); if (primaryKeyValues.Count(m => keyValueComparer.Equals(keyValues.ElementAt(keyValueNo), m)) + keyValues.Count(m => keyValueComparer.Equals(keyValues.ElementAt(keyValueNo), m)) == 1) { continue; } candidateKey.ValidateObjectData = targetTableData[dataTable].ElementAt(keyValueNo); throw new DeliveryEngineValidateException(Resource.GetExceptionMessage(ExceptionMessage.UniqueConstraintViolationOnCandidateKey, candidateKey.NameSource), candidateKey); } lock (_syncRoot) { _dataCache[dictionaryName].AddRange(keyValues); if (!endOfData) { continue; } while (_dataCache[dictionaryName].Count > 0) { _dataCache[dictionaryName].Clear(); } _dataCache.Remove(dictionaryName); } } finally { while (keyValues.Count > 0) { keyValues.Clear(); } } } } }
/// <summary> /// Validates foreign keys on data for a target table. /// </summary> /// <param name="targetTable">Target table.</param> /// <param name="targetTableData">Data for the target table.</param> /// <param name="endOfData">Indicates whether this is the last data for the target table.</param> /// <param name="command">Command which to validate with.</param> protected override void ValidateData(ITable targetTable, IDictionary <ITable, IEnumerable <IEnumerable <IDataObjectBase> > > targetTableData, bool endOfData, IForeignKeysValidationCommand command) { if (_disposed) { throw new ObjectDisposedException(GetType().Name); } foreach (var dataTable in targetTableData.Select(m => m.Key).Where(m => m.ForeignKeys != null && m.ForeignKeys.Count > 0)) { foreach (var foreignKey in dataTable.ForeignKeys) { if (foreignKey.CandidateKey == null) { throw new DeliveryEngineMetadataException(Resource.GetExceptionMessage(ExceptionMessage.MissingCandidateKeyOnForeignKey, foreignKey.NameSource, dataTable.NameSource), foreignKey); } if (foreignKey.CandidateKey.Fields == null || foreignKey.Fields == null || foreignKey.CandidateKey.Fields.Count != foreignKey.Fields.Count) { throw new DeliveryEngineMetadataException(Resource.GetExceptionMessage(ExceptionMessage.UnableToMatchFieldsOnForeignKey, foreignKey.CandidateKey.NameSource, foreignKey.NameSource, dataTable.NameSource), foreignKey); } var keyValueComparer = new KeyValueComparer(); var foreignKeyValues = new List <string>(DataRepositoryHelper.GetKeyValues(foreignKey, targetTableData[dataTable], true).Distinct(keyValueComparer)); if (foreignKeyValues.Count == 0) { continue; } try { var onRemove = new Action <ITable, List <IEnumerable <IDataObjectBase> > >((table, dataRowsToRemove) => { var removeMethod = targetTableData[table].GetType().GetMethod("Remove"); if (removeMethod == null) { throw new DeliveryEngineSystemException(Resource.GetExceptionMessage(ExceptionMessage.MethodNotFoundOnType, "Remove", targetTableData[table].GetType().Name)); } dataRowsToRemove.ForEach(dataRow => removeMethod.Invoke(targetTableData[table], new object[] { dataRow })); }); // Try to validate using a data queryer. var dataQueryer = GetDataQueryer(DataRepository); if (dataQueryer != null) { using (dataQueryer) { var keyValuesFromCache = new List <string>(); try { var dictionaryName = GetDictionaryName(foreignKey); lock (_syncRoot) { List <string> dataInCache; if (_dataCache.TryGetValue(dictionaryName, out dataInCache)) { while (_dataCache.ContainsKey(dictionaryName)) { _dataCache.Remove(dictionaryName); } _dataCache.Add(dictionaryName, dataInCache); } else { _dataCache.Add(dictionaryName, new List <string>()); } while (_dataCache.Count > 0 && _dataCache.Count >= command.NumberOfForeignTablesToCache && Equals(_dataCache.ElementAt(0).Key, dictionaryName) == false) { var keyName = _dataCache.ElementAt(0).Key; while (_dataCache[keyName].Count > 0) { _dataCache[keyName].Clear(); } _dataCache.Remove(keyName); } keyValuesFromCache.AddRange(_dataCache[dictionaryName]); } while (foreignKeyValues.Count > 0) { var dataRows = new List <IEnumerable <IDataObjectBase> >(DataRepositoryHelper.GetDataRowsForKeyValue(foreignKey, targetTableData[dataTable], foreignKeyValues.ElementAt(0))); try { dataRows.ForEach(dataRow => RaiseOnValidationEvent(this, new DataValidatorEventArgs(dataRow))); if (keyValuesFromCache.Any(m => keyValueComparer.Equals(m, foreignKeyValues.ElementAt(0)))) { foreignKeyValues.RemoveAt(0); continue; } var extraCriterias = new List <KeyValuePair <string, object> >(); try { for (var keyFieldNo = 0; keyFieldNo < Math.Min(foreignKey.Fields.Count, foreignKey.CandidateKey.Fields.Count); keyFieldNo++) { var dataObject = DataRepositoryHelper.GetDataObject(dataRows[0].ToList(), foreignKey.Fields.ElementAt(keyFieldNo).Key); var sourceValue = DataRepositoryHelper.GetSourceValue(dataObject); if (Equals(sourceValue, null)) { continue; } var sourceName = foreignKey.CandidateKey.Fields.ElementAt(keyFieldNo).Key.NameSource; var targetName = foreignKey.CandidateKey.Fields.ElementAt(keyFieldNo).Key.NameTarget; var foreignKeyFieldName = foreignKey.CandidateKey.Table.Fields.Count(m => string.Compare(m.NameSource, sourceName, StringComparison.OrdinalIgnoreCase) == 0) > 1 ? targetName : sourceName; extraCriterias.Add(new KeyValuePair <string, object>(foreignKeyFieldName, sourceValue)); } var equalPrimaryKeys = dataQueryer.GetNumberOfEqualKeyValues(foreignKey.CandidateKey, extraCriterias, foreignKeyValues.ElementAt(0)); HandleEqualPrimaryKeysResult(equalPrimaryKeys, dataTable, foreignKey, dataRows, command, onRemove); if (equalPrimaryKeys == 1) { lock (_syncRoot) { if (_dataCache.ContainsKey(dictionaryName) == false) { foreignKeyValues.RemoveAt(0); continue; } while (_dataCache.Select(m => m.Value).Sum(m => m.Count) >= 8192) { _dataCache.Select(m => m.Value).Where(m => m.Count > 0).OrderByDescending(m => m.Count).First().RemoveAt(0); } _dataCache[dictionaryName].Add(foreignKeyValues.ElementAt(0)); } } } finally { while (extraCriterias.Count > 0) { extraCriterias.Clear(); } } } finally { while (dataRows.Count > 0) { dataRows.Clear(); } } foreignKeyValues.RemoveAt(0); } } finally { while (keyValuesFromCache.Count > 0) { keyValuesFromCache.Clear(); } } dataQueryer.Dispose(); } continue; } // Validate without a data queryer. var primaryKeyValues = GetForeignKeyValues(foreignKey.CandidateKey, command.NumberOfForeignTablesToCache); while (foreignKeyValues.Count > 0) { var dataRows = new List <IEnumerable <IDataObjectBase> >(DataRepositoryHelper.GetDataRowsForKeyValue(foreignKey, targetTableData[dataTable], foreignKeyValues.ElementAt(0))); try { dataRows.ForEach(dataRow => RaiseOnValidationEvent(this, new DataValidatorEventArgs(dataRow))); var equalPrimaryKeys = primaryKeyValues.Count(m => keyValueComparer.Equals(foreignKeyValues.ElementAt(0), m)); HandleEqualPrimaryKeysResult(equalPrimaryKeys, dataTable, foreignKey, dataRows, command, onRemove); } finally { while (dataRows.Count > 0) { dataRows.Clear(); } } foreignKeyValues.RemoveAt(0); } } finally { while (foreignKeyValues.Count > 0) { foreignKeyValues.Clear(); } } } } }
/// <summary> /// Finalize missing foreign key values for a given table. /// </summary> /// <param name="table">Table to finalize data manipulation for missing foreign key values.</param> /// <param name="dataRepository">Data repository.</param> /// <param name="dataToManipulate">The last manipulated data which has been received.</param> /// <returns>Finalized and manipulated data for the table.</returns> protected override IEnumerable <IEnumerable <IDataObjectBase> > Finalize(ITable table, IDataRepository dataRepository, IList <IEnumerable <IDataObjectBase> > dataToManipulate) { var dictionaryName = GetDictionaryName(table.PrimaryKey); var workerDictionaryName = string.Format("{0} - {1}", dictionaryName, WorkerId); var primaryKeyValues = new List <string>(); try { // Restore primary key values from the cache. lock (SyncRoot) { if (DataCache.ContainsKey(workerDictionaryName) == false) { return(dataToManipulate); } primaryKeyValues.AddRange(DataCache[workerDictionaryName].Item1); while (DataCache[workerDictionaryName].Item1.Count > 0) { DataCache[workerDictionaryName].Item1.Clear(); } DataCache.Remove(workerDictionaryName); } // Add missing foreign key values. var clonedForeignKeyTable = GetForeignTableWithNotNullCriteria(ForeignKeyTable, _foreignKeyFields.Last()); try { var keyValueComparer = new KeyValueComparer(); var foreignKeyValues = new List <string>(DataRepositoryHelper.GetKeyValues(dataRepository, clonedForeignKeyTable, _foreignKeyFields, true).Distinct(keyValueComparer)); try { var keyValuesToCreate = new List <string>(foreignKeyValues.Where(m => primaryKeyValues.Count(n => keyValueComparer.Equals(m, n)) == 0)); try { AddMissingRows(table, dataToManipulate, keyValuesToCreate); } finally { while (keyValuesToCreate.Count > 0) { keyValuesToCreate.Clear(); } } } finally { while (foreignKeyValues.Count > 0) { foreignKeyValues.Clear(); } } return(dataToManipulate); } finally { clonedForeignKeyTable = null; Debug.Assert(clonedForeignKeyTable == null); GC.Collect(); } } finally { while (primaryKeyValues.Count > 0) { primaryKeyValues.Clear(); } // Remove primary key values from the cache. lock (SyncRoot) { while (DataCache.ContainsKey(workerDictionaryName)) { while (DataCache[workerDictionaryName].Item1.Count > 0) { DataCache[workerDictionaryName].Item1.Clear(); } DataCache.Remove(workerDictionaryName); } } RemoveFromCache(table.PrimaryKey); } }
/// <summary> /// Get the number of equal key values for a given key. /// </summary> /// <param name="key">Key on which to calculate equal number of key values.</param> /// <param name="extraCriterias">Extra criterias (field name and value) to put into the record filter when querying for number of equal key values.</param> /// <param name="matchingKeyValue">The key value on which to calculate the number of equal key values.</param> /// <returns>Number of equal key values for the key.</returns> public virtual int GetNumberOfEqualKeyValues(IKey key, IEnumerable <KeyValuePair <string, object> > extraCriterias, string matchingKeyValue) { if (key == null) { throw new ArgumentNullException("key"); } if (extraCriterias == null) { throw new ArgumentNullException("extraCriterias"); } if (string.IsNullOrEmpty(matchingKeyValue)) { throw new ArgumentNullException("matchingKeyValue"); } var table = key.Table; if (table == null) { throw new DeliveryEngineMetadataException(Resource.GetExceptionMessage(ExceptionMessage.IllegalValue, table, "Table"), key); } var clonedTable = (ITable)table.Clone(); var addCriterias = new List <KeyValuePair <string, object> >(extraCriterias.ToList()); try { foreach (var extraCriteria in addCriterias) { var field = DataRepositoryHelper.GetTableField(clonedTable, extraCriteria.Key); if (clonedTable.RecordFilters.Count == 0) { clonedTable.AddRecordFilter(new Filter()); } foreach (var recordFilter in clonedTable.RecordFilters) { recordFilter.AddCriteria(DataRepositoryHelper.BuildEqualCriteria(field, extraCriteria.Value)); } } var selectCountForTable = SelectCountForTable(clonedTable); if (selectCountForTable == 1) { return(selectCountForTable); } var numberOfEqualKeyValues = 0; GetData(clonedTable, (sender, eventArgs) => { if (eventArgs == null) { throw new ArgumentNullException("eventArgs"); } var keyFields = new List <IField>(key.Fields.Select(m => m.Key).Select(keyField => DataRepositoryHelper.GetTableField(eventArgs.Table, keyField.NameTarget ?? keyField.NameSource))); IList <string> keyValues; var keyValueComparer = new KeyValueComparer(); if (_dataManipulators == null) { keyValues = new List <string>(DataRepositoryHelper.GetKeyValues(keyFields, eventArgs.Data, false)); try { numberOfEqualKeyValues += keyValues.Count(keyValue => keyValueComparer.Equals(keyValue, matchingKeyValue)); } finally { while (keyValues.Count > 0) { keyValues.Clear(); } keyValues = null; Debug.Assert(keyValues == null); while (keyFields.Count > 0) { keyFields.Clear(); } keyFields = null; Debug.Assert(keyFields == null); } return; } var manipulatedData = eventArgs.Data; var myDataManipulators = _dataManipulators.Where(m => (string.IsNullOrEmpty(eventArgs.Table.NameTarget) == false && m.IsManipulatingTable(eventArgs.Table.NameTarget)) || (string.IsNullOrEmpty(eventArgs.Table.NameSource) == false && m.IsManipulatingTable(eventArgs.Table.NameSource))).ToArray(); foreach (var dataManipulator in myDataManipulators) { if (keyFields.Any(keyField => (string.IsNullOrEmpty(keyField.NameTarget) == false && dataManipulator.IsManipulatingField(keyField.NameTarget)) || (string.IsNullOrEmpty(keyField.NameSource) == false && dataManipulator.IsManipulatingField(keyField.NameSource))) == false) { continue; } if (dataManipulator is IMissingForeignKeyHandler) { continue; } manipulatedData = dataManipulator.ManipulateData(eventArgs.Table, manipulatedData); if (eventArgs.EndOfData) { manipulatedData = dataManipulator.FinalizeDataManipulation(eventArgs.Table, manipulatedData); } } keyValues = new List <string>(DataRepositoryHelper.GetKeyValues(keyFields, manipulatedData, false)); try { numberOfEqualKeyValues += keyValues.Count(keyValue => keyValueComparer.Equals(keyValue, matchingKeyValue)); if (numberOfEqualKeyValues > 0 || eventArgs.EndOfData == false) { return; } // ReSharper disable LoopCanBeConvertedToQuery foreach (var missingForeignKeyHandler in myDataManipulators.OfType <IMissingForeignKeyHandler>()) { if (keyFields.Any(keyField => (string.IsNullOrEmpty(keyField.NameTarget) == false && missingForeignKeyHandler.IsManipulatingField(keyField.NameTarget)) || (string.IsNullOrEmpty(keyField.NameSource) == false && missingForeignKeyHandler.IsManipulatingField(keyField.NameSource))) == false) { continue; } if (missingForeignKeyHandler.Worker is IPrimaryKeyAdder) { numberOfEqualKeyValues += Convert.ToInt32(addCriterias.Any() == false); } } // ReSharper restore LoopCanBeConvertedToQuery } finally { while (keyValues.Count > 0) { keyValues.Clear(); } keyValues = null; Debug.Assert(keyValues == null); while (keyFields.Count > 0) { keyFields.Clear(); } keyFields = null; Debug.Assert(keyFields == null); } }); if (numberOfEqualKeyValues == 1 || addCriterias.Any() == false) { return(numberOfEqualKeyValues); } var newCriterias = new List <KeyValuePair <string, object> >(addCriterias.GetRange(0, addCriterias.Count - 1)); try { if (_dataManipulators != null) { var tableNameTarget = key.Table.NameTarget; var tableNameSource = key.Table.NameSource; var retry = _dataManipulators.Any(dataManipulator => { if (string.IsNullOrEmpty(tableNameTarget) == false && dataManipulator.IsManipulatingTable(tableNameTarget)) { return(dataManipulator.IsManipulatingField(addCriterias.Last().Key) || newCriterias.Select(newCriteria => newCriteria.Key).Any(dataManipulator.IsManipulatingField)); } if (string.IsNullOrEmpty(tableNameSource) == false && dataManipulator.IsManipulatingTable(tableNameSource)) { return(dataManipulator.IsManipulatingField(addCriterias.Last().Key) || newCriterias.Select(newCriteria => newCriteria.Key).Any(dataManipulator.IsManipulatingField)); } return(false); }); if (retry) { return(GetNumberOfEqualKeyValues(key, newCriterias, matchingKeyValue)); } } if (newCriterias.Count == 0 && clonedTable.RecordFilters.Any(recordFilter => recordFilter.Criterias.Take(recordFilter.Criterias.Count - 1).OfType <IFieldCriteria>().Any(criteria => criteria.Field != null && (string.Compare(addCriterias.Last().Key, criteria.Field.NameSource, StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(addCriterias.Last().Key, criteria.Field.NameTarget, StringComparison.OrdinalIgnoreCase) == 0)))) { return(numberOfEqualKeyValues); } return(newCriterias.Count == key.Fields.Count - 1 ? GetNumberOfEqualKeyValues(key, newCriterias, matchingKeyValue) : numberOfEqualKeyValues); } finally { while (newCriterias.Count > 0) { newCriterias.Clear(); } newCriterias = null; Debug.Assert(newCriterias == null); } } finally { while (addCriterias.Count > 0) { addCriterias.Clear(); } clonedTable = null; Debug.Assert(clonedTable == null); } }