RavenDB document design, patching, and index creation - ravendb

I am revisiting RavenDB after a brief experiment quite a while ago. At the moment I'm considering document design which is nested 3 levels deep, i.e.
public class UserEvent
{
public UserEvent()
{
Shows = new List<Show>();
}
public readonly string IdPrefix = "Events/";
public string Id { get; set; }
public string Title { get; set; }
public List<Show> Shows { get; set; }
}
public class Show
{
public Show()
{
Entries = new List<ShowEntry>();
}
public readonly string IdPrefix = "Shows/";
public string Id { get; set; }
public string EventId { get; set; }
public string Name { get; set; }
public DateTime Date { get; set; }
public List<ShowEntry> Entries { get; set; }
}
public class ShowEntry
{
public readonly string IdPrefix = "ShowEntries/";
public string Id { get; set; }
public string DogId { get; set; }
public string OwnerName { get; set; }
public EntryClass Class { get; set; }
}
First of all, is this a sensible design? A UserEvent generally has a few (less than 6) Show, but a Show can have between tens to hundreds of ShowEntry. I have included DogId in ShowEntry but maybe later I will change it to a property of Dog type. A Dog is of a particular Breed, and a Breed belongs to a Group. The Dog side of the story will have to be another question but for now I'm interested in the UserEvent side.
If my documents are designed this way can I use the Patching API to add items into the Entries collection within a Show? I would like to have an index which will summarise Entries based on Dog properties. Will indexes get processed if an a document is patched?

Your design certainly looks sensible from an outside perspective. The big question you need to ask yourself is, "What do you plan on querying a majority of the time?"
For instance, Show seems to be a fairly common object that would benefit from being an Aggregate Root (from Domain Driven Design). I find that when organizing my documents, the most important question is, "how often do you plan on querying the object."
To answer your last question, Patching should definitely causing re-indexing.

Related

Storing Historical Data using History table in ASP.Net Core

I have an entity in my database linked up with multiple entities and I need to store historical data for the changes (insert ,updates and delete) in the base entity as well as children entities.
Now the approach we are thinking of adopting is to keep every data in the corresponding history entity. The base table looks like this :
public partial class Con
{
public Guid Id { get; set; }
public string Note { get; set; }
...
public virtual ICollection<Document> Document { get; set; }
public virtual ICollection<ConLine> ConLine { get; set; }
public virtual ICollection<Leg> Leg { get; set; }
}
And the historical table looks like this, I am not sure about how to design the history table to hold linked tables data:
public partial class ConHistory
{
public Guid Id { get; set; }
public Guid ConId { get; set; }
public int TransactionId { get; set; }
...
public virtual ICollection<Document> Document { get; set; }
public virtual ICollection<ConLine> ConLine { get; set; }
public virtual ICollection<Leg> Leg { get; set; }
}
How do I approach this problem and What are the best industry practices? My main concern is when a child's data is being changed how do I log in to parent history table and the corresponding child history table.
For simple time-series data, keeping a separate table with a copy of the modifiable fields is a perfectly valid approach. Unfortunately, in your case you would also need to make a copy of each of the linked tables as well, so that you can maintain consistent foreign keys - e.g. DocumentHistory, ConLineHistory, LegHistory. It's a lot of repetitive code. And then you have to consider, what happens to all the historical records when the schema changes?
Personally, I would store this information as json, in a text column. All the fields that you search on should be in sql, so that you can index it, but the rest can be serialized to a json string:
public partial class ConHistory
{
public Guid Id { get; set; }
public Guid ConId { get; set; }
public int TransactionId { get; set; }
public Guid ModifiedByUser { get; set; }
public DateTime Date { get; set; }
// Serialize the rest of the `ConHistory` fields to a json object, and store them here
public string Json { get; set; }
}
Sql also has the JSON_VALUE function, and there are some examples of using this in Entity Framework, if you do need to get values out of the json string for querying.

DDD shared entity between two aggregate roots

