NHibernate初学者指南(15):使用LINQ to NHibernate提供程序查询数据

By admin in 天文学 on 2018年10月26日

在面前的《NHibernate初学者指南(8):增删查改》一平和被略的涉及了查询一个实体的Get<T>和Load<T>方法及查询实体列表的Query<T>方法,这篇稿子我们尤其讲解查询的关于地方。

理论知识

界定返回的记录数

var orders = session.Query<Order>();

方的询问返回Order表中具备的订单,如果想限制返回记录之个数,可以使Take方法,如下面的代码:

var orders = session.Query<Order>().Take(200);

淘记录集

使用筛选的重点字是Where。LINQ定义了一个Where方法,它将一个谓词作为参数。谓词是包含一个参数的函数它回到一个布尔值,如下面的代码所示:

Func<T, bool> predicate

假使假定查询有下架的活,可以用下的代码:

var discontinuedProducts = session
    .Query<Product>()
    .Where(p => p.Discontinued);

方的查询中,我们利用一个拉姆达表达式p=>p.Discontinued定义谓词。这个表达式的意是:给得一个产品p,获取她的Discontinued属性的情连返。如果回到的价值是true,那么相应的制品即概括于罗的结果集中。

投记录集

炫耀记录集可以用Select方法,它用一个映射函数作为参数。映射函数定义为如下代码:

Func<TSource, TResult> mapper

若果我们怀念加载下架的产品列表,但是只有产品的Id和Name。我们得以先行定义一个类NameID,如下所示:

public class NameID
{
    public int Id { get; set; }
    public string Name { get; set; }
}

查询如下所示:

var discontinuedProducts = session
                           .Query<Product>()
                           .Where(p => p.Discontinued)
                           .Select(p => new NameID { Id = p.Id, Name = p.Name });

点的代码我们定义了映射函数作为拉姆达表达式,如下面的代码:

p => new NameID { Id = p.Id, Name = p.Name }

它们的意是受一个Product对象p并回到一个NameID类型的对象,它的属性也:Id和Name,对诺受活p的Id和Name。

排序结果集

万一我们纪念得Person对象的列表,按姓氏氏排序,如下面的代码所示:

var people = session.Query<Person>()
            .OrderBy(p => p.LastName);

要我们还眷恋按部就班first name排序,那么查询如下所示:

var people = session.Query<Person>()
            .OrderBy(p => p.LastName)
            .ThenBy(p => p.FirstName);

只顾我们得以遵循多单列排序,只待简单的当背后调用ThenBy方法即可。还有跟OrderBy和ThenBy相对应之是本降序排列的方法:OrderByDescending和ThenByDescending。上面的询问仍相反的顺序排列,如下面的代码所示:

var people = session.Query<Person>()
            .OrderByDescending(p => p.LastName)
            .ThenByDescending(p => p.FirstName);

分组记录

假若我们怀念计算出略个人的姓氏氏因相同的字母开始,那么我们得凭借分组函数,代码如下所示:

var personsPerLetter = session.Query<Person>()
                       .GroupBy(p => p.LastName.Substring(0, 1))
                       .Select(g => new { Letter = g.Key, Count = g.Count() });

面的代码返回匿名类型的列表,它富含想使的结果。

GroupBy方法返回IEnumerable<IGrouping<T,V>>,T表示分组根据的值的品种,V表示被分组的花色。在面的代码中,T是string类型的,V是Person类型的。

强制LINQ查询这执行

LINQ查询总是延迟执行之,只有当我们开始遍历结果集时查询才真正的履行。但是有时,我们想强制执行查询并回到结果集。有例外之计得以这么做。

先是,我们得调用扩展方法ToArray或ToList终止查询。这简单只方式就开始枚举结果集并以结果对象放置数组或列表中。

var products = session.Query<Product>()
               .Where(p => p.ReorderLevel > p.UnitsOnStock)
               .ToArray();

方的查询加载所有需要再次订货的有着成品列表,并拿其放入到一个数组中。

