📜 ⬆️ ⬇️

Nhibernate: Mapping Options, Query Options

In this article, I decided to put together all the information to which I regularly turn, rummaging through the Internet or in code. These are mappings and links in NHibernate. A sort of article-memo will be. I decided not to overload it too much (for example, I wrote very little about the NHibernate Queries), and therefore in each headline there will be a link to the article (in English), which I relied on when creating the memo article. I hope it will be useful to you.


I will give examples for ASP.NET MVC 4 and SQL Server 2008 (by the way, we will rarely refer to the latter, just to check how our data was stored there, and the connection string we mention). I will try to write specifically and capaciously, and if there are strange moments, I ask for the article Tutorials on FluentNHibernate c ASP.NET MVC and SQL Server. Part 1 where everything is described in more detail. So let's get started, for starters, start Visual Studio and:
  1. Create a new project File-> New-> Project .
  2. Choose ASP.NET MVC 4 (.Net Framework 4) and call it NHibernateMVC .
  3. Create an NHibernate folder in the Models folder.
  4. In the Package Manager Console, we specify the install-package nhibernate (the examples below work in FluentNhibernate, (checked!): Install-package Fluentnhibernate).


After Nhibernate is installed, the question arises as to which way we will associate (map) the classes from the application with the tables from the database. NHibernate has three types of mapping available for us, such as:

')
Variants of mappings.
1.xml files

The very first developed mapping.
Pros:
+ There are many examples on the Internet.
+ All other methods (Attributes and Fluent) are reduced to obtaining these xml files.
Minuses:
- Completely missing intellisense (!).
- There is no validation at compile time.

Well, let's consider it.
After installing NHibernate, add the Nhibernate.cfg.xml file to the Models-> NHibernate folder
<?xml version="1.0" encoding="utf-8" ?> <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> <session-factory> <property name="connection.provider"> NHibernate.Connection.DriverConnectionProvider </property> <property name="connection.driver_class"> NHibernate.Driver.SqlClientDriver </property> <property name="connection.connection_string"> Server=...\SQLENTERPRISE; database=NhibernateTutor; Integrated Security=SSPI; </property> <property name="dialect"> NHibernate.Dialect.MsSql2008Dialect </property> </session-factory> </hibernate-configuration> 

I work with SQL Server, so I chose SqlClientDriver. If you are working with another database, then the list of NHibernate.Drivers can be viewed here NHibernate.Driver
Since I have SQL Server 2008 installed, I chose MsSql2008Dialect, all dialects can be found here SQL Dialects
Create the NhibernateTutor database in SQL Server and add the connection string. In this article I will not create tables, they will be generated by NHibernate themselves.

Next, add the Book.cs class to the Models folder.
 public class Book { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual string Description { get; set; } } 

(PS All its fields must be virtual - this requirement is necessary for lazy load (lazy loading) and for NHibnerate to track all changes in objects.)

After creating a class, it's time to create a mapping for it. To do this, create an xml file in the Models-> NHibernate folder - “Book.hbm.xml”. ( Attention!
  1. All mapping files must have the extension * .hbm.xml.
  2. Go to the properties of this file (right-click on Book.hbm.xml -> Properties), and in the Advanced list, change the Build Action property to Embedded Resource . The same will need to be done again for other * .hbm.xml-files. If you do not specify it, then in the configuration.AddAssembly (typeof (Book) .Assembly); the NhibernateHelper class (which will be created later) will be an error, which is impossible for the Book class to find its mapping file.)


 <?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true" assembly="NhibernateMVC" namespace="NhibernateMVC.Models"> <class name="Book" dynamic-update="true" > <cache usage="read-write"/> <id name="Id" type="int"> <generator class="native" /> </id> <property name="Name" /> <property name="Description" /> </class> </hibernate-mapping> 

What is there to pay attention to. First, the assembly and namespace should be the same as the Book class. Id I did <generator class = "native" /> because I don’t like guid, and he himself determines which type (identity, sequence or hilo) to use, depending on the capabilities of the database (Sql Server is an identity).


Once the xml mapping has been created, create the NHibernateHelper.cs class in the root directory.
  public class NHibernateHelper { public static ISession OpenSession() { var configuration = new Configuration(); var configurePath = HttpContext.Current.Server.MapPath(@"~\Models\Nhibernate\nhibernate.cfg.xml"); configuration.Configure(configurePath); //    Book.hbm.xml Embedded Resource,          configuration.AddAssembly(typeof(Book).Assembly); ISessionFactory sessionFactory = configuration.BuildSessionFactory(); // Nhibernate         . new SchemaUpdate(configuration).Execute(true, true); return sessionFactory.OpenSession(); } } 

More information about configuring ISessionConfiguration here ISessionFactory Configuration

At the end of all these operations, the following files should have been created.


Let's now see how NHibernate creates a Book table in the database. Create a HomeController class in the Controllers folder and write the following code.
  public ActionResult Index() { var session = NHibernateHelper.OpenSession(); return View(); } 

What the View will look like does not interest us now, let it be empty. We start applications, we come into a SQL Server DB and (voila!) We see the Book table in NhibernateTutor DB. There you can change the data types at your discretion (nvarchar (255) make nvarchar (MAX), but not int!). Until we fill it with data, let's first set up the links (when the one-to-one link appears, an error will occur that the Mind table does not match the Book table) or fill in the data and then delete.



We now turn to setting up the relationship between the tables.

1.1 Relationships
Many-to-many
Book.csAuthor.cs
 private ISet<Author> _authors; public virtual ISet<Author> Authors { get { return _authors ?? (_authors = new HashSet<Author>()); } set { _author = value; } } 

 private ISet<Book> _books; public virtual ISet<Book> Books{ get { return _books?? (_books= new HashSet<Book>()); } set { _books= value; } } 

Book.hbm.xmlAuthor.hbm.xml
 <property ~~~/> ........................................... <set name="Authors" table="Book_Author" cascade="save-update"> <key column="BookId"/> <many-to-many class="Author" column="AuthorId"/> </set> 

 <property ~~~/> ........................................... <set name="Books" table="Book_Author" inverse="true" cascade = "save-update"> <key column="AuthorId"/> <many-to-many class="Book" column="BookId"/> </set> 


Let's take a look at the xml mappings of these classes. Let's start with the set tag, it is used for .NET ISet. For more information, what are the tags for collections, you can read here the Collection of Values , and I will provide a table of collections below and what tags apply to them.
.Net CollectionMapping
IEnumerable / ICollection / IListbag
IList with orderlist
ISetset
IDictionarymap




Many-to-one (one-to-many)
Book.csSeries.cs
 public virtual Series Series { get; set; } 

 private IList<Book> _books; public virtual IList<Book> Books { get { return _books ?? (_books = new List<Book>()); } set { _books = value; } } 

Book.hbm.xml
Series.hbm.xml
 <many-to-one name="Series" class="Series" column="Series_id" cascade = "save-update"/> 

 <bag name="Books" inverse="true"> <key column="Series_id"/> <one-to-many class="Book"/> </bag> 


So, what can I say? We used the tag "bag" because we have IList, column = "Series_id" creates in the Book table a column Series_Id, the rest was said above.

One to one
Book.csMind.cs
 private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } } 
 public virtual Book Book { get; set; } 
Book.hbm.xmlMind.hbm.xml
 <one-to-one name="Mind" class="Mind" constrained="true" cascade = "All"/> 
 <one-to-one name="Book" class="Book" /> 


And here it is already interesting! constrained = "true" means that for each entry in the Book table there must be an entry in the Mind table, that is, the Id of the Book table must be equal to the Id of the Mind table. If you try to save the Book object, forgetting about the Mind table, then Nhibernate will throw an exception that it cannot save data. That is, you must first create a Mind object for Book. Constantly creating a Mind object is very tiring, so when I create a Book object while saving, I initialize the Mind object with the code below, and I always have time to fill the Mind table.
 private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } } 

Cascade = "All" When saving, changing, deleting the table, the Book is also saved, modified, and the Mind table is deleted. So, we created all the links, it's time to check them, saving, editing or deleting data. Detailed information under the spoiler below.

Verifying Mapping Operation: CRUD Operations
Let's create a test application that will save data to the database, update and delete it by changing the HomeController as follows (Comment on the unnecessary parts of the code):
 public ActionResult Index() { using (ISession session = NHibernateHelper.OpenSession()) { using (ITransaction transaction = session.BeginTransaction()) { //,  var createBook = new Book(); createBook.Name = "Metro2033"; createBook.Description = " "; createBook.Authors.Add(new Author { Name = "" }); createBook.Series = new Series { Name = "" }; createBook.Mind = new Mind { MyMind = " " }; session.SaveOrUpdate(createBook); // ( ) var updateBook = session.Get<Book>(1); updateBook.Name = "Metro2033"; updateBook.Description = " "; updateBook.Authors.ElementAt(0).Name = ""; updateBook.Series.Name = ""; updateBook.Mind.MyMind = "11111"; session.SaveOrUpdate(updateBook); // ( ) var deleteBook = session.Get<Book>(1); session.Delete(deleteBook); transaction.Commit(); } var criteria = session.CreateCriteria<Book>(); criteria.CreateAlias("Series", "series", JoinType.LeftOuterJoin); criteria.CreateAlias("Authors", "author", JoinType.LeftOuterJoin); criteria.CreateAlias("Mind", "mind", JoinType.LeftOuterJoin); criteria.SetResultTransformer(new DistinctRootEntityResultTransformer()); var books = criteria.List<Book>(); return View(books); } } 

and change the view as follows:
 @model IEnumerable<NhibernateMVC.Models.Book> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <style> th, td { border: 1px solid; } </style> </head> <body> <p>@Html.ActionLink("Create New", "Create")</p> <table> <tr> <th>@Html.DisplayNameFor(model => model.Name)</th> <th>@Html.DisplayNameFor(model => model.Mind)</th> <th>@Html.DisplayNameFor(model => model.Series)</th> <th>@Html.DisplayNameFor(model => model.Authors)</th> <th></th> </tr> @foreach (var item in Model) { <tr> <td>@Html.DisplayFor(modelItem => item.Name)</td> <td>@Html.DisplayFor(modelItem => item.Mind.MyMind)</td> @{string strSeries = item.Series != null ? item.Series.Name : null;} <td>@Html.DisplayFor(modelItem => strSeries)</td> <td> @foreach (var author in item.Authors) { string strAuthor = author != null ? author.Name : null; @Html.DisplayFor(modelItem => strAuthor) <br /> } </td> <td> @Html.ActionLink("Edit", "Edit", new { id = item.Id }) | @Html.ActionLink("Details", "Details", new { id = item.Id }) | @Html.ActionLink("Delete", "Delete", new { id = item.Id }) </td> </tr> } </table> </body> </html> 

I think you can do it yourself by creating the appropriate fields for Author, Mind and Series. After checking all the operations one by one, we note that:
  • During the Create and Update operations, all data associated with the Book table is updated (remove Cascade = "save-update" or cascade = "all" and the associated data will not be saved)
  • When deleting, data is deleted from the tables Book, Mind, Book_Author, and the rest of the data is not deleted, because they have Cascade = "save-update"
  • When deleting, data is deleted from the tables Book, Mind, Book_Author, and the rest of the data is not deleted, because they have Cascade = "save-update"

Next, you can use this code to check connections in other mapping options, because Criteria works in both Attributes and Fluent. And do not forget to check the keys in the database, you never know what mistake you made, which you will learn later. For example, the Book table is referenced by the AuthorId of the Book_Author table, instead of the BookId key.


Detailed information can be found here.
NHibernate Reference Documentation

2. ATTRIBUTES
It is an add-in to Nhibernate.
Pros:
+ No need to create separate files (* .hbm.xml), write the attributes immediately above the class fields, that is, entities and mappings are nearby.
+ Support for Intellisense 50/50 (!). There are hints for writing attributes (such as Name), but not for its properties, which are represented as strings.
+ Easily upgrade from xml files to Attributes.
Minuses:
- The readability of a code worsens.
- Lack of validation at compile time.
- For properties consisting of more than 1 attribute, indexes should be specified.

There are few materials on NHibernate.Mapping.Attributes on the Internet, even on the nhibernate.info website, he has only ONE head (!) Of NHibernate.Mapping.Attributes and there is a simple explanation for this: it is an add-on to NHibernate, and therefore, in fact has the same settings as the Nhibernate * .hbm.xml files. So you use Attributes instead of nasty * .hbm.xml files. Therefore, if you use Attributes and you have problems, feel free to apply solutions that are applicable for * .hbm.xml-files, since the syntax is the same for them, it will not be difficult to figure out.
  1. Before using attributes, first delete all mapping (* .hbm.xml) files, we will not need them anymore. ( Nhibernate.cfg.xml leave!)
  2. To work with the attributes, we need NHibernate.Mapping.Attribute.dll, install it via the Package Manager Console , where we will install Install-Package NHibernate.Mapping.Attributes .
  3. Change the NHibernateHelper class as follows

  public class NHibernateHelper { public static ISession OpenSession() { var configuration = new Configuration(); var configurePath = HttpContext.Current.Server.MapPath(@"~\Models\Nhibernate\nhibernate.cfg.xml"); configuration.Configure(configurePath); //configuration.AddAssembly(typeof(Book).Assembly);     \\ HbmSerializer.Default.Validate = true; var stream = HbmSerializer.Default.Serialize(Assembly.GetAssembly(typeof(Book))); configuration.AddInputStream(stream); //*****************************************************************************************************\\ ISessionFactory sessionFactory = configuration.BuildSessionFactory(); // Nhibernate         . new SchemaUpdate(configuration).Execute(true, true); return sessionFactory.OpenSession(); } } 


Now it's time to prescribe Attributes. Modify the Book class by adding attributes there as follows
  [Class] public class Book { [Id(0, Name = "Id")] [Generator(1, Class = "native")] public virtual int Id { get; set; } [Property] public virtual string Name { get; set; } [Property] public virtual string Description { get; set; } } 

What should be noticed? First, there must be attributes above each property that you want to mute. Second, did you notice the Id (0 ...) and Generator (1 ...) indices? Indexes need to be applied to properties that consist of more than one attribute. This is due to the fact that NHMA generates * .hbm.xml files on the fly from attributes, and it must know in which order to write out xml elements. (Unfortunately, the attribute order is not supported by reflection).
Let's delete the Book table from the database (it is possible and not to delete it for verification.) We will launch the project, and if there was no Book table in the database, it will be created.
I will not write about the relationship, since the syntax is the same as for the * .hbm.xml files, the only difference is that you need to prescribe indexes for collections.

2.1 Relationships (In Tables)
Many-to-many
Book.csAuthor.cs
 [Set(0, Table = "Book_Author", Cascade = "save-update")] [Key(1, Column = "BookId")] [ManyToMany(2, ClassType = typeof(Author), Column = "AuthorId")] private ISet<Author> _authors; public virtual ISet<Author> Authors { get { return _authors ?? (_authors = new HashSet<Author>()); } set { _author = value; } } 

 [Set(0, Table = "Book_Author", Inverse = true, Cascade = "save-update")] [Key(1, Column = "AuthorId")] [ManyToMany(2, ClassType = typeof(Book), Column = "BookId")] private ISet<Book> _books; public virtual ISet<Book> Books{ get { return _books?? (_books= new HashSet<Book>()); } set { _books= value; } } 


Many-to-one, one-to-many
Book.csSeries.cs
 [ManyToOne(Name = "Series", Column = "SeriesId", ClassType = typeof(Series), Cascade = "save-update")] public virtual Series Series { get; set; } 

 [Bag(0, Name = "Books", Inverse = true)] [Key(1, Column = "SeriesId")] [OneToMany(2, ClassType = typeof(Book))] private IList<Book> _books; public virtual IList<Book> Books{ get { return _books?? (_books= new List<Book>()); } set { _books= value; } } 


One to one
Book.csMind.cs
 [OneToOne(Name = "Mind", ClassType = typeof(Mind), Constrained = true, Cascade = "All")] private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } } 

 [OneToOne(Name = "Book", ClassType = typeof(Book))] public virtual Book Book { get; set; } 



3. Mapping ByCode
Pros:
+ No additional libraries required (as is the case with attributes)
+ Support for Intellisense 100 (!).
+ No .hbm.xml files and Nhibernate.cfg.xml are required.
+ We took the best from Fluent-Nhibernate (lambda expressions) and made the syntax for * .hbm.xml files.
Minuses:
- Removed cascade Save-Update property (you can use Cascade.Persist, but still).
- The structure (in particular the relations between the classes) does not exactly correspond to the elements of * .hbm.xml files.

Will be updated ...
  1. Remove the nhibernate.cfg.xml file
  2. Change the NHibernateHelper class as follows

  public class NHibernateHelper { public static ISession OpenSession() { var cfg = new Configuration() .DataBaseIntegration(db => { db.ConnectionString = @"Server=..\SQLENTERPRISE;initial catalog=NhibernateTutor;Integrated Security=SSPI;"; db.Dialect<MsSql2008Dialect>(); }); var mapper = new ModelMapper(); mapper.AddMappings(Assembly.GetExecutingAssembly().GetExportedTypes()); HbmMapping mapping = mapper.CompileMappingForAllExplicitlyAddedEntities(); cfg.AddMapping(mapping); new SchemaUpdate(cfg).Execute(true, true); ISessionFactory sessionFactory = cfg.BuildSessionFactory(); return sessionFactory.OpenSession(); } } 


Noticed the trend? Each way removes one of the files for Nhibernate. The xml files had * .hbm.xml files and nhibernate.cfg.xml file, Attributes did not need * .hbm.xml files, and in Mapping byCode, nhibernate.cfg.xml was no longer needed. I wonder what will be removed in the new way (and will it be at all?).

The Book class and its mapping should look like this.
  public class Book { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual string Description { get; set; } } public class BookMap : ClassMapping<Book> { public BookMap() { Id(x => x.Id, map => map.Generator(Generators.Native)); Property(x=>x.Name); Property(x=>x.Description); } 


3.1 Relationships (In Tables)
Many-to-many
Book.csAuthor.cs
 private ISet<Author> _authors; public virtual ISet<Author> Authors { get { return _authors ?? (_authors = new HashSet<Author>()); } set { _author = value; } } 

 private ISet<Book> _books; public virtual ISet<Book> Books{ get { return _books?? (_books= new HashSet<Book>()); } set { _books= value; } } 

BookMap.csAuthorMap.cs
 Set(a => a.Authors, c => { c.Cascade(Cascade.Persist); c.Key(k => k.Column("BookId")); c.Table("Book_Author");}, r=>r.ManyToMany(m=>m.Column("AuthorId"))); 

 Set(a => a.Books, c => { c.Cascade(Cascade.All); c.Key(k => k.Column("AuthorId")); c.Table("Book_Author"); c.Inverse(true); }, r => r.ManyToMany(m => m.Column("BookId"))); 


Many-to-one, one-to-many
Book.csSeries.cs
 public virtual Series Series { get; set; } 

 private IList<Book> _books; public virtual IList<Book> Books{ get { return _books?? (_books= new List<Book>()); } set { _books= value; } } 

BookMap.csSeriesMap.cs
 ManyToOne(x => x.Series, c => { c.Cascade(Cascade.Persist); c.Column("Series_Id"); }); 

 Bag(x => x.Books, c => { c.Key(k => k.Column("Series_Id")); c.Inverse(true); }, r => r.OneToMany()); 



One to one
Book.csMind.cs
 private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } } 

 public virtual Book Book { get; set; } 

BookMap.csMindMap.cs
 OneToOne(x=>x.Mind, c=>{c.Cascade(Cascade.All); c.Constrained(true);}); 

 OneToOne(x=>x.Book, c=>c.Cascade(Cascade.None)); 



Detailed information here StackOverflow Mapping-by-Code

4. FLUENT
It offers an alternative to the standard mapping of NHibernate XML files. Instead of writing XML files, you write mappings in strongly typed C # code (via lambda expressions). Due to this, there is a refactoring, improved readability and ease of writing code.
Pros:
+ 100% intellisense support!
+ Fluent-Nhibernate Excellent Documentation
+ Validation at compile time
+ No need to create a file Nhibernate.cfg.xml, all settings, including the connection string, can be written in the NhibernateHelper.
Minuses:
“Compared to other versions of NHibernate, there is a slightly unusual mapping syntax.

Since FluentNhibernate and Nhibernate are a bit different, let me write as if I were re-creating the application? So let's start, create a new application.
  1. In the Package Manager Console, we specify install-package fluentnhibernate
  2. In the folder "Models" create a class "Book.cs" (Models-> Book.cs)
  3. Add the NHibernate folder to Models and create the NHibernateHelper.cs class (Models-> NHibernate-> NHibernateHelper.cs)

 public class NHibernateHelper { public static ISession OpenSession() { ISessionFactory sessionFactory = Fluently.Configure() .Database(MsSqlConfiguration.MsSql2008.ConnectionString(@"Server=..\SQLENTERPRISE; initial catalog= Biblioteca; Integrated Security=SSPI;").ShowSql() ) .Mappings(m =>m.FluentMappings.AddFromAssemblyOf<Book>()) .ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(false, true)) .BuildSessionFactory(); return sessionFactory.OpenSession(); } } 


In this NhibernateHelper.cs it should be noted that now we write the connection string to the database here. And yes, there are lambda expressions.

Fill the class Book.cs
 public class Book { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual string Description { get; set; } } 

and create a mapping class for it
  public class BookMap : ClassMap<Book> { public BookMap() { Id(x => x.Id); Map(x => x.Name); Map(x => x.Description); } } 

Next, create a HomeController class in the Controllers folder and write the following code.
 public ActionResult Index() { var session = NHibernateHelper.OpenSession(); return View(); } 

Create any View, and after running the application in SQL Server, the Book table will be created.

4.1 Relationships (In Tables)
Many-to-many
Book.csAuthor.cs
 private ISet<Author> _authors; public virtual ISet<Author> Authors { get { return _authors ?? (_authors = new HashSet<Author>()); } set { _author = value; } } 

 private ISet<Book> _books; public virtual ISet<Book> Books{ get { return _books?? (_books= new HashSet<Book>()); } set { _books= value; } } 

BookMap.csAuthorMap.cs
 HasManyToMany(x => x.Authors) .Cascade.SaveUpdate() .Table("Book_Author"); 

 HasManyToMany(x => x.Books) .Cascade.All() .Inverse().Table("Book_Author"); 


Many-to-one, one-to-many
Book.csSeries.cs
 public virtual Series Series { get; set; } 

 private IList<Book> _books; public virtual IList<Book> Books{ get { return _books?? (_books= new List<Book>()); } set { _books= value; } } 

BookMap.csSeriesMap.cs
 References(x => x.Series).Cascade.SaveUpdate(); 

 HasMany(x => x.Books) .Inverse(); 


The References method is applied on the many-to-one side, on the other side, the one-to-many method is HasMany.

One to one
Book.csMind.cs
 private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } } 

 public virtual Book Book { get; set; } 

BookMap.csMindMap.cs
 HasOne(x => x.Mind).Cascade.All().Constrained(); 

 HasOne(x => x.Book); 


The .Constrained () method tells NHibernate that a record from the Mind table must match the record from the Book table (the Mind table id must be equal to the Book table id)

Query Options (NHibernate Queries)

NHibernate has powerful query creation tools such as.



 //   , ( Get  Load) var book = session.Get<Book>(1); 

SQLCreateQuery
 //SQl- var queryBook = string.Format(@"select Id, Name, Description from Book"); //    var books = session.CreateSQLQuery(queryBook) //SQl-    .SetResultTransformer(Transformers.AliasToBean(typeof(Book))) .List<Book>().ToList(); 

Lists with restrictions
 //hql var hqlQuery = session.CreateQuery("from Book b where b.Series.Id = ? order by p.Id") // 0   int=2 .SetInt32(0,2); var books = hqlQuery.List<Book>(); //NHibernate.Linq (session.Linq in NH 2/session.Query in NH3) var linq = (from book in session.Query<Book>() where book.Series.Id == 2 orderby book.Id select book); var books = linq.ToList(); return View(books); //criteria var criteria = session.CreateCriteria<Book>() //"Restrictions"   "Expression" .Add(Restrictions.Eq("Series.Id", 3)) //Order .AddOrder(Order.Asc("Id")); var books = criteria.List<Book>(); //query over var queryOver = session.QueryOver<Book>() .Where(x => x.Series.Id == 2) .OrderBy(x => x.Id).Asc; var books = queryOver.List(); return View(books); 


NHibernate Query, Join, Projecting , , NHibernate Queries NHibernate More Queries

QueryOver, QueryOver in NH3

, .

Lazy eager-loading («» «» )
Lazy loading eager loading — , NHibernate navigation properties
-> Lazyloading — . (Book), . , navigation property (Book.Genres), . : .

 //   (View) @foreach (var item in Model) { //     Book @foreach (var genre in item.Genres) { //   Genres,    Book @Html.DisplayFor(modelItem => genre.Name) <br /> } } 

-> Eagerloading — . . join, .
 //   (View) @foreach (var item in Model) { //    Book     . @foreach (var genre in item.Genres) { @Html.DisplayFor(modelItem => genre.Name) <br /> } } 


«» NHibernate Fetch strategies.

EagerLoading LazyLoading , Query Over.
---Query Over — Lazyloading ---
  using (ISession session = NHibernateHelper.OpenSession()) { Genre genreAl = null; Author authorAl = null; Series seriesAl = null; var books = session.QueryOver<Book>() //Left Join   Genres .JoinAlias(p => p.Authors, () => authorAl, JoinType.LeftOuterJoin) .JoinAlias(p => p.Series, () => seriesAl, JoinType.LeftOuterJoin) //  id   Book. .TransformUsing(Transformers.DistinctRootEntity).List(); return View(books); } 

---Query Over — EagerLoading ---
 using (ISession session = NHibernateHelper.OpenSession()) { var books = session.QueryOver<Book>() .Fetch(a => a.Authors).Eager.Fetch(s => s.Series).Eager .TransformUsing(Transformers.DistinctRootEntity).List(); return View(books); 

, LeftJoin , Fetch Book .

Fecth — Nhibernate Fetch strategy lazy eager loading — lazy, fetch batch-size . NhibernateInfo — lazy-eager loading

, .

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


All Articles