I'm working with two different aggregate roots: Post and Question. Both of them have a Category.
So far I have implemented it as a shared entity (which I'm not sure if is a correct design in DDD).
public class Post
{
public Guid Id { get; private set; }
public Category Category { get; private set; }
public string Title { get; private set; }
public string Body { get; private set; }
}
public class Question
{
public Guid Id { get; private set; }
public Category Category { get; private set; }
public string Title { get; private set; }
public string Body { get; private set; }
}
public class Category
{
public int Id { get; private set; }
public string Name { get; private set; }
public string Key { get; private set; }
}
Note: I'm aware I'm falling into primitive obsession anti-pattern, and I have plans on refactor the primitives into ValueObjects.
After read this post DDD: Share entity with multiple aggregate roots I'm thinking that maybe I should convert the Category in a ValueObject (with multiple fields).
In theory Category could be an Entity with its own lifecycle, but reality is that I don't really add/remove/update categories.
Is it possible to use a shared Entity on DDD? Or I better rather use a ValueObject?
Lets deal with one aggregate first: Post
Now to answer your question:
Is it possible to use a shared Entity on DDD? Or I better rather use a ValueObject?
It depends on what you will do with Category.
Scenario 1:
You have a feature(or page) in your application to show all posts of a category. I would go with the following design:
public class Category
{
public int Id { get; set; }
//this is my in-memory database. Use repository and service to adjust yours
public static List<Post> Posts;
public Category()
{
Posts = new List<Post>();
}
public void AddPost(Guid id, string title, string body)
{
var post = new Post(id, title, body, this.Id);
//saving the post into in-memory. Perhaps you can check some business logic inside Post entity
Posts.Add(post);
}
// You can retrieve all posts of a single category
public IEnumerable<Post> GetAllPosts()
{
return Posts.Where(x => x.CategoryId == this.Id);
}
}
public class Post
{
public Guid Id { get; private set; }
public string Title { get; private set; }
public string Body { get; private set; }
public int CategoryId { get; private set; }
public Post(Guid id)
{
Id = id;
}
public Post(Guid id, string title, string body, int categoryId)
{
//I prefer to pass guid into domain from external services.
//Using this way, your service will have the id to return to upper layers.
//Alternatively you can create new guid here on your own
Id = id;
Title = title;
Body = body;
CategoryId = categoryId;
}
// you can retrieve a post detail
public Post GetPost()
{
return Category.Posts.FirstOrDefault(x => x.Id == this.Id);
}
}
I can see only one aggregate root in this scenario: Category.
Scenario 2:
You have posts page, from there users can view detail post. Additionally, every post has a category which will be shown somewhere on that detailed page. You can have following simple design:
public class Post
{
public Guid Id { get; private set; }
public string Title { get; private set; }
public string Body { get; private set; }
public string CatKey { get; private set; }
public Post(Guid id)
{
Id = id;
}
public Post(Guid id, string title, string body, string catKey)
{
//I prefer to pass guid into domain from external services.
//Using this way, your service will have the id to return to upper layers.
//Alternatively you can create new guid here on your own
Id = id;
Title = title;
Body = body;
//I don't even bother with category id. This is a simple value object, you can store all of your categories
//into a hashtable of key-value
CatKey = catKey;
}
// you can retrieve a post detail
public Post GetPost()
{
//get your post detail from repo
}
}
Hope you can make your decision now.
The main question of Entity vs ValueObject is would two instances of the Category with the same values need to be tracked differently? The classic example is a dollar bill - in most instances, the serial number (ID) doesn't matter, and one dollar is the same as another (ValueObject). If your domain is collecting rare bills, though, that would change.
I'd suspect not in your case, since it appears Category is really just comprised of the name and key. If the Category of a Post changes, do you need to track what the Category previous was?

ASP.NET MVC 4 database scaffolding self referential model

I have a constructed a model using code first in C#. The model literally represents a container element for a website building application, in other words, the model defines a Div tag or some such HTML element. Like a Div tag which can contain multiple child elements, I have tried to represent this in my model, but the scaffolding to the DB, does not give me what I'd expect.
I should get a new many to many joins table, but instead I only get a single column in the DB which expects a single int data type.
Here is the model:
public class ElementContainer
{
public int ElementContainerID { get; set; }
public int PageId { get; set; }
public int? ParentElementContainerID { get; set; }
public string ElementContainerName { get; set; }
public ElementType ElementType { get; set; }
public string ElementClass { get; set; }
public PageAsset PageAsset { get; set; } // content of container
public List<ElementContainer> NestedContainers { get; set; }
}
The last line is the self-referential attribute which just appears as a column called ElementContainer_ElementContainerID
Thanks in advance!
I agree with Bahman, DB first is easier.
While I haven't tried to do what you are trying, your code looks like a self-Join that would do exactly what you describe.
This is a One-to-Many relationship. EF Navigation will pull a List of all nested children containers.
If you want to create a many-to-many relationship with EF Code-First, you should create another Entity
public class ContainerChildren
{
public int ElementContainerID { get; set; }
public List<ElementContainer> NestedContainers { get; set; }
}
this reference should help you to get the exact idea http://blogs.msdn.com/b/wriju/archive/2011/05/14/code-first-ef-4-1-building-many-to-many-relationship.aspx

Using TransformResults to select hierarical data from RavenDB?

I have a simple class hierarchy looking like this:
public class Top
{
public string Id { get; set; }
public string Description { get; set; }
public List<Middle> Middles { get; set; }
}
public class Middle
{
public string Id { get; set; }
public string Description { get; set; }
public List<Bottom> Bottoms { get; set; }
}
public class Bottom
{
public string Id { get; set; }
public string Description { get; set; }
}
The whole thing is saved as entity of type 'Top'. Document is designed to preserve and reflect relationships/hierarchy but half but at time I will, for example, care only about an 'Id' and 'Description' of a given relationship. So, the types of queries I'd want to run are
select all Top,
select all Middle,
select Middle where Top.Id=somevalue
select Bottom where Top.Id=somevalue and Middle.Id=somevalue
I would like the results to be transformed and returned to me like this:
public class Result
{
public int Id { get; set; }
public string Description { get; set; }
}
How can I implement TransformResults (I presume that that's the feature that can be used) to achieve this? I've read quite a few examples but all of the sudden I see parameters/values, which were not declared anywhere and as a result I don't understand what's happening.
TransformResults doesn't have access to the outside world, you can't execute logic based on the query that you run.
You can flatten this structure, sure, but unless you will create multiple indexes with different TransformResults, you can't do this.
Note that this is a strange thing to do in the first place, because it doesn't matches the standard modeling of documents as a transaction boundary.

FluentNHibernate mapping syntax help needed

I'm having some trouble figuring out the appropriate FluentNHibernate mapping syntax for the following data model and domain objects. Here's the data model I'm working against:
And I'm trying to map the following domain objects to that model:
namespace FluentNHibernateSandbox.Entities
{
public abstract class EntityBase
{
public virtual long Id { get; set; }
}
}
namespace FluentNHibernateSandbox.Entities
{
public class Attribute : EntityBase
{
public virtual string Name { get; set; }
public virtual string Label { get; set; }
public virtual string Description { get; set; }
public virtual int SortOrder { get; set; }
public virtual Group Group { get; set; }
public virtual Editor Editor { get; set; }
}
}
namespace FluentNHibernateSandbox.Entities
{
public class Group : EntityBase
{
public virtual string Name { get; set; }
public virtual string Label { get; set; }
public virtual string Description { get; set; }
public virtual int SortOrder { get; set; }
public virtual IList<Attribute> Attributes { get; set; }
}
}
namespace FluentNHibernateSandbox.Entities
{
public class Editor : EntityBase
{
public virtual string ViewName { get; set; }
public virtual string WorkerClassName { get; set; }
}
}
In general, what I ultimately want doesn't seem like it should be all that hard to do, but I after having tried just about every combination of mappings I can think of, I still can't seem to get it right. I just need my Attribute to have a reference to the Group that it belongs to and a reference to the Editor assigned to it, and each Group should have a collection of the Attributes that are part of it. The couple of many-to-many join tables are what seem to be giving me fits. Particularly the APPLICATION_ATTRIBUTE table. Ultimately I only want the Attributes that my application is concerned with, in this case, those with an APPLICATION_ID of 4.
Any help would be greatly appreciated. Thanks.
Really kinda surprised nobody responded to this at all, but anyway. The answer/solution for this mapping situation that we came up with, which I was trying to avoid to start with, but turned out to really be the best way to go, was to create some custom views in the database that joined together all of the application-specific data I needed, and then just mapped my application's domain objects to those views. This worked at least partially because the information I needed from these tables is going to be read-only for this application, but even if I needed to write to the tables, I'm pretty sure (though haven't verified as I didn't really have need in this case) that I could have setup my views to be writeable and that would've worked too.
Hat tip to #robconery.