最近在做项目的时候用到了NHibernate,使用它并不困难,但是很麻烦。如果我的数据库有几百张表如果想要一个个的映射岂不是很麻烦,所以这种情况下使用NHibernate就会很笨重,虽然这个ORM框架本身功能强大,但属于重量级的在使用的时候太笨重了,所以需要在项目中改良。这时候就应运而生了FluentNHibernate,它是流畅版的NHibernate,支持所有的NHibernate功能,而且还封装了配置文件的映射功能,也就是说可以将映射使用C#代码编写,这样在维护时就会很简单。
       在没有FluentNHibernate的情况下,如果使用NHibernate来做数据库映射,那么首先需要安装NHibernate(也就是应用Nhibernate.dll),然后创建Nhibernate.cfg.xml数据库配置文件,然后创建映射文件.xml,最后创建Session,直接对对象操作即可。虽然这样做并不困难,但是很麻烦,想象下如果数据库表有上百张,那使用这种方法映射不就很麻烦,笨重了吗。
       那么FluentNHibernate有什么好处呢,它能够省略创建映射文件.xml,使用C#代码编写映射文件,这样做能在一定情况下简化工作量,同时也便于对映射代码进行修改,具体使用方法接下来会详细讨论。

一、创建数据库配置文件

首先创建一个数据库的配置文件,刚开始使用的话手动编写太麻烦,这时候可以考虑使用自带的配置文件,在官网下载后会有一个名为Configuration_Templates的文件夹,里面有不同数据库的配置文件,可以使用它的默认设置,但是需要将名称改为Nhibernate.cfg.xml。这里使用如下的配置:

[html] view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!-- This is the System.Data.dll provider for SQL Server -->
  3. <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  4. <session-factory name="KaddzvoteNHibernateFactory">
  5. <property name="connection.driver_class">
  6. NHibernate.Driver.SqlClientDriver
  7. </property>
  8. <property name="connection.connection_string">
  9. Data Source=.;Initial Catalog=Mapping;Integrated Security=true;Pooling=True;Min Pool Size=20;Max Pool Size=60
  10. </property>
  11. <property name="dialect">
  12. NHibernate.Dialect.MsSql2005Dialect
  13. </property>
  14. <property name="current_session_context_class">thread_static</property>
  15. <property name="generate_statistics">true</property>
  16. <property name="proxyfactory.factory_class">NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate</property>
  17. <property name="query.substitutions">
  18. true 1, false 0, yes 'Y', no 'N'
  19. </property>
  20. <!--配置是否显示sql语句,true代表显示-->
  21. <property name="show_sql">true</property>
  22. </session-factory>
  23. </hibernate-configuration>
<?xml version="1.0" encoding="utf-8"?>
<!-- This is the System.Data.dll provider for SQL Server -->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"><session-factory name="KaddzvoteNHibernateFactory"><property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property><property name="connection.connection_string">Data Source=.;Initial Catalog=Mapping;Integrated Security=true;Pooling=True;Min Pool Size=20;Max Pool Size=60</property><property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property><property name="current_session_context_class">thread_static</property><property name="generate_statistics">true</property><property name="proxyfactory.factory_class">NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate</property><property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property><!--配置是否显示sql语句,true代表显示--><property name="show_sql">true</property></session-factory>
</hibernate-configuration>

二、创建实体

NHibernate的基本映射和Hibernate是完全相同的,有关基本的映射这里不再详细的讨论,可以翻阅笔者的前几篇文章。下面自己做了一个小的项目Demo,演示如何使用NHibernate创建一个数据库的映射,具体的数据库结构图如下:

上图的数据库结构图中涵盖了基本的映射关系,在实际的项目中也就是上面出现的几种基本的关系,其中涵盖了一对一、多对一、多对多的关联关系,接下来将会使用FluentNHibernate来实现基本的映射关系。

2.1 创建实体

添加完配置文件后使用第三方工具将数据库表导出为实体对象,也就是添加数据库表的实体对象。添加完成后继续添加数据库的映射类,添加映射类时需要继承NHibernate的ClassMap<T>类,将数据库实体放置到对象内部,这样在映射时能够直接使用,它使用的是泛型来实现的。数据库表的实体如下代码:

[csharp] view plain copy print ?
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using FluentNHibernate.Automapping;
  8. using FluentNHibernate.Conventions;
  9. using NHibernate;
  10. using NHibernate.Collection.Generic;
  11. namespace ClassLibrary1.mapping
  12. {
  13. public abstract class Entity
  14. {
  15. virtual public int ID { get; set; }
  16. }
  17. public class User : Entity
  18. {
  19. virtual public string Name { get; set; }
  20. public virtual string No { get; set; }
  21. public virtual UserDetails UserDetails { get; set; }
  22. }
  23. public class Project : Entity
  24. {
  25. public Project()
  26. {
  27. Task=new List<Task>();
  28. Product=new List<Product>();
  29. }
  30. public virtual string Name { get; set; }
  31. public virtual User User { get; set; }
  32. public virtual IList<Product> Product { get; set; }
  33. public virtual IList<Task> Task{get;protected set; }
  34. }
  35. public class Product : Entity
  36. {
  37. public Product()
  38. {
  39. Project=new List<Project>();
  40. }
  41. public virtual IList<Project> Project { get; set; }
  42. public virtual string Name { get; set; }
  43. public virtual string Color { get; set; }
  44. }
  45. public class Task : Entity
  46. {
  47. public virtual string Name { get; set; }
  48. public virtual Project Project { get; set; }
  49. }
  50. public class UserDetails : Entity
  51. {
  52. public virtual User User { get; set; }
  53. public virtual int Sex { get; set; }
  54. public virtual int Age { get; set; }
  55. public virtual DateTime BirthDate { get; set; }
  56. public virtual decimal Height { get; set; }
  57. }
  58. }
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FluentNHibernate.Automapping;
using FluentNHibernate.Conventions;
using NHibernate;
using NHibernate.Collection.Generic;namespace ClassLibrary1.mapping
{public abstract class Entity{virtual public int ID { get; set; }}public class User : Entity{virtual public string Name { get; set; }public virtual string No { get; set; }public virtual UserDetails UserDetails { get; set; }}public class Project : Entity{public Project(){Task=new List<Task>();Product=new List<Product>();}public virtual string Name { get; set; }public virtual User User { get; set; }public virtual IList<Product> Product { get; set; } public virtual IList<Task> Task{get;protected set; }}public class Product : Entity{public Product(){Project=new List<Project>();}public virtual IList<Project> Project { get; set; } public virtual string Name { get; set; }public virtual string Color { get; set; }}public class Task : Entity{public virtual string Name { get; set; }public virtual Project Project { get; set; }}public class UserDetails : Entity{public virtual User User { get; set; }public virtual int Sex { get; set; }public virtual int Age { get; set; }public virtual DateTime BirthDate { get; set; }public virtual decimal Height { get; set; }}
}

三、映射详解

在添加映射文件时需要继承FluentNHibernate的ClassMap<T>类,然后在类的构造函数中添加映射的方法,具体的方法是使用的lamuda表达式来映射的,方法的名称跟配置文件的名称基本一致,书写也很方便,接下来将会拆分映射来详细讲解FluentNHibernate的Mapping使用方法。

3.1 一对一映射

首先来看看一对一的映射关系,用户和用户信息表在实际中是一对一的关系,这两个表之间是通过使用UserID来相互关联的,它们有一个共同的ID,在插入Users表的同时也要写入UserDetails表,所以需要添加一对一的限制关系,具体的在Users和UsersDetails两表的映射方法如下代码:

[csharp] view plain copy print ?
  1. public class UsersMapping : ClassMap<User>
  2. {
  3. public UsersMapping()
  4. {
  5. Table("Users");
  6. LazyLoad();
  7. Id(x => x.ID).Column("UserID").GeneratedBy.Identity();
  8. HasOne(x => x.UserDetails).Cascade.All().PropertyRef("User");
  9. Map(x => x.Name).Nullable();
  10. Map(x => x.No).Nullable();
  11. }
  12. }
public class UsersMapping : ClassMap<User>
{public UsersMapping(){Table("Users");LazyLoad();Id(x => x.ID).Column("UserID").GeneratedBy.Identity();HasOne(x => x.UserDetails).Cascade.All().PropertyRef("User");Map(x => x.Name).Nullable();Map(x => x.No).Nullable();}
}

Note:FluentNHibernate在映射时有很多种映射方法,比如Cascade它是指该对象在进行操作时关联到的子对象的操作类型,上面指定了All说明所有的操作都会关联到子表,还有SaveUpdate在添加和更新时关联子表,另外还有None类型不推荐使用此类型因为会出现很多问题。