第二,使用ToDictionary方法。这个主意以打数据库被寻觅出实体列表并也各级一个实例使用唯一键存储在集合中甚有利。我们看一个例,如下面的代码所示:

var personsPerLetter = session.Query<Person>()
                       .GroupBy(p => p.LastName.Substring(0, 1))
                       .Select(g => new { Letter = g.Key, Count = g.Count() })
                       .ToDictionary(x => x.Letter, x => x.Count);

面的查询创建了一个人之字典,它的姓氏氏因吃一定的字母开头。key是姓氏氏的启幕字母,value是人数。

自从查询数据库改呢查询内存对象

以是,我们怀念由数据库查询有数码,然后一发行使底层数据库不支持的作用操作这些多少。这种景象,我们得平等栽方法通知LINQ
to
NHibernate提供次从现在起所有的操作都当内存中形成而未是数据库中。为夫,我们可使用AsEnumerable方法。

为我们看一个事例。假如有一个Email实体,它涵盖部分记录。现在,我们怀念那个成一个邮件的淘列表,筛选标准是一个正则表达式。然而,大多数数据库不支持正则表达式。因此,筛选必须于内存中落成,如下面的代码所示:

var statusList = session.Query<Email>()
                .Select(e => e.EmailAddress)
                .AsEnumerable()
                .Where(e => SomeFilterFunctionUsingRegExp(e));

方的事例,投影出在数据库,而罗在内存中好。

动LINQ to NHibernate创建报表

以熟悉LINQ to
NHibernate的使用,我们创建几个不等之表格打印及屏幕及。在脚的例证中,我们的模子是天文学的同一有的,更确切的说是星分类。我们用XML配置文件以及XML映射文件映射我们的模型。

  1. 在SSMS中创造一个拖欠的数据库:LinqToNHibernateSample。

  2. 于Visual Studio中创造一个控制台应用程序:LinqToNHibernateSample。

  3. 安装项目的Target Framework为.NET Framework 4。

  4. 添加对NHibernate和NHibernate.ByteCode.Castle程序集的援。

5.
于化解方案被补充加一个缓解方案文件夹:Schema,并丰富nhibernate-configuration.xsd
和nhibernatemapping.
xsd两独文本。

  1. 在档次遭到上加一个近似公事Star.cs,添加如下代码定义Star实体:

    public class Star
    {

     public virtual Guid Id { get; set; }
     public virtual string Name { get; set; }
     public virtual IList<Planet> Planets { get; set; }
     public virtual StarTypes Class { get; set; }
     public virtual SurfaceColor Color { get; set; }
     public virtual double Mass { get; set; }
    

    }

  2. 当品种中补充加一个接近公事Planet.cs,添加如下代码定义Planet实体:

    public class Planet
    {

     public virtual Guid Id { get; set; }
     public virtual string Name { get; set; }
     public virtual bool IsHabitable { get; set; }
     public virtual Star Sun { get; set; }
    

    }

8.
于档次遭到上加一个好像公事SurfaceColor.cs,在文件被定义枚举SurfaceColor,代码如下所示:

public enum SurfaceColor
{
    Blue, BueToWhite, WhiteToYellow, OrangeToRed, Red
}

9.
每当品种中补充加一个近乎公事StarTypes.cs,在文书中定义枚举StarTypes,代码如下所示:

public enum StarTypes
{
    O, B, A, F, G, K, M
}
  1. 当档次遭到补充加一个XML文件Star.hbm.xml,设置它的Build
    Action属性为Embedded Resource,并加上如下代码定义Star实体的照:



    <id name="Id">
      <generator class="guid.comb"/>
    </id>
    <property name="Name"/>
    <property name="Mass"/>
    <property name="Class" type="StarTypes"/>
    <property name="Color" type="SurfaceColor"/>
    <bag name="Planets" inverse="true" cascade="all-delete-orphan">
      <key column="StarId" />
      <one-to-many class="Planet"/>
    </bag>
    


