I'm facing a key design question related to how to attach custom fields to entities in my system. The entities are represented in C# and persisted in RavenDB. We are roughly following tenants of Domain Driven Design and our entities are aggregate roots.
[Note: I would like to avoid any debate around the appropriateness of a generic feature like custom fields in a DDD approach. Let's assume we have a legitimate user need to attach and display arbitrary data to our entities. Also, I have made my examples generic for illustrating the design challenges. :)]
My question is concerning how best to lay out the field definitions and the field value instances.
Imagine a domain where we have aggregate roots of Book and Author. We want users to be able to attach arbitrary data attributes to instances of Books and Authors. So, we might define a custom field with a class like this:
public enum CustomFieldType
{
Text,
Numeric,
DateTime,
SingleSelect,
MultiSelect
}
public class CustomFieldDefinition
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public CustomFieldType Type { get; set; }
public Collection<string> Options { get; set; }
}
A CustomFieldDefinition (CFD) that attached to Book might have values like:
The first question I'm facing is what to store on each instance of a Book. The choices range from...
store just the CFD Id and the instance value
to
store the entire CFD along with the value
The "low end" is bad because I cannot display a Book without pulling in the CFD, which is in another document. Also, if I change the CFD in any way, I've change the meaning of values in historical documents.
The "high end" is bad because there would be a lot of duplication. The CFD could be pretty heavy for select list CFDs because the definition contains all of the selectable options.
The first question is... How much should be stored in the document for each Book? Just enough to display the Book (and I'd have to go back to the CFD to display the options and description if I'm going to allow the user to edit the CF value)?
The second question is... Should I store I store the entire collection of CFDs for one entity type in one document or keep each CFD in it's own document?
Each CFD as a document keeps things simple for each CFD (especially when I start to do things like deactivate definitions), but then I need a way to separate Book CFDs from Author CFDs. This also forces me to load 1 document for each CF attached to the entity whenever I want to edit the entity.
All of the CFDs for a given type in one document allows me to load just one document, but then I'm loading all of the deactivated definitions as well.
Third question... Is there a better way to implement this altogether?
Fourth question... Are there any sample or open source solutions out there so I don't have to reinvent this wheel?
To add a custom field, c lick the Custom tab. Use a custom field for content that cannot use one of the fields that come with AutoCAD. Click the Add button. In the Add Custom Property dialog box, enter a field name and value and click OK.
Since you said in comments:
... a Book from a year ago should show the custom fields as of a year ago.
There are only two viable options I can see.
Nt:Tx
type. You can find another example of this relationship type here. You might want to get an overview of temporal relationships in order to make some sense of this. Beware, this is a tricky subject and gets complicated quickly.With either option, I would simply keep a property on the custom field definition that says what type(s) it applies to (Book, Author, etc).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With