다음을 통해 공유


Core 2.0: Work with Fluent NHibernate

Introduction

NHibernate is an object-relational mapping (ORM) framework, it allow to map the object oriented domain model with the tables in a relational Database. To realize the mapping, we have to write XML mapping files (.hbm.xml files), and to make it easier, here comes Fluent NHibernate as an abstraction layer to do it in C# rather than XML.

Database supported by NHibernate are;

  • SQL Server
  • SQL Server Azure
  • Oracle
  • PostgreSQL
  • MySQL
  • SQLLite
  • DB2;
  • Sybase Adaptive Server
  • Firebird
  • Informix

It can support even the use of OLE DB (Object Linking and Embedding) even ODBC (Open Database Connectivity)

What make NHibernate stronger than Entity Framework is that it integrate querying API set like LINQ, Criteria API (implementation of the pattern Query Object), integration with Lucene.NET, use of SQL even stored procedures.

NHibernate also supports:

  • Second Level cache (used among multiple ISessionFactory).

  • Multiple way of ID generation such as Identity, Sequence, HiLo, Guid, Pooled even Native mechanism used in databases.

  • Flushing properties (FlushMode properties in ISession that can take these values: Auto or Commit or Never).

  • Lazy Loading.

  • Generation and updating system like migration API in Entity framework. (Like Code First).

When Microsoft started working on the framework Core, much functionality in NHibernate wasn't supported in .NET Core as target platform, but from the version Core 2.0, we can integration NHibernate even Fluent NHibernate.

NuGet package

The NuGet package to use Fluent NHibernate:

PM>  Install-Package FluentNHibernate -Version 2.1.2

Create Entities

This folder will include two entities: Person and Task.

Person Entity

1.public class Person
2.{
3.public virtual  int Id { get; set; }
4.public virtual  string Name { get; set; }
5.public virtual DateTime CreationDate { get;  set; }
6.public virtual DateTime UpdatedDate { get;  set; }
7.}

Task Entity

01.public class Task
02.{
03.public virtual  string Id { get; set; }
04.public virtual  string Title { get; set; }
05. 
06.public virtual  string Description { get; set; }
07. 
08.public virtual DateTime CreationTime { get;  set; }
09. 
10.public virtual TaskState State { get;  set; }
11. 
12.public virtual Person AssignedTo { get;  set; }
13. 
14.public virtual DateTime CreationDate { get;  set; }
15.public virtual DateTime UpdatedDate { get;  set; }
16. 
17.public Task()
18.{
19.CreationTime = DateTime.UtcNow;
20.State = TaskState.Open;
21.}
22. 
23.}
24. 
25.public enum TaskState : byte
26.{
27./// <summary>
28./// The task is Open.
29./// </summary>
30.Open = 0,
31./// <summary>
32./// The task is active.
33./// </summary>
34.Active = 1,
35. 
36./// <summary>
37./// The task is completed.
38./// </summary>
39.Completed = 2,
40. 
41./// <summary>
42./// The task is closed.
43./// </summary>
44.Closed = 3
45.}

Create Mappings

This folder will contain the mapping classes for the previous entities.

PersonMap