只顾Star实体的有限只枚举类型属性Color和Class是什么映射的。我们应用type特性指定NHibernate映射这些性为数据库的int类型的列(枚举的基类型是int)。另外注意一个star的planets列表是哪些映射的。尤其复习一下inverse和cascade特性以及汇聚类型的采取。还要注意的凡我们以Guid生成器。

  1. 当品种中补充加任何一个XML文件Planet.hbm.xml,设置它的Action
    Build属性为Embedded Resource,并加上如下代码映射Planet实体:


                   assembly="LinqToNHibernateSample" 
                   namespace="LinqToNHibernateSample">
    

    <id name="Id">
      <generator class="guid.comb"/>
    </id>
    <property name="Name"/>
    <property name="IsHabitable"/>
    <many-to-one name="Sun" class="Star" column="StarId"/>
    


小心我们当many-to-one标签中动用column特性匹配Star.hbm.xml映射文件中bag标签定义之key。

12.
在品种蒙添加XML文件hibernate.cfg.xml。这个文件包含配置信息,代码如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory name="Sample">
    <property name="connection.provider">
      NHibernate.Connection.DriverConnectionProvider
    </property>
    <property name="connection.driver_class">
      NHibernate.Driver.SqlClientDriver
    </property>
    <property name="dialect">
      NHibernate.Dialect.MsSql2008Dialect
    </property>
    <property name="connection.connection_string">
      server=.;database=LinqToNHibernateSample;integrated security=true
    </property>
    <property name="proxyfactory.factory_class">
      NHibernate.ByteCode.Castle.ProxyFactoryFactory,NHibernate.ByteCode.Castle
    </property>
  </session-factory>
</hibernate-configuration>
  1. 设置hibernate.cfg.xml文件的Copy to Output Directory属性为always。

  2. 于Program类中之Main方法吃,添加代码初始化Nhibernate
    Configuration对象,如下所示:

    var configuration = new Configuration();

15.
嗲用configuration对象天文学的Configure方法。这个方法会当前目录中摸索名吧hibernate.cfg.xml的文件,如果找到,就从中读取所有的配置值,如下面的代码所示:

configuration.Configure();
  1. 丰富代码告诉configuration对象解析程序集,如下所示:

    configuration.AddAssembly(typeof(Star).Assembly);

  2. 加上代码创建或者再创设数据库架构,如下面的代码所示:

    new SchemaExport(configuration).Execute(true, true, false);

  3. 以configuration对象创建一个session工厂,如下面的代码所示:

    var factory = configuration.BuildSessionFactory();

  4. 接下来上加如下代码:

    CreateData(factory);
    QueryData(factory);
    Console.Write(“\r\n\nHit enter to exit:”);
    Console.ReadLine();

  5. 脚我们第一落实CreateData方法,代码如下:

    private static void CreateData(ISessionFactory factory)
    {

    var sun = new Star
    {
        Name = "Sun",
        Mass = 1,
        Class = StarTypes.G,
        Color = SurfaceColor.WhiteToYellow
    };
    var planets = new List<Planet>
                    {
                        new Planet{Name = "Merkur", IsHabitable = false, Sun = sun},
                        new Planet{Name = "Venus", IsHabitable = false, Sun = sun},
                    // please consult the sample code for full list of planets
                    };
    sun.Planets = planets;
    var virginis61 = new Star
    {
        Name = "61 Virginis",
        Mass = 0.95,
        Class = StarTypes.G,
        Color = SurfaceColor.WhiteToYellow
    };
    var planets2 = new List<Planet>
                    {
                        new Planet{Name = "Planet 1", IsHabitable = false,Sun = virginis61},
                        new Planet{Name = "Planet 2", IsHabitable = true,Sun = virginis61},
                        new Planet{Name = "Planet 3", IsHabitable = false,Sun = virginis61}
                    };
    virginis61.Planets = planets2;
    var stars = new List<Star>
                {
                    sun, virginis61,
                    new Star{Name = "10 Lacertra", Mass = 60,Class = StarTypes.O, Color = SurfaceColor.Blue},
                    new Star{Name = "Spica", Mass = 18,Class = StarTypes.B, Color = SurfaceColor.Blue},
                    // please consult the sample code for full list of stars
                };
    using (var session = factory.OpenSession())
    using (var tx = session.BeginTransaction())
    {
        foreach (var star in stars)
        {
            session.Save(star);
        }
        tx.Commit();
    }
    

    }

  6. 继而我们实现QueryData方法,代码如下:

    private static void QueryData(ISessionFactory factory)
    {

    using (var session = factory.OpenSession())
    using (var tx = session.BeginTransaction())
    {
        PrintListOfStars(session);
        PrintListOfBigBlueStars(session);
        PrintSumOfStarMassPerClass(session);
        PrintListOfHabitablePlanets(session);
        tx.Commit();
    }
    

    }

