📜 ⬆️ ⬇️

Active Record Pattern

I want to talk about the use of the Active Record template for C # in practice. Such a class implements the extraction and writing of the structure to the database. Business logic is imposed on the following levels of abstraction, where it is possible to work with such an object as with a normal structure.

The central case, which I will consider for example, is the work with the Country directory from the database, which is often read, but very rarely changes.

Using an active record object in business logic code looks like this:
')
Country russia = Country.All[“Russia”]; 



Country does not have a public constructor, and retrieving objects is possible only through a call to the Dictionary <string, Country> All method.

Now more in detail about how this class is arranged from the inside.

Record designer



 public readonly string name; private Country(IDataRecord record) { name = record.GetString(0); } 


Due to the privacy of the constructor, we can hope for the correct application of the constructor. And only inside the class.
For example, like this:

 private static Dictionary<string, Country> _all = null; private static Dictionary<string, Country> LoadDictionary() { _all = new Dictionary<string, Country>(); IDataReader reader = DBWrapper.GetReader(sqlSelect); try { while (reader.Read()) { Country item = new Country(reader); _all.Add(item.name, item); } } finally { reader.Close(); } return _all; } 


sqlSelect is a private constant for reading all records with the order of the fields necessary for the constructor.

DBWrapper is a samopisny class that encapsulates work with a database. Thanks to him, at this level we have to work only with interfaces, without specifying a specific implementation.

Add - adding a new entry to the general registry, hidden for brevity of the code in the article.

All dictionary



Here, too, nothing complicated:

 public static Dictionary<string, Country> All { get { return _all ?? LoadDictionary(); }} 


As a result, we have a deferred loading of the directory on the first call.

The _all private variable is used only in this piece of code. Unfortunately, C # does not allow its application to be limited to less than the entire class. There remains the danger of its use for example in public methods. What will become a real problem when working in multiple threads.

This is the first question I want to discuss: how to limit visibility of the _all variable more?

Synchronization multithreading



This method of deferred loading is not yet suitable for working in multi-threading, so I added the LoadStatus class.

private static readonly LoadStatus statusCountryList = new LoadStatus(“country”);

The name for the status is necessary for its identification in the list of statuses of all reference books. But more about that later.

 private static Dictionary<string, Country> _all = null; public static Dictionary<string, Country> All { get { if ( !statusCountryList.IsCompleted ) { lock (statusCountryList) { if ( !statusCountryList.IsCompleted ) { statusCountryList.Start(); _all = new Dictionary<string, Country>(); IDataReader reader= DBWrapper.GetReader(sqlSelect); try { while (reader.Read()) Add(new Country(reader)) statusCountryList.Finish(_all.Count); } catch Exception ex { statusCountryList.Error(ex); } finally { reader.Close(); } }}} return _all; }} 


A lot of pasta, but now we have multithreading and a report on the health of our directory, as a bonus from the architecture.

LoadStatus hides in itself the synchronization and collection of data on the health directory.

In addition, through resetting LoadStatus , it is possible to overload the directory on the fly.
For the sake of this opportunity, I refused to readonly for _all .

Class Generic



The solution turned out so convenient and elegant that I use it in dozens of reference books in all projects. And there is a great desire to turn this code into a generic class .
However, C # syntax does not allow this.

What do you think of this decision?
What are some ways to make this solution generic ?

Source: https://habr.com/ru/post/155545/


All Articles