- SessionFactoryProvider - performs the following functions:
- Configures the basic parameters of NHibernate.
- Registers entity mappings. Supports Fluent syntax.
- Based on 1 and 2 points creates SessionFactory.
-
ScopedSessionManager - provides the life cycle of NHibernate sessions within a web request. It is an analog of the Nhibernate session context. Created because none of the contexts is fully suitable for solving the problem.
-
EntityFactoryService - creates various wrappers for working with the repository. The created interfaces are abstracted from the type of storage.
-
EntityRepository - an abstract repository for working with the repository as a collection of objects. Contains additional infrastructure methods.
-
UnitOfWork - is an implementation of the "Unit of Work" template.
- Add a dependency on IEntityFactoryService to the class.
- Add the configuration file appsettings.json,
"db": [
{
"nick": "default",
"dbServerType": "DB2",
"ConnectionString":
"Database = DBNAME; UserID = user_name; Server = servername: 50000; CurrentSchema = SCHEME;"
},
{
"nick": "mssql",
"dbServerType": "MSSQL",
"ConnectionString": "Server = servername, 1433; Database = DBNAME; User ID = user_name;"
}
]
For each connection to the database, a separate list item is created containing the following parameters:
- nick - the name of the connection to the database. Unique identificator.
- dbServerType - type of database to which the connection is made.
- connectionString - connection string to the database
3a. If you just need to read the entity from the database, then just create a repository and call the Get method, passing the Id into it.
return _entityFactoryService.Create<Entity>()
.Get(message.Id);
3b. If you want to read database entities with filtering, you can use the LINQ query.
return _entityFactoryService.Create<Entity>()
.Query().Where(x => x.Status == EntityStatus.Processed && x.UpdateDate < DateTime.Today);
4a. In the event of an entity change, a unit of work must be created. Changes in the fields of an entity must occur in it.
using (var unitOfWork = _entityFactoryService.Create())
{
var entity = _entityFactoryService.Create<Entity>().Get(message.Id);
entity.DoStaff(message);
unitOfWork.Commit();
}
4b. If an entity is created, use the Add method to add it.
using (var unitOfWork = _entityFactoryService.Create())
{
var entityRepository = _entityFactoryService.Create<Entity>();
var entity = Entity.Create(message);
entityRepository.Add(entity);
unitOfWork.Commit();
}
4c. The Add method, if there is an entity with the same identifier in the collection, will try to execute the Update request. If this behavior should be prohibited, you can use the Insert method, which in the same case will throw an exception.
- You can delete an entity using the Delete method.
using (var unitOfWork = _entityFactoryService.Create())
{
var entityRepository = _entityFactoryService.Create<Entity>();
var entity = entityRepository.Get(message.Id);
entityRepository.Delete(entity);
unitOfWork.Commit();
}
- When processing in manually created tasks, it is additionally necessary to create scope sessions. Without this, exceptions will occur during operation.
return await Task.Run(() =>
{
using (_entityFactoryService.GetScopedSession())
{
return _entityFactoryService.Create<Entity>()
.Get(message.Id);
}
});
- For the correct operation of the entity must be registered in a limited context of the service. To do this, create a class in the assembly
internal sealed class TestLogicsContext: ApplicationContext
{
public TestLogicsContext()
{
AddEntity<Card>();
AddEntity<Product>("mssql");
}
}
and register it in the DI with the IBoundedContext interface.
container.Collection.Append<IBoundedContext, TestLogicsContext>(Lifestyle.Singleton);
To create a SQL query to the database, you need to create a query class.
internal class EntityDetailsQuery : BaseQuery<EntityDetailsItem>
{
private const string query = @"SELECT FIELD, ANOTHER_FIELD
FROM SCHEME.ENTITY SE
WHERE SE.WHERE_FIELD = :data";
public EntityDetailsQuery(string data)
{
Parameters = new Dictionary<string, object>();
Parameters["data"] = data;
sql = query;
}
protected override EntityDetailsItem TransformTuple(object[] tuple, string[] aliases)
{
return new EntityDetailsItem(tuple[0].ToStringSafe(), (DateTime?)tuple[1]);
}
}
Next, you need to create a query executor and call it with the created instance of the command.
var query = new EntityDetailsQuery("keyData");
var customQueryExecutor = _entityFactoryService.CreateCommandExecutor<EntityDetails>();
IEnumerable <EntityDetails> entityDetails = customQueryExecutor.CustomQuery(query);
To create an SQL command to the database, you need to create a command class.
public class EntityCommand: BaseCommand
{
private EntityCommand()
{
}
public static EntityCommand Create(int cnum)
{
return new EntityCommand
{
Parameters = new Dictionary<string, TypeWrapper>
{
{"P_CNUM", new TypeWrapper(cnum, typeof(int))}
},
Sql = "CALL SCHEME.ENTITY_COMMAND(:P_CNUM)"
};
}
}
Next, you need to create an executor of commands and call it with the created instance of the command.
var command = new EntityCommand(123456);
var commandExecutor = _entityFactoryService.CreateCommandExecutor<EntityCommand>();
commandExecutor.Execute(command);
Now ViennaNET.Orm use Microsoft.Extensions.Logging instead of ViennaNET.Logging (log4net). That means you should use standard configuration section for rule output logs with parameters you want, e.g.:
"Logging": {
"LogLevel": {
...,
"ViennaNET.Orm": "Information",
"NHibernate": "Error",
"NHibernate.Sql": "Debug",
}
}
Useful options for LogLevel parameters:
- To log SQL requests with parameters you should set log level of NHibernate.Sql to Debug
- To log query execution time you should set log level of NHibernate.AdoNet.AbstractBatcher to Debug. Ad i logs you get
ExecuteReader took X ms
for query execution andDataReader was closed after X ms
for data mapping