UserDetails的映射中的主键ID是继承自User类的所以在指定ID时需要添加Foreign外键关联的属性名,内部的参数一定要是UserDetails的属性名。

[csharp] view plain copy print ?
  1. public class UserDetailsMapping : ClassMap<UserDetails>
  2. {
  3. public UserDetailsMapping()
  4. {
  5. Table("UserDetails");
  6. LazyLoad();
  7. Id(x => x.ID).Column("UserID").GeneratedBy.Foreign("User");
  8. Map(x => x.Height).Nullable();
  9. Map(x => x.Age).Nullable();
  10. Map(x => x.Sex).Nullable();
  11. Map(x => x.BirthDate).Nullable();
  12. HasOne(x => x.User).Cascade.All();
  13. }
  14. }
public class UserDetailsMapping : ClassMap<UserDetails>
{public UserDetailsMapping(){Table("UserDetails");LazyLoad();Id(x => x.ID).Column("UserID").GeneratedBy.Foreign("User");Map(x => x.Height).Nullable();Map(x => x.Age).Nullable();Map(x => x.Sex).Nullable();Map(x => x.BirthDate).Nullable();HasOne(x => x.User).Cascade.All();}
}

使用测试方法查看映射结果,具体的测试方法如下:

[csharp] view plain copy print ?
  1. using System;
  2. using System.Collections.Generic;
  3. using ClassLibrary1.mapping;
  4. using FluentNHibernate.Testing;
  5. using ClassLibrary1;
  6. using NHibernate;
  7. using NUnit.Framework;
  8. namespace UnitTestProject1
  9. {
  10. [TestFixture]
  11. public class UnitTest1:NHConfig
  12. {
  13. [Test]
  14. public void TestUsers_UserDetails()
  15. {
  16. //get user from database
  17. User user1 = Session.Load<User>(1);
  18. //save the User data
  19. Session.Transaction.Begin();
  20. User user=new User()
  21. {
  22. Name = "Jack",
  23. No = "12321"
  24. };
  25. UserDetails userDetails=new UserDetails()
  26. {
  27. Age = 12,
  28. BirthDate = DateTime.Now.Date,
  29. Height = 240,
  30. Sex = 1
  31. };
  32. user.UserDetails = userDetails;
  33. userDetails.User = user;
  34. Session.Save(user);
  35. Session.Transaction.Commit();
  36. }
  37. }
  38. }
