天道酬勤,学无止境

Eager Loading Using Fluent NHibernate/Nhibernate & Automapping

I have a requirement to load a complex object called Node...well its not that complex...it looks like follows:-

A Node has a reference to EntityType which has a one to many with Property which in turn has a one to many with PorpertyListValue

public class Node
{
    public virtual int Id
    {
        get;
        set;
    }

    public virtual string Name
    {
        get;
        set;
    }

    public virtual EntityType Etype
    {
        get;
        set;
    }

}


public class EntityType
{
    public virtual int Id
    {
        get;
        set;
    }

    public virtual string Name
    {
        get;
        set;
    }

    public virtual IList<Property> Properties
    {
        get;
        protected set;
    }

    public EntityType()
    {
        Properties = new List<Property>();
    }
}

public class Property
{
    public virtual int Id
    {
        get;
        set;
    }

    public virtual string Name
    {
        get;
        set;
    }        

    public virtual EntityType EntityType
    {
        get;
        set;
    }

    public virtual IList<PropertyListValue> ListValues
    {
        get;
        protected set;
    }

    public virtual string DefaultValue
    {
        get;
        set;
    }

    public Property()
    {
        ListValues = new List<PropertyListValue>();
    }
}


public class PropertyListValue
{
    public virtual int Id
    {
        get;
        set;
    }

    public virtual Property Property
    {
        get;
        set;
    }

    public virtual string Value
    {
        get;
        set;
    }

    protected PropertyListValue()
    {
    }
}

What I a trying to do is load the Node object with all the child objects all at once. No Lazy load. The reason is I have thousands of Node objects in the database and I have to send them over the wire using WCF Service.I ran into the classes SQL N+ 1 problem. I am using Fluent Nhibernate with Automapping and NHibernate Profiler suggested me to use FetchMode.Eager to load the whole objects at once. I am using the following qyuery

     Session.CreateCriteria(typeof (Node))
            .SetFetchMode( "Etype", FetchMode.Join )
            .SetFetchMode( "Etype.Properties", FetchMode.Join )
            .SetFetchMode( "Etype.Properties.ListValues", FetchMode.Join )

OR using NHibernate LINQ

        Session.Linq<NodeType>()
         .Expand( "Etype")
         .Expand( "Etype.Properties" )
         .Expand( "Etype.Properties.ListValues" )

When I run any of the above query, they both generate one same single query with all the left outer joins, which is what I need. However, for some reason the return IList from the query is not being loaded property into the objects. Infact the returned Nodes count is equal to the number of rows of the query, so the Nodes objects are repeated.Moreover, the properties within each Node are repeated, and so do the Listvalues.

So I would like to know how to modify the above query to return all unique Nodes with the properties and list values within them.

评论

each mapping has to have lazy loading off

in Node Map:

Map(x => x.EntityType).Not.LazyLoad();

in EnityType Map:

Map(x => x.Properties).Not.LazyLoad();

and so on...

Also, see NHibernate Eager loading multi-level child objects for one time eager loading

Added:

Additional info on Sql N+1:

http://nhprof.com/Learn/Alerts/SelectNPlusOne

I figure it out myself. The key is to use SetResultTransformer() passing an object of DistinctRootEntityResultTransformer as a parameter. So the query now looks like as follows

Session.CreateCriteria(typeof (Node))
   .SetFetchMode( "Etype", FetchMode.Join )
   .SetFetchMode( "Etype.Properties", FetchMode.Join )
   .SetFetchMode( "Etype.Properties.ListValues", FetchMode.Join )
   .SetResultTransformer(new DistinctRootEntityResultTransformer());

I found the answer to my questions through these links:

http://www.mailinglistarchive.com/html/nhusers@googlegroups.com/2010-05/msg00512.html

http://ayende.com/Blog/archive/2010/01/16/eagerly-loading-entity-associations-efficiently-with-nhibernate.aspx

I ended up with something like this:

HasMany(x => x.YourList).KeyColumn("ColumnName").Inverse().Not.LazyLoad().Fetch.Join()

