📜 ⬆️ ⬇️

Using the power of NHibernate in Orchard.CMS

Orchard.CMS is one of the popular free open source web content management systems based on .NET. NHibernate is used as the ORM for data access. More detailed information can be found on the official website of the project , besides, Habré already had articles on Orchard.CMS.
Orchard CMS uses its own method of creating a data scheme through Migration and SchemeBuilder. To access the NHiberanate session (ISession) and transactions, specialized interfaces are used that encapsulate these objects inside (ISessionHolder and ITransactionManager). We have organized our own repository interfaces (IRepository), whose implementations run on top of NHibernate Linq Query.
Orchard does not provide direct access to NHibernate by default. Below will be considered the features of the construction and use of a domain model based on Orchard CMS, as well as the method of using NHibernate directly from its module.
If the business layer is encapsulated separately, and Orchard.CMS addresses entities via web services, the problem of building a domain model does not arise. This applies to large projects. The studies in this article will be valid for projects in which it is initially planned to use a common base for both Orchard CMS and business logic entities.

Orchard.CMS (ContentTypeDefinition) domain model

Consider the BlogPost model in the basic Blog module in Orchard.CMS. (The source code of the project can be found on the official site). BlogPost Blog Type Model:

The blog module is implemented widget allows you to display the latest N blog entries. Let's look at the SQL query that is being formed to get this list. To do this, we use NHProfiler and connect the SoNerdy.NHProf module to Orchard.CMS. (One of the recommendations when developing on Orchard.CMS is to use the NHibernate Profiler www.hibernatingrhinos.com/products/nhprof . This utility is indispensable in analyzing and optimizing the site.)
A query that selects N blog entries is as follows. Join fields of additional content parts were specially removed to focus on the base parts.

SELECT top 12 ... FROM v1__Orchard_Framework_ContentItemVersionRecord this_ inner join v1__Orchard_Framework_ContentItemRecord contentite1_ on this_.ContentItemRecord_id = contentite1_.Id inner join v1__Common_CommonPartRecord commonpart3_ on contentite1_.Id = commonpart3_.Id inner join v1__Orchard_Framework_ContentTypeRecord contenttyp2_ on contentite1_.ContentType_id = contenttyp2_.Id WHERE contenttyp2_.Name in ('BlogPost' /* @p0 */) and commonpart3_.Container_id = 22 /* @p1 */ and this_.Published = 1 /* @p2 */ ORDER BY commonpart3_.CreatedUtc desc 

')
A brief analysis of the request:

The result of the implementation of the domain model of the application within the Orchard.CMS content types will be the following:


As a solution to the problem - completely abandon the use of content types when building a domain model. Its implementation using simple Record classes. Orchard uses AutoMapping to configure NHibernate, and one of the conventions is as follows: Record postfix must be added to all data type names. The downside is that testing will still depend on the Orchard context, and the migration to another content management system will become more complicated. In addition, it is necessary to implement separate modules for business logic and for presentation.

Using NHibernate directly in Orchard.CMS

The Orchard.CMS Framework provides the ability to configure HNibernate and use its capabilities directly, without the Orchard pipeline. Starting with version 1.7, the new interface ISessionConfigurationEvents has become available. An example implementation of ISessionConfigurationEvents in a demonstration project:

 public class PersistenceConfiguration : ISessionConfigurationEvents { public PersistenceConfiguration() { Logger = NullLogger.Instance; } public ILogger Logger { get; set; } public void Created(FluentConfiguration cfg, AutoPersistenceModel defaultModel) { cfg.Mappings(x => x.FluentMappings.AddFromAssemblyOf<Customer>()); } ... public void ComputingHash(Hash hash) { hash.AddString("NHStore.Domain.Mapping"); } } 

To configure your module, you need to add the implementation of this interface to your module and define the configuration of NHibernate in the Created method. You also need to define the Hash module for automatic regeneration of the overall configuration of NHibernate. Orchard.CMS generates the NHibernate configuration in the mapping.bin file, which is located in the App_Data \ Sites \ Default folder, a separate configuration for each site. To regenerate an existing configuration, you must delete the mapping file, and the application will create it automatically.

To access entities, it is possible to use existing interfaces in Orchard.CMS:

IRepository is a standard interface, the implementation used by Linq To NHibernate Cacheble Query. Basic methods:

ISessionLocator is an interface in Orchard.CMS that provides access to an ISession interface object. Basic methods:

It is necessary to mention transactions in Orchard. By default, Orchard.CMS creates one transaction for the entire request and executes its Commit after the completion of the request. If the request is executed successfully - commit is executed, if not - the transaction is rolled back. The default data isolation level is ReadCommitted. In order to complete the current transaction and open a new one, you need to use the ITransactionManager interface. This interface provides methods for working with transactions.

It was possible to test and implement a demonstration project using the Fluent NHibernate Mapping configuration of a domain model defined in a separate assembly. The project is on github and is available for download .

This article is a recommendation to implement projects using Orchard.CMS. I would be glad if the comments describe other effective approaches for implementing the domain model within this content management system.

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


All Articles