How to store custom data in Episerver – Part IV: Migrate to Entity Framework
In the previous parts of this series, I demonstrated how you can store custom data in Episerver using the Dynamic Data Store and how to make the most out of it. However, DDS has many serious drawbacks. In this blog post, I want to present to you an alternative solution which works much better: Entity Framework.
Problems with Dynamic Data Store
There are two main problems with Episerver’s DDS:
- it has a poor performance
- It has a limited way of querying data
DDS vs Entity Framework performance
To compare Dynamic Data Store and Entity Framework performance, let’s use an example from Part III of this blog series. We used PageViewsData
class and put its store in a separate table to boosts the performance of DDS.
For test purposes I created another class named EntityPageViewsData
which reflects DDS’s PageViewsData
:
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace Setapp.DataStore { public class EntityPageViewsData { [Key] public int Id { get; set; } [Index("IDX_PageIdKey")] public int PageId { get; set; } public int ViewsAmount { get; set; } } }
Let’s start with filling the table. The biggest difference here is that in Entity Framework you can add multiple entries to a table at once (in DDS you need to add entries one by one, there’s no bulk action for it). And that speeds up this action a lot! I am adding 50 000 rows to each table:
var store = typeof(PageViewsData).GetOrCreateStore(); for (int i = 0; i < 50000; i++) { store.Save(new PageViewsData { PageId = i, ViewsAmount = i }); }
DbSet entityPageViewsDatas = applicationDbContext.PageViewsData; var entries = new List(); for (int i = 0; i < 50000; i++) { entries.Add(new EntityPageViewsData { PageId = i, ViewsAmount = i }); } entityPageViewsDatas.AddRange(entries); applicationDbContext.SaveChanges();
Here’s a comparison of the average time of adding the entries to the tables using both frameworks:
Now that makes a difference, doesn’t it?
Ok, but what about a read operation? Let’s compare a few cases here and start with searching for a single object by an indexed column:
store.Items().FirstOrDefault(pageViewsData => pageViewsData.PageId == 25000);
vs
entityPageViewsDatas.FirstOrDefault(pageViewsData => pageViewsData.PageId == 25000);
The difference here isn’t that big but it gets worse when we search with an unindexed column:
store.Items().FirstOrDefault(pageViewsData => pageViewsData.ViewsAmount == 25000);
vs
entityPageViewsDatas.FirstOrDefault(pageViewsData => pageViewsData.ViewsAmount == 25000);
Let’s go further and see what happens if we want to get and materialize the whole collection filtered by an unindexed value:
store.Items().Where(pageViewsData => pageViewsData.ViewsAmount > 25000).ToList();
vs
entityPageViewsDatas.Where(pageViewsData => pageViewsData.ViewsAmount > 25000).ToList();
The biggest problem here is the materialization of the objects, that’s what DDS handles much, much worse. The performance gets better if you only count the objects, although you can still clearly see the advantage of Entity Framework.
Other Entity Framework advantages
Well, let’s be honest: Entity can do at least the same things as DDS and it can do it much faster. Besides that, what are the most important features missing in Dynamic Data Store?
In DDS you can only query a single table. There is no way of using LINQ to build more complicated queries which would easily join tables or perform “group by” operations and sort it. So even if LINQ syntax allows you to write such a piece of code:
store.Items() .GroupBy(pageViewsData => pageViewsData.PageId) .Select(group => new { PageId = group.Key, Count = group.Count() }) .OrderBy(obj => obj.PageId)
and even though it will compile with no problems, you will get a runtime exception as DDS cannot form a valid SQL query from this LINQ code. Entity will have no problems with that.
Another big advantage of Entity Framework over DDS is that in the latter case it can be very problematic if you want to change a class stored in the database.
For example, if you want to change a type of a property or add another one, it gets very complicated to change the store definition if you have a (much faster) custom table. In Entity Framework, you can use its migration mechanism which can automatically change the structure of your database if needed.
Final Words
You can find the whole solution on Github and test it yourself. As you can see, DDS is very limited in its functionality and its performance is very poor, even if optimized by using a custom table. To use Entity Framework in Episerver, you don’t even have to include any additional libraries – it’s one of the dependencies of Episerver anyway!
There is no reason not to start using Entity Framework instead of DDS, it will surely help you create better performing software.
If you missed my previous three blog posts from the ‘How to store custom data in Episerver’ blog series. Then, you can check them out below:
- Part I: Dynamic Data Store basic
- Part II: Dynamic Data Store implementation
- Part III: Separate custom big tables
P.S. At Setapp, we’ve got some great tech positions open. If you want to work in a challenging environment and deliver meaningful projects, then do check them out now.