/// <summary> /// Deletes the messages matching the messagefilter passed in /// </summary> /// <param name="messageFilter">The message filter.</param> /// <param name="adapter">The adapter to use for persistence activity.</param> /// <remarks>The caller has to have started a transaction on the passed in adapter</remarks> private static async Task DeleteMessagesAsync(IPredicate messageFilter, IDataAccessAdapter adapter) { // first delete all audit info for these message. This isn't done by a batch call directly on the db, as this is a targetperentity hierarchy // which can't be deleted directly into the database in all cases, so we first fetch the entities to delete. var qf = new QueryFactory(); var q = qf.AuditDataMessageRelated.Where(AuditDataMessageRelatedFields.MessageID.In(qf.Create() .Select(MessageFields.MessageID) .Where(messageFilter))); var messageAudits = await adapter.FetchQueryAsync(q).ConfigureAwait(false); await adapter.DeleteEntityCollectionAsync(messageAudits).ConfigureAwait(false); // Threadstatistics are already considered removed. // delete all attachments for this message. This can be done directly onto the db. await adapter.DeleteEntitiesDirectlyAsync(typeof(AttachmentEntity), new RelationPredicateBucket(AttachmentFields.MessageID.In(qf.Create() .Select(MessageFields.MessageID) .Where(messageFilter)))) .ConfigureAwait(false); await adapter.DeleteEntitiesDirectlyAsync(typeof(MessageEntity), new RelationPredicateBucket(messageFilter)).ConfigureAwait(false); // don't commit the transaction, leave that to the caller. }
/// <summary> /// Deletes the threads matching the passed in filter, inside the transaction specified. /// </summary> /// <param name="threadFilter">The thread filter.</param> /// <param name="adapter">The adapter to use in this method, has a live transaction.</param> private static async Task DeleteThreadsAsync(PredicateExpression threadFilter, IDataAccessAdapter adapter) { var qf = new QueryFactory(); // we've to perform a set of actions in a given order to make sure we're not violating FK constraints in the DB. // First thread statistics for the threads matching the specified threadfilter. await adapter.DeleteEntitiesDirectlyAsync(typeof(ThreadStatisticsEntity), new RelationPredicateBucket(ThreadStatisticsFields.ThreadID.In(qf.Thread.Where(threadFilter) .Select(ThreadFields.ThreadID)))) .ConfigureAwait(false); // then the messages, which refer to threads await MessageManager.DeleteAllMessagesInThreadsAsync(threadFilter, adapter); // delete bookmarks (if exists) of the threads to be deleted await adapter.DeleteEntitiesDirectlyAsync(typeof(BookmarkEntity), new RelationPredicateBucket(BookmarkFields.ThreadID.In(qf.Thread.Where(threadFilter) .Select(ThreadFields.ThreadID)))) .ConfigureAwait(false); // delete audit info related to this thread. Can't be done directly on the db due to the fact the entities are in a TargetPerEntity hierarchy, which // can't be deleted directly on the db, so we've to fetch the entities first. var q = qf.AuditDataThreadRelated.Where(AuditDataThreadRelatedFields.ThreadID.In(qf.Thread.Where(threadFilter).Select(ThreadFields.ThreadID))); var threadAuditData = await adapter.FetchQueryAsync(q).ConfigureAwait(false); await adapter.DeleteEntityCollectionAsync(threadAuditData).ConfigureAwait(false); // delete support queue thread entity for this thread (if any) await adapter.DeleteEntitiesDirectlyAsync(typeof(SupportQueueThreadEntity), new RelationPredicateBucket(SupportQueueThreadFields.ThreadID.In(qf.Thread.Where(threadFilter) .Select(ThreadFields.ThreadID)))) .ConfigureAwait(false); // delete threadsubscription entities await adapter.DeleteEntitiesDirectlyAsync(typeof(ThreadSubscriptionEntity), new RelationPredicateBucket(ThreadSubscriptionFields.ThreadID.In(qf.Thread.Where(threadFilter) .Select(ThreadFields.ThreadID)))) .ConfigureAwait(false); // delete the threads themselves, using the filter passed in await adapter.DeleteEntitiesDirectlyAsync(typeof(ThreadEntity), new RelationPredicateBucket(threadFilter)).ConfigureAwait(false); // don't commit the transaction, that's up to the caller. }