using System;
using System.Collections.Generic;
using ClassLibrary1.mapping;
using FluentNHibernate.Testing;
using ClassLibrary1;
using NHibernate;
using NUnit.Framework;
namespace UnitTestProject1
{[TestFixture]public class UnitTest1:NHConfig{[Test]public void TestUsers_UserDetails(){//get user from databaseUser user1 = Session.Load<User>(1);//save the User dataSession.Transaction.Begin();User user=new User(){Name = "Jack",No = "12321"};UserDetails userDetails=new UserDetails(){Age = 12,BirthDate = DateTime.Now.Date,Height = 240,Sex = 1};user.UserDetails = userDetails;userDetails.User = user;Session.Save(user);Session.Transaction.Commit();}}
}

在get和save对象的地方添加断点,Debug运行测试就会看到执行的结果。

3.2 一对多/多对一

一对多和多对一是相对而言的正如上例中的Projects和Tasks类似,一个Projects有多个Tasks,反过来说就是多个Tasks可能会对应一个Projects所以有时一对多的关系也就是多对一的关系,只不过是一种特殊的多对一。这里的多对一比较特殊,常见的多对一的关系比如学生和班级的关系,多个学生属于一个班级。
         一对多的映射方法和一对一的映射方法其实很多地方是类似的,只不过一对多的关系里面要添加一个外键引用关系,然后在多的一端添加一个外键,在一的一端添加HasMany,映射到Projects和Tasks中就是在Tasks(多)中添加Project的外键。

3.2.1 映射

首先时Tasks表的映射,因为Tasks表是多的一端,所以要添加对Projects表的外键引用关系,另外因为是一种外键引用不关系到父表的操作,所以这里可以使用Cascade.None()。

[csharp] view plain copy print ?
  1. public class TasksMappping : ClassMap<ClassLibrary1.mapping.Task>
  2. {
  3. public TasksMappping()
  4. {
  5. Table("Tasks");
  6. LazyLoad();
  7. Id(x => x.ID).Column("TaskID").GeneratedBy.Identity();
  8. References(x => x.Project).Nullable().Column("ProjectID").Cascade.None();
  9. Map(x => x.Name).Nullable();
  10. }
  11. }
public class TasksMappping : ClassMap<ClassLibrary1.mapping.Task>
{public TasksMappping(){Table("Tasks");LazyLoad();Id(x => x.ID).Column("TaskID").GeneratedBy.Identity();References(x => x.Project).Nullable().Column("ProjectID").Cascade.None();Map(x => x.Name).Nullable();}
}

在Projects表中,因为该表中的一个ID会对应多个Tasks所以在添加HasMany方法,来表明Projects和Tasks的多对一的关系,如下代码它会涉及到任务的添加和更新操作,所以需要使用Cascade.SaveUpdate()。

[csharp] view plain copy print ?
  1. public class ProjectsMapping:ClassMap<Project>
  2. {
  3. public ProjectsMapping()
  4. {
  5. Table("Projects");
  6. LazyLoad();
  7. Id(x => x.ID).Column("ProjectID").GeneratedBy.Identity();
  8. References(x => x.User).Column("UserID").Cascade.None();
  9. Map(x => x.Name).Nullable();
  10. HasMany(x => x.Task).KeyColumn("ProjectID").LazyLoad().Cascade.SaveUpdate();
  11. }
  12. }
public class ProjectsMapping:ClassMap<Project>
{public ProjectsMapping(){Table("Projects");LazyLoad();Id(x => x.ID).Column("ProjectID").GeneratedBy.Identity();References(x => x.User).Column("UserID").Cascade.None();Map(x => x.Name).Nullable();HasMany(x => x.Task).KeyColumn("ProjectID").LazyLoad().Cascade.SaveUpdate();}
}

Note:TasksMapping中的外键关系使用的是Cascade.None这说明它的操作不会涉及到Projects的操作,但是ProjectsMapping中使用了Cascade.SaveUpdate()方法所以在save或者update Projects的时候会连带着修改Tasks。

3.2.2 Unit Test

编写单元测试代码如下:

[csharp] view plain copy print ?
  1. [Test]
  2. public void TestOneToMany()
  3. {
  4. Project project = Session.Get<Project>(15);
  5. //save the User data
  6. Session.Transaction.Begin();
  7. Task task = new Task()
  8. {
  9. Name ="create",
  10. Project = project
  11. };
  12. Session.Save(task);
  13. Session.Transaction.Commit();
  14. Task task1 = Session.Get<Task>(1);
  15. }
[Test]
public void TestOneToMany()
{Project project = Session.Get<Project>(15);//save the User dataSession.Transaction.Begin();Task task = new Task(){Name ="create",Project = project};Session.Save(task);Session.Transaction.Commit();Task task1 = Session.Get<Task>(1);
}

执行查看结果:

这里使用的一对多的关联只是单向的关联,在关联中不仅有单向的另外还有双向关联,具体使用方法这里不再详细讨论,有兴趣学习的话可以翻阅笔者的前篇文章有关Hibernate的关联关系。

3.3 多对多

上文详细讨论了一对一、多对一/一对多的关系,使用FluentNHibernate来映射这种关系就很简单了,最后继续讨论多对多的关系,多对多的关系在使用的时候更类似于一对一的关系,因为它属于双向的关联,所以需要在关联的两端同时添加HasManyToMany的映射方法,另外反应到数据库中这其实是需要建立关联表,利用第三张表来维护双向的关系,具体的使用方法如下实例。

3.3.1 映射

在项目中常见的多对多的关系有很多,比如本例中使用的Product和Project的关系,一个Project会有有很多Product,同时一个Product也可能会在多个Project中,它们之间就形成了多对多的关联关系。反映到映射关系中,代码如下:

[csharp] view plain copy print ?
  1. public class ProjectsMapping:ClassMap<Project>
  2. {
  3. public ProjectsMapping()
  4. {
  5. Table("Projects");
  6. LazyLoad();
  7. Id(x => x.ID).Column("ProjectID").GeneratedBy.Identity();
  8. References(x => x.User).Column("UserID").Cascade.None();
  9. Map(x => x.Name).Nullable();
  10. HasMany(x => x.Task).KeyColumn("ProjectID").LazyLoad().Cascade.SaveUpdate();
  11. HasManyToMany(x => x.Product).ParentKeyColumn("ProjectID").ChildKeyColumn("ProductID").Table("ProjectProduct");
  12. }
  13. }
  14. public class ProductMapping : ClassMap<Product>
  15. {
  16. public ProductMapping()
  17. {
  18. Table("Product");
  19. Id(x => x.ID).Column("ProductID").GeneratedBy.Identity();
  20. Map(x => x.Name).Nullable();
  21. Map(x => x.Color).Nullable();
  22. HasManyToMany(x => x.Project).ParentKeyColumn("ProductID").ChildKeyColumn("ProjectID").Table("ProjectProduct");
  23. }
  24. }
public class ProjectsMapping:ClassMap<Project>
{public ProjectsMapping(){Table("Projects");LazyLoad();Id(x => x.ID).Column("ProjectID").GeneratedBy.Identity();References(x => x.User).Column("UserID").Cascade.None();Map(x => x.Name).Nullable();HasMany(x => x.Task).KeyColumn("ProjectID").LazyLoad().Cascade.SaveUpdate();HasManyToMany(x => x.Product).ParentKeyColumn("ProjectID").ChildKeyColumn("ProductID").Table("ProjectProduct");}
}public class ProductMapping : ClassMap<Product>
{public ProductMapping(){Table("Product");Id(x => x.ID).Column("ProductID").GeneratedBy.Identity();Map(x => x.Name).Nullable();Map(x => x.Color).Nullable();HasManyToMany(x => x.Project).ParentKeyColumn("ProductID").ChildKeyColumn("ProjectID").Table("ProjectProduct");}
}

具体添加关联的步骤如下:
               (1)在映射的两端同时添加HasManyToMany的关系这样就形成了双向的关联关系
               (2)指定映射的ParentKey和ChildKey,一般会将对象本身的ID指定为ParentKey,关联对象的ID指定为ChildKey
               (3)指定关联关系的关系表,使用Table方法指定关联表,如上示例的Table("ProjectProduct")。

3.3.2  Unit Test

最后添加一个测试方法来查看映射的结果,是否实现了多对多的映射关系,具体测试方法如下。

[csharp] view plain copy print ?
  1. [Test]
  2. public void TestManyToMany()
  3. {
  4. Session.Transaction.Begin();
  5. //get the Project
  6. ICriteria query = Session.CreateCriteria<Project>();
  7. IList<Project> projects = query.List<Project>();
  8. //create the Product
  9. Product product=new Product()
  10. {
  11. Name = "Product1",
  12. Color = "Red"
  13. };
  14. product.Project = projects;
  15. Session.Save(product);
  16. Session.Transaction.Commit();
  17. }
[Test]
public void TestManyToMany()
{Session.Transaction.Begin();//get the ProjectICriteria query = Session.CreateCriteria<Project>();IList<Project> projects = query.List<Project>();//create the ProductProduct product=new Product(){Name = "Product1",Color = "Red"};product.Project = projects;Session.Save(product);Session.Transaction.Commit();
}

Debug运行测试方法,运行到get projects处查看projects所获取的对象信息如下图:

从上图可以看出已经获取到了与projects相关联的Product,这就是多对多的关系,在获取projects时同时获取了与它关联的Products,如果这里使用Lazyload方式的话就不会获取所有的信息,所以要根据具体的情况而定。

继续运行测试,成功执行。
                

查看数据库发现数据已经成功添加,如下图:
                                              

结语

本文主要讨论了FluentNHibernate的基本使用技巧,突出讨论了一对一的双向关联映射,一对多的单向关联和多对多的双向关联关系,它们使用相当简单,因为有了FluentNHibernate,只需要了解关联的规则就可以了,从数据模型到对象模型真的就很简单了。

虽然使用FluentNHibernate在一定程度上减少了编写代码,但是并不能真正的解决代码冗余的繁琐问题,可否有一中不需要编写Mapping代码的方法来实现映射关系呢?是的FluentNHibernate还封装了一种AutoMapping方式来映射对象,是一种自动映射的方法,只需要继承实现数据库表到对象的转换规则就可以了,具体的实现方法将会在下篇文章中详细讨论。

FluentNHibernate之基本映射详解相关推荐

  1. Elastricsearch 索引操作详解(快速入门、索引管理、映射详解、索引别名)

    一.快速入门 1. 查看集群的健康状况 http://localhost:9200/_cat http://localhost:9200/_cat/health?v 说明:v是用来要求在结果中返回表头 ...

  2. ElasticSearch最全详细使用教程:入门、索引管理、映射详解、索引别名、分词器、文档管理、路由、搜索详解...

    墨墨导读:之前我们分享了ElasticSearch最全详细使用教程:入门.索引管理.映射详解,本文详细介绍ElasticSearch的索引别名.分词器.文档管理.路由.搜索详解. 一.索引别名 1. ...

  3. ElasticSearch最全详细使用教程:入门、索引管理、映射详解

    墨墨导读:本文介绍了ElasticSearch的必备知识:从入门.索引管理到映射详解. 一.快速入门 1. 查看集群的健康状况http://localhost:9200/_cat http://loc ...

  4. Mybatis映射详解

    Mybatis映射详解 在最近的工作中,碰到一个比较复杂的返回结果,发现简单映射已经解决不了这个问题了,只好去求助百度,学习mybatis复杂映射应该怎么写,将学习笔记结合工作碰到的问题写下本文,供自 ...

  5. Hibernate对象关系映射详解之一对多关系映射

    Hibernate对象关系映射详解之"一对多"关系映射 之前学习Hibernate框架的时候,对这七大关系映射一直是云里雾里的,虽然可以仿照写出代码,但是不能独立编写出来.鉴于工作 ...

  6. elasticsearch最全详细使用教程:入门、索引管理、映射详解、索引别名、分词器、文档管理、路由、搜索详解

    一.快速入门 1. 查看集群的健康状况 http://localhost:9200/_cat http://localhost:9200/_cat/health?v 说明:v是用来要求在结果中返回表头 ...

  7. 数据库系统之:三级模式-两层映射详解

    数据库系统之:三级模式-两层映射详解 前言 一.数据库三大模式详解 1.外模式(反映了数据库系统的用户观) 2.概念模式(反映了数据库系统的整体观) 3.内模式(反映了数据库系统的存储观) 4.概念模 ...

  8. 第二章 关系映射详解

    本章学习目标 generator 主键策略 对象关系映射之一对多映射 cascade 和 inverse 配置详解 对象关系映射之多对多映射 对象关系映射之一多一映射 1. generator主键策略 ...

  9. 内网端口映射详解(花生壳)

    转自:http://hi.baidu.com/xujinnei/item/de88c5b22af4f2eb4fc7fdf2 关于如何建立服务器的解答. 一.花生壳的作用 首先,我们先来了解一下花生壳的 ...

最新文章

  1. Contiki 2.7 Makefile 文件(一)
  2. mysql 5.5.55_MySQL系列(5)
  3. POJ 3237 Tree (树链剖分)
  4. windows server 2003 安装显卡驱动
  5. Logback 配置文件这么写,TPS 提高 10 倍!
  6. S/4HANA extension field search的SQL语句是在什么地方生成的
  7. linux clang安装,linux 配置 clang++ SDL 开发环境 (新手向)
  8. table模板标签,批量多选失效的问题,tr td结构多选框失效相关问题
  9. 显卡测试软件 温度,显卡温度检测软件
  10. 卡耐基梅隆大学计算机科学课本,美国卡耐基梅隆大学计算机科学硕士.pdf
  11. 实验七 磁盘调度算法的模拟与实现
  12. CentOS 6.5 ZIP、RAR文件压缩解压操作详解
  13. 2020年中国数字减影血管造影系统(DSA)市场现状分析,DSA设备需求不断提升「图」
  14. 【CISSP备考笔记】第4章:通信与网络安全
  15. 原生javascript-图片查看器的制作-注释版
  16. [日语]基于日语常用汉字表的音读到汉字的映射表
  17. 对接天猫接口之如何授权订阅消息?包含天猫端授权和服务商端授权taobao.tmc.user.permit
  18. Eclipse 解决项目中中文注释乱码问题
  19. Elasticsearch学习1 入门进阶 Linux系统下操作安装Elasticsearch Kibana 初步检索 SearchAPI Query DSL ki分词库 自定义词库
  20. JAVA实现扫雷游戏

热门文章

  1. MSP432 P401R 单片机 矩阵键盘 贪吃蛇 OLED 代码 程序
  2. eclipse是什么工具?
  3. 显著性检测评估指标及计算方法
  4. matlab:分析控制系统稳定性综合实例
  5. c++ 多线程编程demo
  6. Java学习之while循环及案例
  7. 计算机等级证书怎么写进简历,如何优化技能证书在简历中的位置
  8. 工字型钢弹性截面模量计算公式_型钢计算公式2
  9. 【卸载CUDA-10.0】
  10. Java实战之管家婆记账系统(5)——主界面及功能实现