1

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);
        }
13
  • Add more code samples especially how are you prepare data and then set facet. That is not clear from current samples Commented Mar 15, 2018 at 19:59
  • Do you use 'new ContactExpandOptions(MyCustomFacet)' when getting Contact ? This could be one reason Commented Mar 15, 2018 at 20:03
  • Yes I used ContactExpandOptions with Custom facet key.
    – Foysal
    Commented Mar 16, 2018 at 5:11
  • Have you verified that the facets are saved? Take a look in ContactFacets table in one of Shard dbs Commented Mar 16, 2018 at 5:18
  • 1
    Can you add your contact facet model code and JSON? Commented Mar 16, 2018 at 13:15

1 Answer 1

5

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:

4
  • 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. Commented Mar 16, 2018 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.
    – Foysal
    Commented Mar 16, 2018 at 19:18
  • Keeping fingers crossed and keep us posted :) Commented Mar 16, 2018 at 19:19
  • Great @Enthusiast :) Glad to be able to help Commented Mar 19, 2018 at 7:31

Your Answer

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

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