private bool IsProcessedAfterAllAssociatedEntities(EntityInsertAction action, int latestBatchNumberForType) { var propertyValues = action.State; var propertyTypes = action.Persister.ClassMetadata.PropertyTypes; for (var i = 0; i < propertyValues.Length; i++) { var value = propertyValues[i]; var type = propertyTypes[i]; if (type.IsEntityType && value != null) { // find the batch number associated with the current association, if any. int associationBatchNumber; if (_entityBatchNumber.TryGetValue(value, out associationBatchNumber) && associationBatchNumber > latestBatchNumberForType) { return(false); } } } return(true); }
private int GetBatchNumber(EntityInsertAction action, string entityName) { int batchNumber; if (_latestBatches.TryGetValue(entityName, out batchNumber)) { // There is already an existing batch for this type of entity. // Check to see if the latest batch is acceptable. if (IsProcessedAfterAllAssociatedEntities(action, batchNumber)) { return(batchNumber); } } // add an entry for this type of entity. // we can be assured that all referenced entities have already // been processed, // so specify that this entity is with the latest batch. // doing the batch number before adding the name to the list is // a faster way to get an accurate number. batchNumber = _actionBatches.Count; _latestBatches[entityName] = batchNumber; return(batchNumber); }
private void UpdateChildrenDependencies(int batchNumber, EntityInsertAction action) { var propertyValues = action.State; var propertyTypes = action.Persister.EntityMetamodel?.PropertyTypes; if (propertyTypes == null) { log.WarnFormat( "Entity {0} persister does not provide meta-data: if there is dependent entities providing " + "meta-data, they may get batched before this one and cause a failure.", action.EntityName); return; } var sessionFactory = action.Session.Factory; for (var i = 0; i < propertyValues.Length; i++) { var type = propertyTypes[i]; if (!type.IsCollectionType) { continue; } var collectionType = (CollectionType)type; var collectionPersister = sessionFactory.GetCollectionPersister(collectionType.Role); if (collectionPersister.IsManyToMany || !collectionPersister.ElementType.IsEntityType) { continue; } var children = propertyValues[i] as IEnumerable; if (children == null) { continue; } foreach (var child in children) { if (child == null) { continue; } int latestDependency; if (_entityBatchDependency.TryGetValue(child, out latestDependency) && latestDependency > batchNumber) { continue; } _entityBatchDependency[child] = batchNumber; } } }
private void AddToBatch(int batchNumber, EntityInsertAction action) { List <EntityInsertAction> actions; if (!_actionBatches.TryGetValue(batchNumber, out actions)) { actions = new List <EntityInsertAction>(); _actionBatches[batchNumber] = actions; } actions.Add(action); }
private bool RequireNewBatch(EntityInsertAction action, int latestBatchNumberForType) { // This method assumes the original action list is already sorted in order to respect dependencies. var propertyValues = action.State; var propertyTypes = action.Persister.EntityMetamodel?.PropertyTypes; if (propertyTypes == null) { log.InfoFormat( "Entity {0} persister does not provide meta-data, giving up batching grouping optimization for this entity.", action.EntityName); // Cancel grouping optimization for this entity. return(true); } int latestDependency; if (_entityBatchDependency.TryGetValue(action.Instance, out latestDependency) && latestDependency > latestBatchNumberForType) { return(true); } for (var i = 0; i < propertyValues.Length; i++) { var value = propertyValues[i]; var type = propertyTypes[i]; if (type.IsEntityType && value != null) { // find the batch number associated with the current association, if any. int associationBatchNumber; if (_entityBatchNumber.TryGetValue(value, out associationBatchNumber) && associationBatchNumber > latestBatchNumberForType) { return(true); } } } return(false); }
public void AddAction(EntityInsertAction action) { insertions.Add(action); }
//Order the {@link #insertions} queue such that we group inserts //against the same entity together (without violating constraints). The //original order is generated by cascade order, which in turn is based on //the directionality of foreign-keys. So even though we will be changing //the ordering here, we need to make absolutely certain that we do not //circumvent this FK ordering to the extent of causing constraint //violations private void SortInsertActions() { // IMPLEMENTATION NOTES: // // The main data structure in this ordering algorithm is the 'positionToAction' // map. Essentially this can be thought of as an put-ordered map (the problem with // actually implementing it that way and doing away with the 'nameList' is that // we'd end up having potential duplicate key values). 'positionToAction' maintains // a mapping from a position within the 'nameList' structure to a "partial queue" // of actions. Dictionary <int, List <EntityInsertAction> > positionToAction = new Dictionary <int, List <EntityInsertAction> >(); List <string> nameList = new List <string>(); while (!(insertions.Count == 0)) { // todo-events : test behaviour // in Java they use an implicit cast to EntityInsertAction // but it may be not work because the insertions list may contain EntityIdentityInsertAction // (I don't like that "goto"too) object tempObject = insertions[0]; insertions.RemoveAt(0); EntityInsertAction action = (EntityInsertAction)tempObject; string thisEntityName = action.EntityName; // see if we have already encountered this entity-name... if (!nameList.Contains(thisEntityName)) { // we have not, so create the proper entries in nameList and positionToAction List <EntityInsertAction> segmentedActionQueue = new List <EntityInsertAction>(); segmentedActionQueue.Add(action); nameList.Add(thisEntityName); positionToAction[nameList.IndexOf(thisEntityName)] = segmentedActionQueue; } else { // we have seen it before, so we need to determine if this insert action is // is dependent upon a previously processed action in terms of FK // relationships (this FK checking is done against the entity's property-state // associated with the action...) int lastPos = nameList.LastIndexOf(thisEntityName); object[] states = action.State; for (int i = 0; i < states.Length; i++) { for (int j = 0; j < nameList.Count; j++) { List <EntityInsertAction> tmpList = positionToAction[j]; for (int k = 0; k < tmpList.Count; k++) { EntityInsertAction checkAction = tmpList[k]; if (checkAction.Instance == states[i] && j > lastPos) { // 'checkAction' is inserting an entity upon which 'action' depends... // note: this is an assumption and may not be correct in the case of one-to-one List <EntityInsertAction> segmentedActionQueue = new List <EntityInsertAction>(); segmentedActionQueue.Add(action); nameList.Add(thisEntityName); positionToAction[nameList.LastIndexOf(thisEntityName)] = segmentedActionQueue; goto loopInsertion; } } } } List <EntityInsertAction> actionQueue = positionToAction[lastPos]; actionQueue.Add(action); } loopInsertion :; } // now iterate back through positionToAction map and move entityInsertAction back to insertion list for (int p = 0; p < nameList.Count; p++) { List <EntityInsertAction> actionQueue = positionToAction[p]; foreach (EntityInsertAction action in actionQueue) { insertions.Add(action); } } }