如何在 Sitecore 方面实现对象集合?

How can I implement collections of objects in a Sitecore facet?

This article 似乎暗示这是可能的,但似乎跳过了集合本身的关键实现。它列出了粗略的结构:

public interface ICoordinate : IElement
{
    float Longitude { get; set; }
    float Latitude { get; set; }
}

public interface IPlace : IElement
{
    string Description { get; set; }
    ICoordinate Coordinate { get; }
}

public interface IPlaces : IFacet
{
    IElementDictionary<IPlace> Places { get; }
}

正是我需要的对象集合。那么我该如何实现呢?

[Serializable]
  internal class Coordinate : Element, ICoordinate
  {
    private const string LONGITUDE = "Longitude";
    private const string LATITUDE = "Latitude";

    public float Longitude
    {
        get
        {
            return this.GetAttribute<float>( LONGITUDE );
        }
        set
        {
            this.SetAttribute( LONGITUDE, value );
        }
    }

    public float Latitude
    {
        get
        {
            return this.GetAttribute<float>( LATITUDE );
        }
        set
        {
            this.SetAttribute( LATITUDE, value );
        }
    }

    public Coordinate()
    {
      this.EnsureAttribute<float>(LONGITUDE);
      this.EnsureAttribute<float>(LATITUDE);
    }
  }

那是坐标,那Places呢?如何添加新地点?该文章似乎缺少此信息

经过多次尝试,我终于拼凑起来了。文章的关键(虽然没有很好解释)部分是:

Register the attributes, collections, and dictionaries with the base class in the constructor using the following helper methods:

this.EnsureAttribute<TValue>( string name );
this.EnsureElement<TElement>( string name );
this.EnsureDictionary<TElement>( string name );
this.EnsureCollection<TElement>( string name );

所以 collection 与属性 "Ensured" 不同。所以 Places class 的实现(从示例中)看起来像:

[Serializable]
public Places : Facet, IPlaces
{
    private const string FIELD_PLACES = "Places";

    public Places()
    {
       this.EnsureDictionary<IPlace>(FIELD_PLACES);
    }


    public IElementDictionary<IPlace> Places 
    { 
      get
      {
          return this.GetCollection<IPlace>(FIELD_PLACES);
      }

    }
}

注意不同的 Get(this.GetCollection<IPlace>(FIELD_PLACES);) 和 Ensure 调用(this.EnsureDictionary<IPlace>(FIELD_PLACES);)。如果您不这样做,您的 collection 将是 nullIPlace.Coordinate 将以相同的方式设置。通过调用它们,它将为您实例化正确的 collections。

添加也不简单(或解释)。 IElementDictionary 不公开 Add 方法。它确实暴露了 Create()。使用反射工具快速查看它,您可以看到它创建了一个项目并将其添加到词典中:

public TElement Create(string key)
{
    Assert.ArgumentNotNull(key, "key");
    TElement tElement = ModelFactory.CreateElement<TElement>();
    this.dictionary.Add(key, tElement);
    return tElement;
}

所以添加到 Places 字典的方式如下:

IPlaces places = _contact.GetFacet<IPlaces>("name form XML config");
IPlace newPlace = places.Places.Create();
newPlace.Description = "test";
ICoordinate newCoord = newPlace.Coordinate.Create();
newCoord.Longitude = 0;

无需保存等,持久化等内部处理。

您需要注册所有 3 个 "elements",但只有最上面的 (IPlaces) 需要进入 [=48= 的 <entities> collection ].所以整个配置看起来像:

<sitecore>
    <model>
      <elements>
        <element interface="Namespace.IPlaces, Dllname" implementation="Namespace.Places, Dllname" />
        <element interface="Namespace.IPlace , Dllname" implementation="Namespace.Place, Dllname" />
        <element interface="Namespace.ICoordinate, Dllname" implementation="Namespace.Coordinate , Dllname" />

      </elements>
      <entities>
        <contact>
          <facets>
            <facet name="name form XML config" contract="Namespace.IPlaces, Dllname" />
          </facets>
        </contact>
      </entities>
    </model>
  </sitecore>

Subsequently I've seen this article 其中涵盖了这一点并深入介​​绍了有关自定义数据的其他详细信息