Just make sure to select your entity like this, to avoid duplication due to the join:

session.CreateCriteria(typeof(T)).SetResultTransformer(Transformers.DistinctRootEntity).List<T>();

SetResultTransformer with DistinctRootEntityResultTransformer will only work for Main object but IList collections will be multiplied.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 实体框架4与NHibernate [关闭](Entity Framework 4 vs NHibernate [closed])
    问题 关门了。 这个问题是基于意见的。 它当前不接受答案。 想改善这个问题吗? 更新问题,以便通过编辑此帖子以事实和引用的形式回答。 6年前关闭。 改善这个问题 在网络上(以及在stackoverflow上)已经谈论了很多关于Entity Framework第一版的问题,很明显,当我们已经有了更好的替代方案(如NHibernate)时,这不是一个好选择。 但是我找不到Entity Framework 4和NHibernate的很好的比较。 我们可以说今天NHibernate在所有.NET ORM中处于领先地位,但是我们可以期望Entity Framework 4取代NHibernate的位置。 我认为,如果Microsoft确实在EF4中注入了非常好的功能,则它可以与NHibernate竞争,因为它具有Visual Studio集成,易于使用并且在大多数商店中总是优先考虑MS产品。 回答1 EF4对于“自我跟踪实体”中的n层开发具有开箱即用的答案。 没有人发布过类似的NHib代码。 NHib具有许多未被提及为EF4的功能。 这些包括二级缓存集成。 它还在继承映射方面具有更大的灵活性,可以与存储的proc /数据库函数/自定义SQL /触发器更好地集成,支持公式属性等。 IMO作为ORM基本上已经成熟了。 回答2 更新:从版本4.0开始,我还没有使用实体框架
  • IndexOutOfRangeException在NHibernate的深处(IndexOutOfRangeException Deep in the bowels of NHibernate)
    问题 我有以下映射: public class SecurityMap : ClassMap<Security> { public SecurityMap() { Table("Security"); CompositeId().KeyProperty(k => k.Id, "SecurityId").KeyProperty(k => k.EndDate); Map(x => x.LastUpdateUser); References(x => x.Company).Columns("CompanyId", "EndDate"); References(x => x.PrimaryListing).Columns("PrimaryListingId", "EndDate"); } } public class ListingMap : ClassMap<Listing> { public ListingMap() { Table("Listing"); CompositeId().KeyProperty(k => k.Id, "ListingID").KeyProperty(k => k.EndDate); References(x => x.Security).Columns("SecurityId","EndDate"); } } public class CompanyMap
  • IndexOutOfRangeException Deep in the bowels of NHibernate
    I have the following mappings: public class SecurityMap : ClassMap<Security> { public SecurityMap() { Table("Security"); CompositeId().KeyProperty(k => k.Id, "SecurityId").KeyProperty(k => k.EndDate); Map(x => x.LastUpdateUser); References(x => x.Company).Columns("CompanyId", "EndDate"); References(x => x.PrimaryListing).Columns("PrimaryListingId", "EndDate"); } } public class ListingMap : ClassMap<Listing> { public ListingMap() { Table("Listing"); CompositeId().KeyProperty(k => k.Id, "ListingID").KeyProperty(k => k.EndDate); References(x => x.Security).Columns("SecurityId","EndDate"); } }
  • DateTime precision in NHibernate and support for DateTime2 in NHibernate SchemeExport
    I am then using Fluent NHibernate and its automapping feature to map the the following simplified POCO class: public class Foo { public virtual int Id { get; set; } public virtual datetime CreatedDateTime { get; set; } } The CreatedDateTime field will map to a SQL DateTime by default. However if I do a test to check that the entity is being created correctly it fails. This is because the precision of the DateTime field is not maintained through to the SQL database. I undersatnd the reason behind this to be that a MS SQL Server DateTime can only hold milisecond precision by rounded to
  • Some suggestions on which .NET ORM to look at learning
    I am a little ashamed to say that I have never used an ORM; as you may recall most of my career experience is hacking around with Classic ASP and the little .NET I do tends to be maintenance only. For my own career as well as in preparation for a new project at work (done in .NET finally!) I'm looking at adding an ORM to my skillset - being the masochist I am I'm also going to look at TDD while I'm at it for this project. Anyways, I am using .NET 3.5 for the project (or plan to, anyways) so I am trying to decide what ORM I want to choose; like I said I am not really familiar with them but I
  • Entity Framework Code First Case Sensitivity on string PK/FK Relationships
    I have a fairly simple composite one to many relationship defined using POCO/Fluent API, one column of which is a string. I've discovered that the data in this column in our database is inconsistent in terms of case ie 'abb', 'ABB' - this is our main ERP system and is fed by a variety of sources which are mainly beyond our control. This is leading to problems using EF code first when joining to related tables as the join is silently ignored by EF when the case of PK/FK is different even though SQL Profiler shows the correct SQL being executed and results returned. I'm using WCF so have lazy
  • 延迟加载与急切加载(Lazy Loading vs Eager Loading)
    问题 实体框架中的延迟加载是加载和访问相关实体时发生的默认现象。 但是,急切加载是指对所有这些关系强制加载的做法。 我遇到了一个问题:在什么情况下,优先加载比延迟加载更有利。 这样做,是因为很明显,延迟加载对资源更友好,即使我们使用ToList()方法,我们仍然可以利用延迟加载行为。 但是,我认为延迟加载可能会增加对实际数据库的请求数量,这也许就是为什么有时开发人员使用Inlcude方法强制加载所有关系的原因。 例如,在MVC 5中使用Visual Studio自动脚手架时,在控制器中自动创建的Index方法始终使用“急切加载”,而我一直有一个问题,为什么在这种情况下,Microsoft默认使用“急切加载”。 如果有人向我解释在什么情况下,优先加载比延迟加载更有利,并且在有比延迟加载更友好的资源的情况下,为什么我们完全使用它,我将不胜感激。 回答1 我认为对这样的关系进行分类是很好的 何时使用紧急加载 在一对多关系的“一侧”中,您确定在每个位置都与主要实体一起使用了该关系。 例如文章的用户属性。 产品的类别属性。 通常,当关系不是太多并且需要快速加载时,减少在服务器上的进一步查询将是一个好习惯。 何时使用延迟加载 一对多关系的几乎每个“集合方”。 像用户文章或某个类别的产品您完全知道您将不需要即时财产。 注意:就像Transcendent所说的,延迟加载可能存在处理问题。 回答2
  • Lazy Loading vs Eager Loading
    Lazy loading in Entity Framework is the default phenomenon that happens for loading and accessing the related entities. However, eager loading is referred to the practice of force-loading all these relations. I have come across the question of under what situation eager loading could be more beneficial than lazy loading. Asking this, because it is obvious that lazy loading is more resource friendly, and even if we use the ToList() method, we can still take advantage of the lazy loading behavior. However, I thought maybe lazy loading increases the number of requests to the actual database and
  • 实体框架渴望负载不返回数据,延迟负载(Entity Framework Eager Load Not Returning Data, Lazy Load Does)
    问题 我先使用代码EF5 ,我有一个对象,该对象的集合定义为virtual (延迟加载)。 调用时将返回数据。 但是我希望它能被加载。 我已经从属性签名中删除了virtual ,但是现在它总是返回null数据。 EF甚至没有运行查询,任何人都可以帮忙吗? 编辑:我知道.include()我只想使用非虚拟属性方法来做到这一点。 对象 User ( [Key] ID位于资源对象上,该对象是人员类的父对象): namespace Entities { [Table("Users")] public class User : Person { [Required] public ICollection<Role> Roles { get; set; } } } 角色: namespace Entities { public class Role { [Key] public string Id { get; set; } public virtual ICollection<User> Users { get; set; } } } 回答1 这是一个普遍的困惑。 懒加载相反的是:没有加载,除非你明确地做自己负载(例如,通过使用预先加载Include )。 因此,如果您以任何方式关闭延迟加载-删除virtual修饰符就是其中之一-这种行为不会变成渴望加载,而是不会加载。 考虑一下
  • Entity Framework 4.1 default eager loading
    I'm using Entity Framework 4.1 code first approach. I want to make eager loading as my the dafault configuration, and by that avoid using the Include extension method in each fetching query. I did as recomended in MSDN, changing the simple lazy property at the DbContext constructor: public class EMarketContext : DbContext { public EMarketContext() { // Change the default lazy loading to eager loading this.Configuration.LazyLoadingEnabled = false; } } unfortunately, this approach is not working. I have to use the Include method to perform eager loading in each query. Any ideas why? Thanks in
  • Eager , Lazy and explicit loading in EF6
    I have read this tutorial and this article but I don't understand exactly the use of each loading type. I Explain I have this POCO : public partial class dpc_gestion { public dpc_gestion() { this.ass_reunion_participant = new HashSet<ass_reunion_participant>(); this.dpc_participant = new HashSet<dpc_participant>(); this.dpc_reunion = new HashSet<dpc_reunion>(); } public int dpc_id_pk { get; set; } public Nullable<int> dpc_id_gdp_fk { get; set; } public Nullable<int> dpc_id_theme { get; set; } public int dpc_id_animateur_fk { get; set; } public Nullable<System.DateTime> dpc_date_creation { get
  • 什么是渴望加载?(What is eager loading?)
    问题 什么是渴望加载? 我用PHP / JS编写代码,但是更通用的答案就可以了。 我看到了很多有关Java和Ruby的问题,但是我不知道这些语言中的任何一种,而且我很难阅读代码。 首先我不知道该怎么办 回答1 分为三个级别: 渴望加载:在被询问时您可以做所有事情。 经典示例是将两个矩阵相乘。 您进行所有计算。 渴望加载; 延迟加载:仅在需要时进行计算。 在前面的示例中,在访问结果矩阵的元素之前,您无需进行任何计算; 和急切加载:您可以在此处尝试预期用户的要求并对其进行预加载。 我希望在您看到的情况下这是有道理的。 让我给您一个“ Webby”示例。 想象一个页面,其中包含菜单项或导航之类的过渡图像。 在此页面上可以通过三种方式加载图像: 在呈现页面之前加载所需的每张图像( eager ); 仅在页面加载时加载显示的图像,并在需要时加载其他图像(惰性); 和在页面加载时仅加载显示的图像。 页面加载后,在需要时将其他图像预加载到背景中(过度使用)。 有道理? 回答2 这与延迟加载相反,延迟加载推迟了对象的初始化,直到需要该对象为止。 渴望加载会在创建对象时初始化它。 回答3 如果您想象自己有一个叫人的对象,该人具有名字,出生日期和不太重要的细节,那么可以说喜欢的颜色,喜欢的电视节目。 要延迟加载该类,您可能需要从数据库中读取所有更频繁使用的核心详细信息(例如姓名和出生日期)
  • Getting specific columns with eager loading laravel 4
    I am new to laravel and making a basic application to get a grip on relationships.I have implemented one to one relationship and want to get specific columns from both the base table and the related table.I have two tables namely users and identity_cards.Relationship is defined as follows class User extends Eloquent implements UserInterface, RemindableInterface { use UserTrait, RemindableTrait; /** * The database table used by the model. * * @var string */ protected $table = 'users'; /** * The attributes excluded from the model's JSON form. * * @var array */ //protected $hidden = array(
  • Eager loading property of derived class using Include
    I have classes like: Person { Name Address } Employee : Person { Compensation - object } Visitor : Person { } If I write linq: var persons = Context.Persons .Include("Compensation"); I get error: A specified Include path is not valid. The EntityType 'Person' does not declare a navigation property with the name 'Compensation'. It works ok if I do: var persons = Context.Persons .OfType<Employee>() .Include("Compensation"); But I would like to get Employees and visitors in the same query. Looks like there is a request for this feature on EF4 UserVoice: http://data.uservoice.com/forums/72025-ado
  • Entity Framework Core 2.0.1 Eager Loading on all nested related entities
    I have a simple problem, but cant seem to find a way around it. I am using Entity Framework Core version 2.0.1 and want to eager load all my entities by default. Example: public class Order { public int Id { get; set; } public string Name { get; set; } public int CustomerId { get; set; } public Customer Customer { get; set; } } public class Customer { public int Id { get; set; } public string Name { get; set; } public int AddressId { get; set; } public Address Address { get; set; } } public class Address { public int Id { get; set; } public string PostCode { get; set; } public string City {
  • Linq for NHibernate and fetch mode of eager loading
    Is there a way to set the fetchmode to eager for more than one object using linq for nhibernate. There seems to be an expand method which only allows me to set one object. However I need to set it for more than one object. Is this possible? Thanks
  • Dynamic Include statements for eager loading in a query - EF 4.3.1
    I have this method: public CampaignCreative GetCampaignCreativeById(int id) { using (var db = GetContext()) { return db.CampaignCreatives .Include("Placement") .Include("CreativeType") .Include("Campaign") .Include("Campaign.Handshake") .Include("Campaign.Handshake.Agency") .Include("Campaign.Product") .AsNoTracking() .Where(x => x.Id.Equals(id)).FirstOrDefault(); } } I would like to make the list of Includes dynamic. I tried: public CampaignCreative GetCampaignCreativeById(int id, string[] includes) { using (var db = GetContext()) { var query = db.CampaignCreatives; foreach (string include in
  • Laravel 5 eager loading with limit
    I have two tables, say "users" and "users_actions", where "users_actions" has an hasMany relation with users: users id | name | surname | email... actions id | id_action | id_user | log | created_at Model Users.php class Users { public function action() { return $this->hasMany('Action', 'user_id')->orderBy('created_at', 'desc'); } } Now, I want to retrieve a list of all users with their LAST action. I saw that doing Users::with('action')->get(); can easily give me the last action by simply fetching only the first result of the relation: foreach ($users as $user) { echo $user->action[0]-
  • Rails Eager Loading on All Finds
    OK, I've been playing around with some of the eager loading things, and have 2 models something like: Class Recipe < ActiveRecord::Base belongs_to :cookbook has_many :recipetags end and Class Cookbook < ActiveRecord::Base has_many :recipes, :include => [:recipetags] end Which is working out well, when I find a Cookbook, then I eager load the recipes, and in turn the recipes eager load the :recipetags: cb = Cookbook.find(10590, :include => [:recipes]) But what I want to also do is whenever I open a recipe, have it pull in all of it's eager associations automatically - basically I want to do
  • 渴望/自动加载EJB /在启动时加载EJB(在JBoss上)(Eager / auto loading of EJB / load EJB on startup (on JBoss))
    问题 EJB似乎是延迟加载的-每当访问时。 但是,我想热切地初始化它们-即每当容器启动时。 如何实现的(特别是在JBoss中) 该主题提供了一些提示,但并不十分令人满意。 回答1 从EJB 3.1开始,可以将模块的启动和停止通知单例bean: @Singleton @Startup public class StartupBean { @PostConstruct private void postConstruct() { /* ... */ } @PreDestroy private void preDestroy() { /* ... */ } } 在EJB 3.1之前,没有标准的纯EJB解决方案。 我建议将WAR添加到您的EAR并使用servlet-context-listener。 回答2 根据Adam Bien的“现实世界Java EE模式-重新思考最佳实践”(请参阅​​模式摘要)和Service Starter模式,这确实是bkail所建议的 使用Java EE 6 = EJB 3.1时,将@Singleton与@Startup一起使用(也许也与@DependsOn一起使用) 在此之前,唯一的标准且可移植的方法是使用Servlet API,例如,一个HttpServlet以其init()方法启动EJB,并在web.xml中将load-on-startup设置为1。