01.public class PersonMap : ClassMap<Person>
02.{
03.public PersonMap()
04.{
05.Id(x => x.Id);
06. 
07.Map(x => x.Name);
08. 
09.Map(x => x.CreationDate);
10.Map(x => x.UpdatedDate);
11.}
12. 
13. 

TaskMap

01.public class TaskMap : ClassMap<Task>
02.{
03.public TaskMap()
04.{
05.Id(x => x.Id);
06. 
07.Map(x => x.CreationTime);
08.Map(x => x.State);
09.Map(x => x.Title);
10.Map(x => x.Description);
11.Map(x => x.UpdatedDate);
12.Map(x => x.CreationDate);
13. 
14.References(x => x.AssignedTo);
15.}
16.}

Create the SessionFactory Builder

01.public class SessionFactoryBuilder
02. {
03. 
04. public static ISessionFactory BuildSessionFactory(string connectionStringName, bool create = false, bool update = false)
05. {
06. return Fluently.Configure()
07. .Database(PostgreSQLConfiguration.Standard
08. .ConnectionString(ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString))
09. //.Mappings(m => entityMappingTypes.ForEach(e => { m.FluentMappings.Add(e); }))
10. .Mappings(m =>m.FluentMappings.AddFromAssemblyOf<NHibernate.Cfg.Mappings>())
11. .CurrentSessionContext("call")
12. .ExposeConfiguration(cfg => BuildSchema(cfg, create, update))
13. .BuildSessionFactory();
14. }
15. 
16. 
17. /// <summary>
18. /// Build the schema of the database.
19. /// </summary>
20. /// <param name="config">Configuration.</param>
21. private static  void BuildSchema(Configuration config, bool create = false, bool update = false)
22. {
23. if (create)
24. {
25. new SchemaExport(config).Create(false, true);
26. }
27. else
28. {
29. new SchemaUpdate(config).Execute(false, update);
30. }
31. }
32. }

Create Services

This folder will include all different treatment that we can do like GetAll element of an Entity, add new element in database for example, in this sample, I will include two services according to our entities.

PersonService

01.public class PersonService
02.{
03.public static  void GetPerson(Person person)
04. 
05.{
06. 
07.Console.WriteLine(person.Name);
08. 
09.Console.WriteLine();
10. 
11.}
12. 
13. 
14.}

TaskService

01.public class TaskService
02.{
03.public static  void GetTaskInfo(Task task)
04. 
05.{
06. 
07.Console.WriteLine(task.Title);
08.Console.WriteLine(task.Description);
09.Console.WriteLine(task.State);
10.Console.WriteLine(task.AssignedTo.Name);
11. 
12. 
13.Console.WriteLine();
14. 
15.}
16.}

Add and display Table content

Now, we will try to display data from database or add a new element.

In the program, we will start by creating a session factory using the method: BuildSessionFactory implemented inside the class SessionFactoryBuilder after, we will open a new Session for every Transaction done. We start a new Transaction inside, and it depend from the operation, if we need to insert a new line in the database, we use session.SaveOrUpdate(MyObjectToAdd); after we commit this using this transaction: transaction.Commit();

This is the main:

01.static void Main(string[] args)
02. {
03. // create our NHibernate session factory
04. string connectionStringName = "add here your connection string";
05. var sessionFactory = SessionFactoryBuilder.BuildSessionFactory(connectionStringName, true,  true);
06. 
07. using (var session = sessionFactory.OpenSession())
08. {
09. // populate the database
10. using (var transaction = session.BeginTransaction())
11. {
12. // create a couple of Persons
13. 
14. var person1 = new Person { Name = "Rayen Trabelsi" };
15. 
16. var person2 = new Person { Name = "Mohamed Trabelsi" };
17. 
18. var person3 = new Person { Name = "Hamida Rebai" };
19. 
20. //create tasks
21. 
22. var task1 = new Task {Title = "Task 1", State = TaskState.Open, AssignedTo = person1};
23. var task2 = new Task { Title = "Task 2", State = TaskState.Closed, AssignedTo = person2 };
24. var task3 = new Task { Title = "Task 3", State = TaskState.Closed, AssignedTo = person3 };
25. 
26. // save both stores, this saves everything else via cascading
27. session.SaveOrUpdate(task1);
28. 
29. session.SaveOrUpdate(task2);
30. 
31. session.SaveOrUpdate(task3);
32. 
33. transaction.Commit();
34. 
35. }
36. using (var session2 = sessionFactory.OpenSession())
37. 
38. {
39. 
40. //retreive all tasks with person assigned to
41. 
42. using (session2.BeginTransaction())
43. 
44. {
45. var tasks = session.CreateCriteria(typeof(Task))
46. 
47. .List<Task>();
48. foreach (var task in tasks)
49. {
50. TaskService.GetTaskInfo(task);
51. }
52. }
53. }
54. Console.ReadKey();
55. }
56. }
57.}

Conclusion

This sample is a sample use of Fluent NHibernate, in another article; I will show you another web sample using some of advantages like Criteria APIs.