Search code examples
c#design-patternsmetadata

Metadata pattern for your object graph


I want to add metadata to my object graph for non-domain type data that will be associated to my objects but is not essential to the problem set of that domain. For example, I need to store sort settings for my objects so that the order in which they appear in the UI is configurable by the user. The sort indices should be serializable so that the objects remember their positions. That's just one among a few other metadata items I need to persist for my objects. My first thought is to solve this by having a MetadataItem and a MetadataItemCollection where the base Entity class will have a "Meta" property of type MetadataItemCollection. E.g.:

public class MetadataItem
{
    public string Name;
    public object Data;
}

public class MetadataItemCollection
{
    /* All normal collection operations here. */

    // Implementation-specific interesting ones ...
    public object Get(string name);
    public MetadataItem GetItem(string name);

    // Strongly-type getters ...
    public bool GetAsBool(string name);
    public string GetAsString(string name);

    // ... or could be typed via generics ...
    public T Get<T>(string name);
}

public class Entity
{
    public MetadataItemCollection Meta { get; }
}

A few concerns I can think of are:

  • Serialization - the database has a single table of EntityID | Name | Value where Value is a string and all types are serialized to a string?
  • Future Proofing - what if a metadata item's type (unlikely) or name needs to be changed?
  • Refactorability - should the keys come from a static list via enum or a class with static string properties, or should free-form strings be allowed:
var i = entity.Meta["SortIndex"];

vs.

public enum Metadatas { SortIndex };
var i = entity.Meta[Metadatas.SortIndex];

vs.

public static class Metadatas
{
    public static string SortIndex = "SortIndex";
}
var i = entity.Meta[Metadatas.SortIndex];
  • Anything else?

Thoughts, ideas, gotchas?


Solution

  • Metadata literally means data about data, but what you seem to be asking for is a way to control and change behavior of your objects.

    I think such a concern is much better addressed with a Role Interface - see e.g. Udi Dahan's talk about Making Roles Explicit. More specifically, the Strategy design pattern is used to define loosely coupled behavior. I'd look for a way to combine those two concepts.

    As we already know from .NET, the use of static, weakly typed attributes severely limits our options for recomposing components, so I wouldn't go in that direction.