AcroDb. New Data Provider

Original author: Oleksiy Glib
  • Transfer
The birth of a new CMS system often begins with the design of the architecture and the implementation of the simplest blocks of this architecture.
Today, I am starting a series of articles on the new content management system implemented in C # and the .Net platform. The system is planned to be open source, and with these articles, I will try to describe all its elements in the order of their initial appearance and design 2 years ago.
The beginning was a universal layer of access to any data provider (either a relational database, or not a relational, or even its own database organization).
Who interested, I ask under the cat.

Like everything that we want to make ingenious and simple, it must also be convenient, fast, and flexible. So I wanted to do with the data access layer. Please note any data :)
The easiest method for a programmer was always using some kind of ORM system. In the .Net Framework, this stuff is enough, starting with the sources - NHibernate, Nolics , LINQ2SQL, Entity Framework, and a bunch of self-written ... What steps should a developer usually take to connect any ORM system to a project?
  • DB selection (necessarily relational)
  • Choosing an ORM system for working with the database
  • Creating tables and links in the database
  • Creating prototypes of tables in the form of classes in code (with LINQ2SQL, this step can be automated with sqlmetal, but EF does this itself)
  • For systems like Nolics.net, you need another step to describe the interface for the prototype table and a description of the structure of the table in its own language, but there is no need to create a table in the database with pens. Nolics will automatically migrate at startup if it’s good to ask him about it :)
  • Further, the developer writes data management classes, such as adding, editing, deleting, selecting

And everything seems to be cool. But! There comes a time when the customer does not like subd (maybe it is expensive or slow and then MongoDB appears which is on everyone’s lips). And the programmer has to rewrite and redo the entire data access layer. Again, almost all of the same steps (please do not kick me lovers of flexible architecture, in which everything has long been provided for, we are not talking about those tasks so far :)).
So the idea was born to unify access to different providers by providing an interface for CRUD operations and not providing relationships between tables (not all database providers know about relationships, but I will explain how to do relationships in AcroDB in the following articles). What did I want to achieve?
  • Create a flexible replacement engine for the data access layer for medium-sized projects and small ones too
  • Create a table description method only once and in one place
  • So that the use of ORM is hidden from the developer, and requests are carried out only by LINQ expressions
  • So that if there is no description of the table in the data provider (sub), this table is automatically created at startup, without the participation of the developer

What came of it? You can download the AcroDB project from the github site .
Let's see what you need to use any table with its automatic creation (a detailed example is in the AcroDbTest subproject in sorts).
First, you need to describe the interface of the future table:
  [AcroDbEntity]
  public interface IUser
  {
    Guid ID { get; set; }
    string Name { get; set; }
  }

* This source code was highlighted with Source Code Highlighter.

marking it with the AcroDbEntity attribute, you tell the system that on the basis of this interface you need to create a class in memory that implements it and use this class to work with the internal ORM system. not bad? :) move on.
Next, when starting the project, we need to configure the connection to the desired data provider (while MsSql and MongoDB are supported for testing):
    static string[] SettingsCallBack(string name)
    {
      if (name == "MsSql")
        return new[] { @"server=OLEKSIY-PC\SQLEXPRESS;Database=acrodbtest;Trusted_Connection=True;" };
      return new string[0];
    }
    static void Main()
    {
      DataContextFactory.SettingsCallback = SettingsCallBack;
      DataContextFactory.Instance.ScanAssembly(typeof(MsSqlDataContext).Assembly);
      //...
    }

* This source code was highlighted with Source Code Highlighter.

The SettingsCallBack method is used to substitute configuration data to configure the data provider. in our example, this is the connection string to the DBMS.
The DataContextFactory class is a singleton that provides on-demand contexts of different data providers. In order for DataContextFactory to know about new data providers, its ScanAssembly method needs to feed the assembly, where there is possibly information about such a provider, and it will perform a search reflexively.
Now we need to configure the data access context generator to use the provider:
  AcroDataContext.DefaultDataContext = DataContextFactory.Instance.Get("MsSql");
  AcroDataContext.ScanAssemblyForEntities(Assembly.GetExecutingAssembly());

* This source code was highlighted with Source Code Highlighter.

AcroDataContext is also a singleton, and the ScanAssemblyForEntities method looks for interfaces marked with the AcroDbEntity attribute in the assembly and creates prototype classes for use in ORM.
How to use CRUD operations further:
  using (var manager = AcroDataContext.Go)
  {
    var usr = manager.Provide().Create();
    usr.Name = "Some user name";
    manager.Provide().Save(usr);
    manager.SubmitChanges();
  }

* This source code was highlighted with Source Code Highlighter.

I will describe here only one line - AcroDataContext.Go. This is creating a context for connecting to a data provider that is already connected and ready to go. Do not forget to close it with the Dispose method.
In order to create a table description based on the description of your interface in the data provider (in this case, the Users table with the primary key ID and the Name field with the type nvarchar (255) will be created in the subdirectory, you need to call the " AcroDataContext.PerformMigrations () ". Migrations are done based on SubSonic Migrations . They used to be done using SQL SMO.

The functionality of this library does not end there, but I will gladly describe additional elements, if someone needs it. And also, impatient ones can read the source code :)
For the first article I ask you not to kick much, I will try to answer all questions :)

Also popular now: