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:
- Create a new project File-> New-> Project .
- Choose ASP.NET MVC 4 (.Net Framework 4) and call it NHibernateMVC .
- Create an NHibernate folder in the Models folder.
- 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:
- XML. Create a * .hbm.xml mapping file
- Attributes. It is an add-in for xml-mapping. Mapping looks like .NET attributes
- Mapping by code. - instead of xml-files are used * .cs ConfORM mapping classes
- Fluent. Create * .cs fluent mapping classes
')
Variants of mappings.1.xml filesThe 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.DriverSince I have SQL Server 2008 installed, I chose MsSql2008Dialect, all dialects can be found here
SQL DialectsCreate 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!- All mapping files must have the extension * .hbm.xml.
- 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).
- The complete list of generators is here IdGenerator .
- A list of class properties.
- A list of Id properties can be read here.
- Property List Property .
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);
More information about configuring ISessionConfiguration here
ISessionFactory ConfigurationAt 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 RelationshipsMany-to-manyBook.cs | Author.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.xml | Author.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 Collection | Mapping |
---|
IEnumerable / ICollection / IList | bag |
IList with order | list |
ISet | set |
IDictionary | map |
- table = "Book_Author" - an attribute that creates an intermediate Book_Author table, necessary for a many-to-many relationship.
- name = "Books / Authors" - indicates the name of the collection
- cascade = "save-update" - indicates that when saving and updating, the tables associated with it are also saved and updated. Types cascade = "all | none | save-update | delete | all-delete-orphan", in more detail here LifeCycles and object graphs
- inverse = "true" means that the opposite Book table is the parent (responsible for the relationship) and will be updated. Inverse true example can be found here.
- key column = "BookId" - indicates that the Book table will be associated with the Book_Author table by the BookId key
- many-to-many class = "Author" column = "AuthorId" - indicates that the Book table will be associated with the Author table by the "AuthorId" key
Many-to-one (one-to-many)Book.cs | Series.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 oneBook.cs | Mind.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.xml | Mind.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 OperationsLet'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()) {
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 Documentation2. ATTRIBUTESIt 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.
- Before using attributes, first delete all mapping (* .hbm.xml) files, we will not need them anymore. ( Nhibernate.cfg.xml leave!)
- 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 .
- 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);
- configurePath - Indicates the path to the configuration of the file Nhibernate
- HbmSerializer.Default.Validate - enables or disables checking generated xml streams
- HbmSerializer.Default.Serialize - serializes classes to xml files
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-manyBook.cs | Author.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-manyBook.cs | Series.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 oneBook.cs | Mind.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 ByCodePros:
+ 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 ...- Remove the nhibernate.cfg.xml file
- 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-manyBook.cs | Author.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.cs | AuthorMap.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-manyBook.cs | Series.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.cs | SeriesMap.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 oneBook.cs | Mind.cs |
---|
private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } }
| public virtual Book Book { get; set; }
|
BookMap.cs | MindMap.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-Code4. FLUENTIt 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.
- In the Package Manager Console, we specify install-package fluentnhibernate
- In the folder "Models" create a class "Book.cs" (Models-> Book.cs)
- 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-manyBook.cs | Author.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.cs | AuthorMap.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-manyBook.cs | Series.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.cs | SeriesMap.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 oneBook.cs | Mind.cs |
---|
private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } }
| public virtual Book Book { get; set; }
|
BookMap.cs | MindMap.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.
- The session.Get and session.Load methods. Obtaining (list) of object (s) by primary key.
- SQL (CreateSQLQuery method) - mainly used to convert a SQL script to a specific class
- HQL is a SQL-like language, well suited for static queries.
- LINQ to NHibernate - In NHibernate 2x, linq queries were set by the ISession.Linq <T> interface, which worked well for simple queries. With the release of Nhibernate 3 (the interface has changed to ISession.Query <T>), it gained more opportunities, although it was not widely used among programmers
- Criteria ( ) — , .
- QueryOver ( ) — NHibernate 3. , intellisense
SQLCreateQuery
Lists with restrictions
NHibernate Query, Join, Projecting , ,
NHibernate Queries NHibernate More QueriesQueryOver,
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)
---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, .