留意这法子是如何创造session,transaction以及以transaction内调用四单表格方法。下面让我们独家实现地方的季独主意。

22.
给我们首先实现率先只措施,它根据star的名排序列表并打印,代码如下所示:

private static void PrintListOfStars(ISession session)
{
    Console.WriteLine("\r\n\nList of stars ------------------\r\n");
    var stars = session.Query<Star>().OrderBy(s => s.Name);
    foreach (var star in stars)
    {
        Console.WriteLine("{0} ({1}, {2})",
        star.Name, star.Class, star.Color);
    }
}

留意点的代码中,我们是何许运用Query扩展方法获得IQueryable<Star>,然后运OrderBy方法排序的。此外,注意当我们初步遍历它经常查询才会实施。

23.
底实现第二个措施。我们采取多单特性筛选和排序,甚至是各个颠倒过来,代码如下所示:

private static void PrintListOfBigBlueStars(ISession session)
{
    Console.WriteLine("\r\n\nList of big blue stars -------\r\n");
    var stars = session.Query<Star>()
                .Where(s => s.Color == SurfaceColor.Blue && s.Mass > 15)
                .OrderByDescending(s=>s.Mass)
                .ThenBy(s => s.Name);
    foreach (var star in stars)
    {
        Console.WriteLine("{0} ({1}, {2}, Mass={3})",
        star.Name, star.Class, star.Color, star.Mass);
    }
}

24.
老三个法子,我们分组star列表,并行使一个聚合函数(Sum)计算存储于数据库中之star相对质量的总数。代码如下所示:

private static void PrintSumOfStarMassPerClass(ISession session)
{
    Console.WriteLine("\r\n\nSum of masses per class -------\r\n");
    var starMasses = session.Query<Star>()
                    .GroupBy(s => s.Class)
                    .Select(g => new
                                {
                                    Class = g.Key,
                                    TotalMass = g.Sum(s => s.Mass)
                                 }
                            );
    foreach (var mass in starMasses)
    {
        Console.WriteLine("Class={0}, Total Mass={1}",
        mass.Class, mass.TotalMass);
    }
}

25.
最终,我们实现的措施是打印按照Sun和行星的名称排序的符合人类居住的行星列表,代码如下所示:

private static void PrintListOfHabitablePlanets(ISession session)
{
    Console.WriteLine("\r\n\nList of habitable planets------\r\n");
    var planets = session.Query<Planet>()
                   .Where(p => p.IsHabitable)
                   .OrderBy(p => p.Sun.Name)
                   .ThenBy(p => p.Name);
    foreach (var planet in planets)
    {
        Console.WriteLine("Star='{0}', Planet='{1}'",
        planet.Sun.Name, planet.Name);
    }
}
  1. 运转程序,结果如果下图所示:

天文学 1

总结

第一我们介绍了利用LINQ to
NHibernate提供次查询的片理论知识,然后通过一个事例
概念了不同之查询,包括罗、排序、分组和聚集,并拿结果集打印至屏幕上。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2018 亚洲必赢手机官网 版权所有