This code is designed to perform a cleanup after a mailbox rehydration (from Symantec Enterprise Vault). We take a snapshot index of the MessageId
and ConversationId
of all items in the mailbox before the rehydration.
After the rehydration this code
if (string.Equals(item.ItemClass, "IPM.Note.EnterpriseVault.Shortcut", StringComparison.InvariantCulture) || ((existingIds.Any(x => x.ConversationId == item.ConversationId.ToString()) == false || (item.ItemClass == "IPM.Appointment" && existingIds.Any(x => x.MessageId == item.Id.ToString()) == false) && item.DateTimeReceived < snapshotDate)))
{
item.Delete(DeleteMode.HardDelete);
}
should delete
ItemClass
of "IPM.Note.EnterpriseVault.Shortcut"ItemClass
of "IPM.Appointment" where the Id
is not in the existingIds
list of MessageId
s, unless they were received after the `snapshotDateConversationId
is not in the existingIds
list, unless they were received after the snapshotDate
. After running this code a user reported having lost some email that was received after the snapshotDate
so it seems I have got the if
statement wrong: .( Could somebody tell me please what I have got wrong (or a way that I can break this down to understand it better) and what this code will actually have done so I can let the user know what has been lost. I know lofical ORs are notoriously hard to get write and I think I have made a mistake with the brackets somewhere but I just can't see it.
I find the easiest way to look at this sort of problem is to use lots of line breaks and indentation. I add a break and increase indentation after every (
(except trivial ()
), bring matching )
s below their matching pair and put the operators on separate lines between the items they're joining:
if (
string.Equals(
item.ItemClass,
"IPM.Note.EnterpriseVault.Shortcut", StringComparison.InvariantCulture
)
||
(
(
existingIds.Any(
x => x.ConversationId == item.ConversationId.ToString()
) == false
||
(
item.ItemClass == "IPM.Appointment"
&&
existingIds.Any(
x => x.MessageId == item.Id.ToString()
) == false
)
&&
item.DateTimeReceived < snapshotDate
)
)
)
{
item.Delete(DeleteMode.HardDelete);
}
I can immediately spot two things - there's a pair of parentheses that just contains another pair, and we have &&
and ||
occurring at the same "level" so we're relying on operator precedence.
I'm guessing you wanted the &&
outside of the inner parentheses so that it is applied against both the appointment check and the existing Ids one. Eg this instead:
if (
string.Equals(
item.ItemClass,
"IPM.Note.EnterpriseVault.Shortcut", StringComparison.InvariantCulture
)
||
(
(
existingIds.Any(
x => x.ConversationId == item.ConversationId.ToString()
) == false
||
(
item.ItemClass == "IPM.Appointment"
&&
existingIds.Any(
x => x.MessageId == item.Id.ToString()
) == false
)
)
&&
item.DateTimeReceived < snapshotDate
)
)
{
item.Delete(DeleteMode.HardDelete);
}
(Once you've confirmed everything matches up as you need, you can collapse back down to fewer lines)
I would recommend you to split if check into local functions it will be much easier to debug.
if (IsShourtcut(item) || NotExistingAppItment(item) || ExistingConversation(item) && IsReceivedBeforSnapshot(item))
{
// to delete
}
bool IsShourtcut(Item item) => string.Equals(item.ItemClass, "IPM.Note.EnterpriseVault.Shortcut", StringComparison.InvariantCulture);
bool NotExistingAppItment(Item item) => item.ItemClass == "IPM.Appointment" && existingIds.All(x => x.MessageId != item.Id.ToString());
bool ExistingConversation(Item item) => existingIds.All(x => x.ConversationId != item.ConversationId.ToString();
bool IsReceivedBeforSnapshot(Item item) => item.DateTimeReceived < snapshotDate;
Both of the other answers to this were extremely helpful and I have upvoted accordingly. However I thought I would post my final solution to this as inspired by https://stackoverflow.com/a/61009776/470014 and https://stackoverflow.com/a/61008198/470014 , leaning particularly heavily on the use of local functions as recommended by OxQ. I have now written unit tests (which I should have done earlier) and these all pass using my new method whereas five of them were failing before. I believe this code more closely matches the stated problem and is fairly straightforward to read and understand. I have had to use scalar values rather than the whole Item
object, so I can unit test this as Exchange Web Services managed API doesn't use interfaces.
switch (itemClass)
{
case "IPM.Note.EnterpriseVault.Shortcut":
return true;
case "IPM.Appointment":
return NotExistingMessage() && IsReceivedBeforeSnapshot();
default:
return NotExistingConversation() && IsReceivedBeforeSnapshot();
}
bool NotExistingMessage() => existingIds.All(x => x.MessageId != messageId);
bool NotExistingConversation() => existingIds.All(x => x.ConversationId != conversationId);
bool IsReceivedBeforeSnapshot() => dateTimeReceived < uploadDate;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.