I am thinking about using a NoSQL database to scale database reads
Good idea. It sounds like you are going down the path of Command Query Responsibility Segregation(CQRS). NoSql databases make for excellent read stores.
The link you referenced describes a technique to update
Combining SQL Server and MongoDB using NHibernate - this is what I meant by 'Combo' (combining) Repository. "Combo Repository" isn't a standard pattern. Quoting the author:
Of course, theoretically, we could just move all the data to some NoSQL storage, but what if we don’t want to get rid of our relational database completely? How can we combine them together?
You've tagged your original question with both a Sql-Server
and a NoSql
database, so at a guess you're in the Polyglot space
The Repository Pattern is a very common abstraction layer around data persistence.
The "combining" link you've referenced specifically solves the problem of many-to-many relationships (often referred to as Junction tables in Sql), and the performance implications when there are many such relations.
In the more general sense, as an alternative to providing interception points in NHibernate, you may / may not have abstracted data access via the repository pattern.
Here's an ultra simple (and non-generic) repository interface in C#:
public interface IWidgetRepository
{
Task<Widget> FetchWidget(string widgetKey);
Task SaveWidget(Widget toBeSaved);
}
Suppose we already have a SqlRepository:
public class SqlWidgetRepository : IWidgetRepository
{
public async Task<Widget> FetchWidget(string widgetKey)
{
... Code to use Obtain an NHibernate session and retrieve and deserialize Widget
}
... Other methods here
}
You could also choose to provide a MongoDb
implementation
public class MongoWidgetRepository : IWidgetRepository
{
public async Task<Widget> FetchWidget(string widgetKey)
{
... Code to connect to a MongoDb secondary and Find() the
widget and deserialiaze into Widget
}
... Other methods here
}
And to maintain both databases simultaneously, here's an example of how this "combo" repository may look:
public class ComboWidgetRepository : IWidgetRepository
{
private readonly IWidgetRepository _repo1;
private readonly IWidgetRepository _repo2;
public ComboWidgetRepository(IWidgetRepository repo1, IWidgetRepository repo2)
{
repo1 = repo1;
repo1 = repo2;
}
public async Task<Widget> FetchWidget(string widgetKey)
{
// Just need the one ... first one wins
return await Task.WhenAny(repo1.FetchWidget(widgetKey),
repo2.FetchWidget(widgetKey));
}
public async Task SaveWidget(Widget toBeSaved)
{
// Need both to be saved
await Task.WhenAll(repo1.SaveWidget(toBeSaved),
repo2.SaveWidget(toBeSaved));
}
The above "combo" repository may well fulfil the needs of a single system (and there are many other ways to keep two databases synchronized).
CQRS is however frequently used at enterprise scale (i.e. where you have many systems, with many databases).
My comment about an Enterprise Service Bus will only make sense if you need to distribute data across an enterprise.
The concept is simple
- Commands are queued to a transactional system (e.g. "Add Widget") across the bus.
- Your system handling widgets performs the transaction (e.g. inserts the widget into a database)
- The
Widget
system then publishes (broadcasts) a message to the bus detailing that a new widget has been added (with all the relevant widget information)
- Other systems on in the enterprise which are interested in updates to Widgets subscribe to this message and will update their own
Read Store
representations of the Widgets (e.g. into a NoSql database or cache, and in the format which makes most sense to them).
- This way, when a user accesses any of these other systems and views a screen about 'Widgets', the system can serve the data from its own Read Store, instead of having to request the data from the
Widget
system itself.