I have created a custom facet model with Sitecore 9.0.1 & xConnect.

My contact custom facet contains a property of List<string> which I want to populate with different values while contact visiting the site.

N.B. I have indexed the anonymous contacts.

I am trying to save the new item in the list using contact.SetFacet<MyCustomFacet>...and then adding item to facet, but the problem is the list becomes empty again when I use contact.GetFacet<MyCustomFacet>....

I am submitting the client each time after adding a item. Do I really need that? or, will it automatically saved at session end? I am looking for right way to achieve that.

I want to keep all the items I added to the list available till the session end so that I can use them whenever needed.

public static void AddDynamicFacetItem(DynamicFacetItem facetData)
{
    var manager = AnalyticsHelpers.GetContactManager();

    if (manager != null)
    {
        using (var client = SitecoreXConnectClientConfiguration.GetClient())
        {
            try
            {
                var item = facetData.ConvertToData();

                if (AnalyticsHelpers.CurrentTracker.Contact.IsNew)
                {
                    Sitecore.Analytics.Tracker.Current.Contact.ContactSaveMode = ContactSaveMode.AlwaysSave;
                    manager.SaveContactToCollectionDb(Sitecore.Analytics.Tracker.Current.Contact);

                    var trackerIdentifier = new IdentifiedContactReference(
                        Sitecore.Analytics.XConnect.DataAccess.Constants.IdentifierSource,
                        Sitecore.Analytics.Tracker.Current.Contact.ContactId.ToString("N"));

                    var contact = client.Get<Contact>(trackerIdentifier,
                        new Sitecore.XConnect.ContactExpandOptions());

                    AddItemForNewContact(client, contact, item);
                }
                else
                {
                    var trackerIdentifier = new IdentifiedContactReference(
                        Sitecore.Analytics.XConnect.DataAccess.Constants.IdentifierSource,
                        Sitecore.Analytics.Tracker.Current.Contact.ContactId.ToString("N"));

                    var contact = client.Get<Contact>(trackerIdentifier,
                        new Sitecore.XConnect.ContactExpandOptions(DynamicDataFacet.DefaultFacetKey));

                    AddItemForExistingContact(client, contact, item);
                }

                manager.RemoveFromSession(AnalyticsHelpers.CurrentTracker.Contact.ContactId);
            }
            catch (Exception e)
            {
                Sitecore.Diagnostics.Log.Error(e.Message, e, "AddDynamicFacetItem");
            }
        }
    }
}

private static void AddItemForNewContact(XConnectClient client, Sitecore.XConnect.Contact contact,
    XYZ.Model.Data data)
{
    try
    {
        if (contact != null)
        {
            var list = new List<Data> { data };

            client.SetFacet<DynamicDataFacet>(contact, DynamicDataFacet.DefaultFacetKey, new DynamicDataFacet()
            {
                Data = list
            });

            client.Submit();
        }
    }
    catch (Exception e)
    {
        Sitecore.Diagnostics.Log.Error(e.Message, e, "AddItemForNewContact");
    }
}

private static void AddItemForExistingContact(XConnectClient client, Sitecore.XConnect.Contact contact,
    XYZ.Model.Data data)
{
    try
    {
        if (contact != null)
        {
            if (contact.DynamicData() != null)
            {
                contact.DynamicData().Data.Add(data);
            }
            else
            {
                var list = new List<Data> { data };

                client.SetFacet<DynamicDataFacet>(contact, DynamicDataFacet.DefaultFacetKey,
                    new DynamicDataFacet()
                    {
                        Data = list
                    });
            }

            client.Submit();
        }
    }
    catch (Exception e)
    {
        Sitecore.Diagnostics.Log.Error(e.Message, e, "AddItemForExistingContact");
    }
}

[xdb_collection].ContactFacets data:

2DBF166D-45E5-0000-0000-0539A599359D    DynamicData 2018-03-16 11:30:16.5605749 C8032A2E-C837-4FA1-B150-B559EFE237DD    {"@odata.type":"#xyz.Model.DynamicDataFacet","Data":[{"PropertyName":"Discount.Amount","Type":"System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","Value":"1520"}]}

JSON:

{
  "Name": "XYZ.Model.DynamicDataModel",
  "Version": "1.0",
  "References": [
    {
      "Name": "XConnect",
      "Version": "1.0"
    },
    {
      "Name": "Sitecore.XConnect.Collection.Model",
      "Version": "9.0"
    }
  ],
  "Types": {
    "XYZ.Model.DynamicDataFacet": {
      "Type": "Facet",
      "BaseType": "Sitecore.XConnect.Facet",
      "ClrType": "XYZ.Model.DynamicDataFacet, XYZ, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
      "Properties": {
        "Data": {
          "Type": [
            "XYZ.Model.Data"
          ]
        }
      }
    },
    "XYZ.Model.Data": {
      "Type": "Complex",
      "ClrType": "XYZ.Model.Data, XYZ, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
      "Properties": {
        "PropertyName": {
          "Type": "String"
        },
        "Type": {
          "Type": "String"
        },
        "Value": {
          "Type": "String"
        }
      }
    }
  },
  "Facets": [
    {
      "Target": "Contact",
      "Name": "DynamicData",
      "Type": "XYZ.Model.DynamicDataFacet"
    }
  ]
}

Model

namespace XYZ.Model
{
    [Serializable]
    [FacetKey(DefaultFacetKey)]
    public class DynamicDataFacet : Facet
    {
        public const string DefaultFacetKey = "DynamicData";
        public List<Data> Data { get; set; }

        public DynamicDataFacet()
        {
            Data = new List<Data>();
        }
    }
}

namespace XYZ.Model
{
    [Serializable]
    public class Data
    {
        public string PropertyName { get; set; }
        public string Type { get; set; }
        public string Value { get; set; }
    }
}

namespace XYZ.Model
{
    public class DynamicDataModel
    {
        public static XdbModel Model { get; } = BuildModel();

        private static XdbModel BuildModel()
        {
            XdbModelBuilder modelBuilder = new XdbModelBuilder("XYZ.Model.DynamicDataModel", new XdbModelVersion(1, 0));
            modelBuilder.ReferenceModel(Sitecore.XConnect.Collection.Model.CollectionModel.Model);
            modelBuilder.DefineFacet<Contact, DynamicDataFacet>(DynamicDataFacet.DefaultFacetKey);
            return modelBuilder.BuildModel();
        }
    }
}

public static DynamicDataFacet DynamicData(this Contact contact)
        {
            return contact.GetFacet<DynamicDataFacet>(DynamicDataFacet.DefaultFacetKey);
        }
  • Add more code samples especially how are you prepare data and then set facet. That is not clear from current samples – Peter Prochazka Mar 15 at 19:59
  • Do you use 'new ContactExpandOptions(MyCustomFacet)' when getting Contact ? This could be one reason – Peter Prochazka Mar 15 at 20:03
  • Yes I used ContactExpandOptions with Custom facet key. – Enthusiast Mar 16 at 5:11
  • Have you verified that the facets are saved? Take a look in ContactFacets table in one of Shard dbs – Peter Prochazka Mar 16 at 5:18
  • 1
    Can you add your contact facet model code and JSON? – Pete Navarra Mar 16 at 13:15
up vote 5 down vote accepted

You should use similar code as below one to fix your problems to get and set custom facet values:

Contact contact = client.Get<Contact>(
   new IdentifiedContactReference(_contactSource, contactIdentifier),
   new ContactExpandOptions(DynamicDataFacet.DefaultFacetKey));

var list = new List<Data> { data };

if (contact != null)
{
  var facet = contact.GetFacet<DynamicDataFacet>(DynamicDataFacet.DefaultFacetKey);

  if (facet != null)
  {
     facet.DynamicDataFacet.Add(new DynamicDataFacet()
       { Data = list }));

     client.SetFacet(contact, DynamicDataFacet.DefaultFacetKey, facet);
  }
  else
  {
     client.SetFacet(contact, DynamicDataFacet.DefaultFacetKey, new DynamicDataFacet() { Data = list }));
  }
}

We have similar code in production but I have changed facet names to correspond yours.

I think you have three issues in your code that cause you trouble:

1)

You should use client.GetFacet instead of contact.DynamicData() != null.

Also client.SetFacet should be used instead of contact.DynamicData().Data.Add as I think contact.DynamicData().Data.Add will do nothing at all at the end. You are adding something to contact but client object doesn't know about that when you are calling client.Submit() here in your code below (look in my suggested code above to compare):

if (contact != null)
    {
        if (contact.DynamicData() != null)
        {
            contact.DynamicData().Data.Add(data);
        }
        else
        {
            var list = new List<Data> { data };

            client.SetFacet<DynamicDataFacet>(contact, DynamicDataFacet.DefaultFacetKey,
                new DynamicDataFacet()
                {
                    Data = list
                });
        }

        client.Submit();

2)

You should not use new Sitecore.XConnect.ContactExpandOptions()).

You should always use new ContactExpandOptions(DynamicDataFacet.DefaultFacetKey) instead in your case.

3)

Not related to your issue directly but you should have only one method to set facet not two as you have now. :)

Also you are repeating code here:

var trackerIdentifier = new IdentifiedContactReference(
Sitecore.Analytics.XConnect.DataAccess.Constants.IdentifierSource,
Sitecore.Analytics.Tracker.Current.Contact.ContactId.ToString("N"));

var contact = client.Get<Contact>(trackerIdentifier,
                    new Sitecore.XConnect.ContactExpandOptions());

That should be moved to unified AddItem method.

Follow DRY principles!

More information about facets on contacts in xConnect:

  • 3
    I spent a fair amount of time, with the time that I had working on a solution and then saw this answer and realized that it was exactly what I had found. This is the right answer. – Pete Navarra Mar 16 at 15:34
  • I made the required changes, but could not verify the result. I will give my feedback on my next working day. Thanks for your support guys. – Enthusiast Mar 16 at 19:18
  • Keeping fingers crossed and keep us posted :) – Peter Prochazka Mar 16 at 19:19
  • 1
    It works. Thanks guys. – Enthusiast Mar 19 at 7:30
  • Great @Enthusiast :) Glad to be able to help – Peter Prochazka Mar 19 at 7:31

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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