3

In Sitecore 8.2 we have a Reset() function on all facets. This allows us to reset the facet, clearing all values. On xConnect we do not have that functionality.

The drawback for xConnect is that you are not allow to just new a object and stick it in. If the facet exists, you have to reuse it. That is what I believe.

The Facet

[FacetKey(DefaultFacetKey)]
public class MemberDataFacet : Facet
{
    public const string DefaultFacetKey = "MemberData";

    public MemberDataFacet()
    {

    }

    public Location Location { get; set; } = new Location();

    public Membership Membership { get; set; } = new Membership();

}

The xConnect call

using (var client = this.contactIdentificationRepository.CreateContext())
{
    var contact = client.Get(contactReference, new ContactExpandOptions(MemberDataFacet.DefaultFacetKey));
    if (contact == null)
    {
        throw new ArgumentNullException(nameof(contact));
    }

    var membershipFacet = contact.GetFacet<MemberDataFacet>(MemberDataFacet.DefaultFacetKey) ?? new MemberDataFacet();

    ResetMemberData(membershipFacet);

    membershipFacet.Location.City = "Sarasota";

    client.SetFacet(contact, MemberDataFacet.DefaultFacetKey, membershipFacet);

    client.Submit();
    contactFacetsProvider.UpdateTracker();
}

The reset function

public void ResetMemberData(MemberDataFacet memberfacet)
{
    memberfacet.Location = new Location();
    memberfacet.Membership = new Membership();
}

This seems to be a crappy way of doing it. Especially if your facet gets big with a lot of properties that are not in a subclass. Like I said, using membershipFacet = new MemberDataFacet() if the facet is already on the contact.

Anyone know of a way to allow me to reset the facet in the reset() in xDB?

Possible

I believe this is how it should be done. But it errors

Message: This context does not support this operation. Source: Sitecore.Xdb.Common.Web at Sitecore.Xdb.Common.Web.Synchronous.SynchronousExtensions.SuspendContextLock[TResult](Func1 taskFactory) at Sitecore.XConnect.Client.XConnectSynchronousExtensions.SuspendContextLock(Func1 taskFactory)

private void ResetFacet()
{
    var contactReference = this.contactIdentificationRepository.GetContactReference();

    using (var client = this.contactIdentificationRepository.CreateContext())
    {
        var contact = client.Get(contactReference, new ContactExpandOptions(MemberDataFacet.DefaultFacetKey));
        if (contact == null) return;

        client.ClearFacet(new FacetReference(contact, MemberDataFacet.DefaultFacetKey), new MemberDataFacet());

        client.Submit();
        contactFacetsProvider.UpdateTracker();
    }
}

2 Answers 2

2

This is intended behaviour as stated here -> https://doc.sitecore.com/developers/90/sitecore-experience-platform/en/deleting-data.html

"It is currently not possible to delete contact and interaction data. However, it is possible to remove sensitive data using the right to be forgotten functionality."

I believe that this is because of GDPR and auditing purposes. Values cannot be deleted like it was prior Sitecore 9.x.

However you can execute Right to be forgotten.

If the Facet property is marked [PIISensitive], value will change to it's default like you wanted to have.

Executing right to be forgotten makes the following changes to a contact:

  • Deletes all identifiers - known and anonymous
  • Clears all facets or facet properties marked PII sensitive:

    • If a facet is marked [PIISensitive], the entire facet is deleted.
    • If a facet property is marked [PIISensitive], that property is reset to its default value.
  • ConsentInformation.ExecutedRightToBeForgotten is set to true

So in your case, just decorate facet properties with [PIISensitive] and execute right to be forgotten.

This is how you can execute this async:

using Sitecore.XConnect;
using Sitecore.XConnect.Client;
using System;
using System.Threading.Tasks;

namespace Documentation
{
    public class ForgetContact
    {
        // Async example
        public async void ExampleAsync()
        {
            using (Sitecore.XConnect.Client.XConnectClient client = Sitecore.XConnect.Client.Configuration.SitecoreXConnectClientConfiguration.GetClient())
            {
                try
                {
                    Event ev = new Event(Guid.NewGuid(), DateTime.UtcNow) { Duration = new TimeSpan(20) };
                    var reference = new Sitecore.XConnect.IdentifiedContactReference("twitter", "myrtlesitecore");

                    Task<Sitecore.XConnect.Contact> contactTask = client.GetAsync<Sitecore.XConnect.Contact>(reference, new Sitecore.XConnect.ContactExpandOptions() { });

                    Sitecore.XConnect.Contact contact = await contactTask;

                    client.ExecuteRightToBeForgotten(contact);

                    await client.SubmitAsync();
                }
                catch (XdbExecutionException ex)
                {
                    // Manage exceptions
                }
            }
        }
     }
  }

Take a closer look in official Sitecore xConnect documentation for "Executing right to be forgotten":

https://doc.sitecore.com/developers/90/sitecore-experience-platform/en/execute-right-to-be-forgotten.html

3
  • I appreciate the answer Peter, but I would like to not have to decorate all my properties with [PIISensitive] when the fields are not PIISensitive. I am just trying to avoid having to setting each property in my object to its default value.
    – Chris Auer
    Jan 16, 2019 at 13:52
  • 1
    Both solutions are not good. Could be that the answer will help somebody else Jan 16, 2019 at 14:11
  • 1
    I have a ticket in with Sitecore. Lets see what they say. The .Reset() function was perfect in 8.2.
    – Chris Auer
    Jan 16, 2019 at 14:15
2

The issue with xConnect facets is that the facet has a Concurrency Token after it has been written to xConnect. if you try and apply a new facet, xConnect yells because the token doesn't match. The secret sauce is to write the token back to the new facet after you create a new facet. In the code below, it is used as an extension.

Code

public static class FacetExtensions
{
    public static T GetFacetWithDefaultValues<T>(this T facet) where T : Facet, new()
    {
        var concurrencyToken = facet.ConcurrencyToken;
        var result = new T();
        var type = result.GetType();
        Condition.Ensures(type, type.Name).IsNotNull();
        var property = type.GetProperty("ConcurrencyToken");
        Condition.Ensures(property, property.Name).IsNotNull();
        property.SetValue(result, concurrencyToken);
        return result;
    }
}

Usage

var facet = contact.GetFacet<PersonalInformation>(PersonalInformation.DefaultFacetKey);
if (facet != null)
{
   facet = facet.GetFacetWithDefaultValues();
   client.SetFacet(contact, PersonalInformation.DefaultFacetKey, facet);
   client.Submit();
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.