5

When iterating an item's fields', sometimes the API fails to see a field unless item.Fields.ReadAll() is executed prior to checking for field existence.

I've ran into this multiple times in all my years, and running item.Fields.ReadAll() always saves the day but I don't have a clear explanation for why it returns fields sometimes, but not others.

In my most recent example, I iterated a list of items with the same template. The items without an image set (I believe this happens on other field types as well) would return as if the field didn't exist on the template.

if (product.Fields.Select(i => i.Name).All(i => i != field.Name))
  continue;

The line above would trip the continue on products without an image set.

I'm aware that item[field.Name] would always return the value of the field regardless of whether or not item.Fields.ReadAll() was executed prior.

1
  • This is totally unrelated to your question, but I think your code above could be a little performant by condensing it to product.Fields.All(f => f.Name != field.Name). You're welcome for the unsolicited advice! ;P Oct 25, 2018 at 19:58

1 Answer 1

8

When you need all fields :-)

For performance reasons, Sitecore will not explicitly read fields that have no value, or fields that have only Standard Value defined. The only time you will need to call .ReadAll is when you plan to loop through the FieldCollection - pretty much like the scenario you describe above.

For reference:

For the sake of performance, Sitecore will not give you all fields in the FieldCollection in the following code, only fields with explicit values on item level, including empty string:

foreach(Sitecore.Data.Fields.Field field in Sitecore.Context.Item.Fields)
{
  // here you will see only fields with values (even empty string) set on item level
  // fields with null in them or standard values will not be here.
}

Source: Friday Gotcha: Sitecore.Data.Items.Item.Fields

Reading the template definition

If you are interested in what fields are defined for your item (template), TemplateManager also has a method to help you out.

Template template = TemplateManager.GetTemplate(new ID(""), Sitecore.Context.Database);
TemplateField[] allFields = template.GetFields(true);

Adding (true) to the GetFields call, will instruct TemplateManager to also return base fields.

Essentially this is what ReadAllFields does, behind the scenes.

Source: Getting all the fields of a template in Sitecore

On source

Sitecore retrieves data only when necessary. To ensure that Sitecore retrieves all field values for an item, invoke the Sitecore.Data.Items.Item.ReadAll() method. For example, to iterate the fields of the context item:

Sitecore.Data.Items.Item item = Sitecore.Context.Item;
item.Fields.ReadAll();
foreach (Sitecore.Data.Fields.Field field in item.Fields)
{
 // TODO: process field
}

From the: Sitecore CMS 6.4 and later Content API Cookbook

Funnily enough, this is not mentioned in the 6.0 cookbook. I would have thought this method was around since the beginning of time - but I've found no earlier mention of it.

2
  • What happens if I don't call ReadAll(), update a field that exists and then save the item with the API? Does that lose data on the fields not returned?
    – geedubb
    Apr 6, 2020 at 16:28
  • 1
    No, no data is lost like that.
    – Mark Cassidy
    Apr 6, 2020 at 16:47

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.