代码之家  ›  专栏  ›  技术社区  ›  Ben Hoffman

从所有表中获取数据,而不是使用只应获取1个表数据的HQL查询获取数据

  •  3
  • Ben Hoffman  · 技术社区  · 15 年前

    我在数据库中创建了3个表,并将数据放入其中。这三张桌子都有连接在一起的外键。下面是表类和那里的映射。当我运行末尾列出的查询时,我会得到对象的ilist<gt;,它们具有来自所有3个表的数据。但是,我的HQL查询只来自最上面的表。我怎样才能从最上面的表中得到结果呢?

    以下是我的课程:

    public class Technology
    {
        public virtual int Id { get; private set; }
        public virtual string Name { get; set; }
        public virtual int SortOrder { get; set; }
        public virtual string Abbreviation { get; set; }
        public virtual IList<TechnologyDescription> TechnologyDescriptions { get; private set; }
    
        public Technology()
        {
            TechnologyDescriptions = new List<TechnologyDescription>();
        }
    
        public virtual void AddTechnologyDescription(TechnologyDescription technologyDescription)
        {
            technologyDescription.Technology = this;
            TechnologyDescriptions.Add(technologyDescription);
        }
    }
    
    public class TechnologyDescription
    {
        public virtual int Id { get; private set; }
        public virtual Technology Technology { get; set; }
        public virtual string Description { get; set; }
        public virtual DescriptionType DescriptionType { get; set; }
    }
    
    public class DescriptionType
    {
        public virtual int Id {get; private set;}
        public virtual string Type { get; set; }
    }
    
    These are my mapping objects:
    
    public class TechnologyMap : ClassMap<Technology>
    {
        public TechnologyMap()
        {
            Id(x => x.Id);
            Map(x => x.Name);
            Map(x => x.SortOrder);
            Map(x => x.Abbreviation);
            HasMany(x => x.TechnologyDescriptions)
                    .Inverse()
                    .Cascade.All();
        }
    }
    
    public class TechnologyDescriptionMap  : ClassMap<TechnologyDescription>
    {
        public TechnologyDescriptionMap()
        {
            Id(x => x.Id);
            References(x => x.Technology);
            Map(x => x.Description);
            References(x => x.DescriptionType);
        }
    }
    
    public class DescriptionTypeMap : ClassMap<DescriptionType>
    {
        public DescriptionTypeMap()
        {
            Id(x => x.Id);
            Map(x => x.Type);
        }
    }
    

    这是我的HQL代码:

    IQuery q = session.CreateQuery("from Technology T");
    IList technologies = q.List();
    
    2 回复  |  直到 15 年前
        1
  •  1
  •   Frederik Gheysels    15 年前

    我不知道是否可以使用HQL,但是使用NHibernate的标准API,您可以这样做:

    ICriteria criteria = session.CreateCriteria (typeof(Technology));
    
    criteria.SetFetchMode ("TechnologyDescriptions", FetchMode.Lazy);
    
    var list = criteria.List<Technology>();
    

    然而,这可能不是你真正想要的。技术脚本现在不会被获取,但一旦您访问它们,它们就会被获取(即:第一次调用技术脚本属性)。

    在与NHibernate合作时,你不应该考虑“数据”。相反,你应该用“实体”来思考。
    在检索实体时,您希望完整地检索该实体(直接或以懒惰的方式)。部分检索实体是不可能的,这是非常明显的; 当您试图保存实体时,nhibernate应该如何处理部分检索到的实体?

    我脑海中闪现的另一件事: 我想您想要检索这些技术,而没有相关的内容,因为您想要在概述或类似的内容中显示它们? 在这种情况下,您应该看看“转换”。 例如,您可以创建一个称为 TechnologyView ,如下所示:

    public class TechnologyView
    {
        public int Id
        {
            get;
            private set;
        }
    
        public string Name
        {
            get;
            private set;
        }
    
        public string Abbreviation
        {
            get;
            private set;
        }
    
        private TechnologyView()
        {
           // Private constructor, required for NH
        }
    
        public TechnologyView( int id, string name, string abbreviation )
        {
           this.Id = id;
           this.Name = name;
           this.Abbreviation = abbreviation;
        }
    }
    

    一旦你这样做了,你必须通知NHibernate这个类的存在。 例如,您可以通过在hbm.xml文件中导入类来实现这一点。(我不知道用流利的语言怎么做)。

    <import class="MyNamespace.TechnologyView" />
    

    之后,您可以创建一个查询(使用hql或条件),用于检索 技术观 实例。nhibernate足够智能,可以生成性能良好的SQL查询。

    使用HQL:

    IQuery q = s.CreateQuery ("select new TechnologyView (t.Id, t.Name, t.Abbreviation) from Technology t");
    

    使用标准:

    ICriteria criteria = s.CreateCriteria (typeof(Technology));
    criteria.SetResultTransformer (Transformers.AliasToBean (typeof(TechnologyView));
    var result = criteria.List<TechnologyView>();
    
        2
  •  1
  •   Community CDub    7 年前

    我想你要找的是让技术脚本变得懒惰。这样,只有在访问描述时才能从数据库加载描述(nhibernate将发出第二个db查询)。请注意,在某些情况下,这可能会导致N+1选择,您可能更喜欢一次查询,具体取决于用法。)

    通过nhibernate XML映射,默认为延迟加载集合。在过去,流畅的NHibernate似乎没有同样的默认值。你需要添加 .LazyLoad() 到映射。

    最近,似乎延迟加载已成为默认的Fluent映射: Is the default behavior with Fluent NHibernate to lazy load HasMany<T> collections?