Analysis and explanation
There are several scenarios that may occur in the code you have posted. Below, I will only analyze the scenario that will lead to the problem you are experiencing.
Contact A is found in the Collection database by its email address:
var contact = _repository.LoadContactReadOnly(Email);
It is returned from the method GetXdbContact
and saved to the variable currentContact
.
Contact B is loaded by its ID. It is then available as lockResult.Object
.
lockResult = XdbContactManager.TryLoadContact(currentContact.ContactId);
As you can see, it is very possible that you can load two different contacts: one by its Email, the other by its ID. While contact A is guaranteed to have an identifier (that's how you found it), contact B may well be unidentified. Obviously, the two contacts in this scenario will be completely unrelated to each other.
Suggested solution
From your code, I can deduce that you are trying to update some contact fields without knowing whether the contact currently has a live session. I propose the following approach to this.
First, create a method that updates a given contact's fields, and does nothing else. We'll use this method to work with contacts that come from the session, from the tracker, or from the database.
public void UpdateContactData(Contact contact)
{
// set contact fields, facets, etc.
}
Then, in a more or less reliable way, you can use the following method to find the contact by its identifier, update its fields, and put it back to whatever storage we found it in:
void UpdateContact(string identifier, Action<Contact> updateMethod)
{
var contactRepository = (ContactRepositoryBase)Factory.CreateObject("contactRepository", true);
var sharedSessionManager = (SharedSessionStateManager)Factory.CreateObject("tracking/sharedSessionState/manager", true)
if (Tracker.Current.Contact != null && Tracker.Current.Contact.Identifiers.Identifier == identifier)
{
// The current contact is the one we need to update.
updateMethod(Tracker.Current.Contact);
}
else
{
// Find out if a contact with the given identifier exists in the database.
Contact databaseContact = contactRepository.LoadContactReadOnly(identifier);
if (databaseContact != null)
{
Guid contactId = databaseContact.ContactId;
// Try to load the contact from the Shared Session.
Contact sessionContact = sharedSessionManager.LockAndLoadContact(contactId);
if (sessionContact != null)
{
// Update this contact and release it back to the Shared Session.
updateMethod(sessionContact);
sharedSessionManager.SaveAndReleaseContact(sessionContact);
}
else
{
// In this branch, we know that the contact we need exists in the database, but it's not locked by our cluster.
// We'll try to lock it and update its data.
LeaseOwner leaseOwner = new LeaseOwner("SOME_UNIQUE_WORKER_NAME", LeaseOwnerType.OutOfRequestWorker);
LockAttemptResult<Contact> lockResult = contactRepository.TryLoadContact(identifier, leaseOwner, TimeSpan.FromMinutes(1));
if (lockResult.Status == LockAttemptStatus.Success)
{
// Update the contact and release it to the Collection DB.
updateMethod(lockResult.Object);
var options = new ContactSaveOptions(release: true, owner: leaseOwner);
contactRepository.SaveContact(lockResult.Object, options);
}
else
{
// Log the inability to lock the contact.
// Decide what else you want to do in that case.
}
}
}
else
{
// In this branch, we know that the contact with the provided identifier does not exist yet.
// You will have to decide what to do in that case. Below is an example where you identify the current contact.
Tracker.Current.Session.Identify(identifier);
updateMethod(Tracker.Current.Contact);
}
}
}
Here's how you can use this method:
string identifier = "[email protected]";
UpdateContact(identifier, UpdateContactData);
null
, do you meanlockedContact.ContactId
? OrlockedContact.Identifiers.Identifier
?contact.System.Classification
? 4) When you already have a contact object incurrentContact
, why are you trying to obtain another contact object fromXdbContactManager.TryLoadContact
? This doesn't make sense to me... Please answer all of the above questions.