Nhibernate和Hibernate有那些区别

Nhibernate和Hibernate有那些区别

本文目录

  • Nhibernate和Hibernate有那些区别
  • LINQ和NHibernate
  • nhibernate怎么实现数据的添加,删除,修改简单程序
  • NHibernate 连接多数据库怎么配置
  • 在C#中,用NHibernate对系统进行优化有哪些方式
  • NHibernate二级缓存问题
  • 如何使用Nhibernate动态连接Oracle数据库
  • 在NHibernate 中一切必须是 Virtual 的吗求答案
  • C#中的nhibernate ORM的详解意思是什么
  • NHibernate中的schema是干什么用的

Nhibernate和Hibernate有那些区别


Nhibernate是Hibernate在.NET环境中的实现。功能和目的上两者区别不大。
在实现的机制方面,Nhibernate频繁地使用C#的新语法现象——lamda表达式,所以其使用方式看起来有点怪,没有Hibernate简明。

LINQ和NHibernate


在达人博客上看到的:是个系列,一共三篇,你去百度搜搜“LINQ to SQL、NHibernate比较”就能找到了。我给你转第一篇。
LINQ to SQL、NHibernate比较(一)-- LINQ和NHibernate初体验
1 引言
研发与数据库打交道的系统的时候,最过于繁琐的莫过于没有编程快感的使用ADO.NET对后台数据库进行操作,因为所有的数据库连接、读取、操作千篇一律,编程成为了体力活。
虽然我们可以设计自己的类作为数据库访问的持久层,但是每一个类都必须有不相同的SQL语句,这样对于设计统一的数据库读写类造成了很大的困难。
开发人员在这种情况下必须包办窗体设计、方法设计、数据库读写设计的过程,这样加大了开发人员的负担也使得项目的维护和后期开发变得难以进行。
2 .NET下的ORM解决方案
2.1 LINQ
2.1.1 LINQ简介
作为微软开发的查询方案,LINQ 提供了一条更常规的途径即给 .Net Framework 添加一些可以应用于所有信息源( all sources of information )的具有多种用途( general-purpose )的语法查询特性( query facilities ),这是比向开发语言和运行时( runtime )添加一些关系数据( relational )特性或者类似 XML 特性( XML-specific )更好的方式。这些语法特性就叫做 .NET Language Integrated Query (LINQ) 。
如果觉得上面的解释有点抽象,那么可以这样理解,LINQ其实就是提供了一套查询功能,可以实现任何数据源的查询,此处数据源不单指数据库或者XML文件,而是任何集合或者实体,比如我们接触各种编程语言都需要用到的数组,现在不用遍历数组元素来寻找需要的项,LINQ可以实现这方面的查询。
LINQ查询数组:
图2.1 LINQ查询数组
上面是最简单的LINQ实现对数组的查询,泛型类型var在LINQ查询中提供了强大的委托类型支持,不管查询集合中项的类型(无论是int,char还是string或者类),我们只用一个var就可以保存LINQ查询到的结果。程序结果如下:
图2.2 LINQ查询数组程序结果
是不是很方便,LINQ的应用远远不这些,通过不同的映射方案,我们可以实现对数据库(LINQ To SQL),对XML文件(LINQ To XML)的访问。
2.1.2 LINQ简介
表2.1 LINQ的操作符
操作符
说明

聚合

Aggregate
对序列执行一个自定义方法

Average
计算数值序列的平均值

Count
返回序列中的项目数(整数)

LongCount
返回序列中的项目数(长型)

Min
查找数字序列中的最小数

Max
查找数字序列中的最大数

Sum
汇总序列中的数字

连接

Concat
将两个序列连成一个序列

转换

Cast
将序列中的元素转换成指定类型

OfType
筛选序列中指定类型的元素

ToArray
从序列返回一个数组

ToDictionary
从序列返回一个字典

ToList
从序列返回一个列表

ToLookup
从序列返回一个查询

ToSequence
返回一个 IEnumerable 序列

元素

DefaultIfEmpty
为空序列创建默认元素

ElementAt
返回序列中指定索引的元素

ElementAtOrDefault
返回序列中指定索引的元素,或者如果索引超出范围,则返回默认值

First
返回序列中的第一个元素

FirstOrDefault
返回序列中的第一个元素,或者如果未找到元素,则返回默认值

Last
返回序列中的最后一个元素

LastOrDefault
返回序列中的最后一个元素,或者如果未找到元素,则返回默认值

Single
返回序列中的单个元素

SingleOrDefault
返回序列中的单个元素,或者如果未找到元素,则返回默认值

相等

SequenceEqual
比较两个序列看其是否相等

生成

Empty
生成一个空序列

Range
生成一个指定范围的序列

Repeat
通过将某个项目重复指定次数来生成一个序列

分组

GroupBy
按指定分组方法对序列中的项目进行分组

联接

GroupJoin
通过归组将两个序列联接在一起

Join
将两个序列从内部联接起来

排序

OrderBy
以升序按值排列序列

OrderByDescending
以降序按值排列序列

ThenBy
升序排列已排序的序列

ThenByDescending
降序排列已排序的序列

Reverse
颠倒序列中项目的顺序

分区

Skip
返回跳过指定数目项目的序列

SkipWhile
返回跳过不满足表达式项目的序列

Take
返回具有指定数目项目的序列

TakeWhile
返回具有满足表达式项目的序列

投影

Select
创建部分序列的投影

SelectMany
创建部分序列的一对多投影

限定符

All
确定序列中的所有项目是否满足某个条件

Any
确定序列中是否有任何项目满足条件

Contains
确定序列是否包含指定项目

限制

Where
筛选序列中的项目

设置

Distinct
返回无重复项目的序列

Except
返回代表两个序列差集的序列

Intersect
返回代表两个序列交集的序列

Union
返回代表两个序列交集的序列
Lambda 表达式
许多标准查询操作符在对序列执行运算时都使用 Func 委托来处理单个元素。Lambda 表达式可与标准查询操作符结合使用以代表委托。lambda 表达式是创建委托实现的简略表达形式,并可用于匿名委托适用的所有场合。C# 和 Visual Basic® .NET 均支持 Lambda 表达式。但是,必须注意:由于 Visual Basic .NET 尚不支持匿名方法,Lambda 表达式可能仅包含一个语句。
上例中的的程序等同于下面
图2.3 Lambda表达式的使用
2.2 NHibernate
说到NHibernate,就不得不提Hibernate,原因很简单,Hibernate顾名思义就是Hibernate的.NET版本。
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。
NHibernate作为Hibernate的.NET应用于Hibernate的实现完全相同,学习NHibernate完全可以直接学习Hibernate的资料。
事实上,虽然在Java数据库映射领域Hibernate是使用最为广泛的方案,但是在.NET中由于LINQ等映射方案(包括微软下一代重量级的Entity Framework)的使用,NHibernate冷了许多。
NHibernate需要配置数据库配置文件和类/表映射配置文件,所以使用NHibernate需要懂得XML文件的基础知识,并且需要掌握比较复杂的XML文件配置节和相应的配置命令。
2.2.1 数据库配置文件
NHibernate官方提供了配置文件的模板和实例可供我们参考。
图2.4 NHibernate官方数据库配置文件模板(对应了不同的数据库)
上图为数据库配置文件。通常以“cfg.xml”作为后缀,一个示例的文件内容如下
图2.5 数据库配置文件示例
下面是一些在运行时可以改变NHibernate行为的其他配置。所有这些都是可选的,也有合理的默认值。
表2.2 NHibernate 配置属性
属性名
用途

hibernate.dialect
NHibernate方言(Dialect)的类名 - 可以让NHibernate使用某些特定的数据库平台的特性
例如: full.classname.of.Dialect(如果方言创建在NHibernate中), 或者full.classname.of.Dialect, assembly (如果使用一个自定义的方言的实现,它不属于NHibernate)。

hibernate.default_schema
在生成的SQL中,scheml/tablespace的全限定名.
例如: SCHEMA_NAME

hibernate.prepare_sql
是否准备sql语句
例如: true | false

hibernate.session_factory_name
SessionFactory被创建后将自动绑定这个名称.
例如: some.name

hibernate.use_outer_join
允许使用外连接抓取。
例如:true | false

hibernate.cache.provider_class
指定一个自定义的CacheProvider缓存提供者的类名
例如: full.classname.of.CacheProvider(如果ICacheProvider创建在NHibernate中), 或full.classname.of.CacheProvider, assembly(如果使用一个自定义的ICacheProvider,它不属于NHibernate)。

hibernate.query.substitutions
把NHibernate查询中的一些短语替换为SQL短语(比如说短语可能是函数或者字符)。
例如: hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC
2.2.2 实体映射配置文件
NHibernate官方开源包中提供了实体映射配置文件的实例可供我们参考。
图2.6 NHibernate开源包中提供的实体映射配置文件
与数据库配置文件一样实体映射配置文件也是XML文件(XML果然是很强大啊,微软下一代应用程序开发技术WPF就是使用XML文件将C/S和B/S长期分居的二人统一到一个屋檐下),所不同的是实体映射配置文件后缀是“hbm.xml”。
图2.7 实体映射配置文件
实体映射配置文件所要配置的信息一般为
Ø Schema
所有的XML映射都需要使用nhibernate-mapping-2.0 schema。目前的schema可以在NHibernate的资源路径或者是NHibernate.dll的嵌入资源(Embedded Resource)中找到。NHibernate总是会优先使用嵌入在资源中的schema文件。
Ø hibernate-mapping
(1)
schema (可选): 数据库schema名称.

(2)
default-cascade (可选 - 默认为 none): 默认的级联风格.

(3)
auto-import (可选 - 默认为 true): 指定是否我们可以在查询语言中使用非全限定的类名(仅限于本映射文件中的类)。

(4)
default-access (可选 - 默认为 property): NHibernate访问属性值时的策略。

(5)
assembly (可选): 指定一个程序集,如果在映射文档中没有指定程序集,就使用这个程序集。

(6)
namespace (可选): 指定一个命名空间前缀,如果在映射文档中没有指定全限定名,就使用这个命名空间名。
Ø class (1)
name: 持久化类(或者接口)的全限定名。

(2)
table: 对应的数据库表名。

(3)
discriminator-value (可选 - 默认和类名一样): 一个用于区分不同的子类的值,在多态行为时使用。

(4)
mutable (可选, 默认为 true): 表明该类的实例可变(不可变)。

(5)
schema (可选): 覆盖在根《hibernate-mapping》 元素中指定的schema名字。

(6)
proxy (可选): 指定一个接口,在延迟装载时作为代理使用。你可以在这里使用该类自己的名字。

(7)
dynamic-update (可选, 默认为 false): 指定用于UPDATE 的SQL将会在运行时动态生成,并且只更新那些改变过的字段。

(8)
dynamic-insert (可选, 默认为 false): 指定用于INSERT的 SQL 将会在运行时动态生成,并且只包含那些非空值字段。

(9)
polymorphism (可选, 默认为 implicit(隐式)): 界定是隐式还是显式的使用查询多态。

(10)
where (可选) 指定一个附加的SQL WHERE 条件,在抓取这个类的对象时会一直增加这个条件。

(11)
persister (可选): 指定一个定制的 IClassPersister.

(12)
lazy(可选):假若设置 lazy=“true“,就是设置这个类自己的名字作为proxy接口的一种等价快捷形式。
Ø id (1)
name (可选): 标识属性的名字。

(2)
type (可选): 标识NHibernate类型的名字。

(3)
column (可选 - 默认为属性名): 主键字段的名字。

(4)
unsaved-value (可选 - 默认为 null): 一个特定的标识属性值,用来标志该实例是刚刚创建的,尚未保存。这可以把这种实例和从以前的session中装载过(可能又做过修改--译者注)但未再次持久化的实例区分开来。

(5)
access (可选 - 默认为 property): NHibernate用来访问属性值的策略。
除此之外我们可以通过其他途径深入了解配置方面的知识,一个NHibernate项目,配置文件的错误往往导致错误的结果甚至使得程序无法运行。
3 小结
本文初步介绍了LINQ to SQL和NHibernate,其中介绍NHibernate使用了较多的篇幅,因为相对LINQ to SQL而言NHibernate的使用入门门槛较高,配置较为复杂。关于LINQ to SQL、NHibernate优缺点将在后面文章中讨论,不过从此处其实已经得出一点,那就是LINQ to SQL比NHibernate更加容易上手,节省了人员培训的开销。

nhibernate怎么实现数据的添加,删除,修改简单程序


一、创建数据库
数据库名:Nhibernate
use NHibernate
go
CREATE TABLE users (
LogonID nvarchar(20) NOT NULL default ’0’,
Name nvarchar(40) default NULL,
Password nvarchar(20) default NULL,
EmailAddress nvarchar(40) default NULL,
PRIMARY KEY (LogonID)
)
go
数据表:users

二、总体介绍
项目名:WebNhibernate
界面:WebForm.aspx
具体表现文件:WebForm.aspx.cs
实体类文件:EntityClass.cs
映射文件:Userhbm.xml
配置文件:Web.config

三、创建Web界面
类型
对象名
Text属性值
Label
Label1
ID:
Label
Label2
姓名:
Label
Label3
密码:
Label
Label4
Email:
Label
Labmessage

TextBox
TxtId

TextBox
TxtName

TextBox
TxtPassword

TextBox
TxtEmail

Button
ButSave
添加
Button
ButDel
删除
Button
ButUpdata
修改

四、创建映射文件(xml文件)和实体类
实体类
using System;
namespace WebNhibernate
{
public class EntityClass
{
private string id;
private string userName;
private string password;
private string emailAddress;
public EntityClass()
{}
public string Id
{
get { return id; }
set { id = value; }
}
public string UserName
{
get { return userName; }
set { userName = value; }
}
public string Password
{
get { return password; }
set { password = value; }
}
public string EmailAddress
{
get { return emailAddress; }
set { emailAddress = value; }
}
}
}
映射文件:
《?xml version=“1.0“ encoding=“utf-8“ ?》
《hibernate-mapping xmlns=“urn:nhibernate-mapping-2.0“》
《class name=“WebNhibernate.EntityClass, WebNhibernate“ table=“users“》
《id name=“Id“ column=“LogonId“ type=“String“ length=“20“》
《generator class=“assigned“ /》
《/id》
《property name=“UserName“ column= “Name“ type=“string“ length=“40“/》
《property name=“Password“ type=“string“ length=“20“/》
《property name=“EmailAddress“ type=“String“ length=“40“/》
《/class》
《/hibernate-mapping》
注意点:
1.《class name=“WebNhibernate.EntityClass, WebNhibernate“ table=“users“》
WebNhibernate.EntityClass代表:实体类名
WebNhibernate代表:该项目的装配集名称
Users代表:数据表名
2.当属性列表《property name=”” column=””/》中既有name和column说明实体层的属性与数据表的字段名不同名
3.指定一个id, 在数据表中就是主键, 这个非常重要,nhibernate就是通过id来判断对象的唯一性的.

五、在配置文件中添加配置内容
1.首先在配置文件的《configuration》代码下面添加如下代码
《configSections》
《section name=“nhibernate“ type=“System.Configuration.NameValueSectionHandler, System, Version=1.0.3300.0,Culture=neutral, PublicKeyToken=b77a5c561934e089“ /》
《/configSections》
这一段代码是必须要的
2.在配置文件的《/system.web》代码下面添加如下代码
《nhibernate》
《!—连接数据提供者 --》
《add
key=“hibernate.connection.provider“
value=“NHibernate.Connection.DriverConnectionProvider“
/》
《!—连接数据方言最常用的是MsSql2000Dialect --》
《add
key=“hibernate.dialect“
value=“NHibernate.Dialect.MsSql2000Dialect“
/》
《!—连接数据驱动类--》
《add
key=“hibernate.connection.driver_class“
value=“NHibernate.Driver.SqlClientDriver“
/》
《!—连接数据库--》
《add
key=“hibernate.connection.connection_string“
value=“Server=yanfa1;initial catalog=nhibernate;User id=sa;password=8626798;“
/》
《/nhibernate》

六、实现代码
首先在文件头添加代码
using NHibernate;
using NHibernate.Cfg;
1.添加数据:
双击“添加“按钮
private void ButSave_Click(object sender, System.EventArgs e)
{
mCfg=new Configuration();//创建配置类
mCfg.AddXmlFile (System.Web.HttpContext.Current.Server.MapPath(“Userhbm.xml“));//指明映射文件Userhbm.xml
EntityClass vEntity=new EntityClass();
vEntity.Id=TxtId.Text;
vEntity.UserName=TxtName.Text;
vEntity.Password=TxtPassword.Text;
vEntity.EmailAddress=TxtEmail.Text;
ISession vSession= mCfg.BuildSessionFactory().OpenSession();//创建会话工厂, 一般来说应该使用一个单例对象来封装会话工厂.
ITransaction vTransaction = vSession.BeginTransaction();//创建事物处理
try
{
vSession.Save(vEntity);//向数据库添加数据
vTransaction.Commit();
Labmessage.Text=“OK“;
}
catch(Exception ex)
{
vTransaction.Rollback();
Labmessage.Text=“Error“+ex.ToString();
}
finally
{
vSession.Close();
}
}

2.删除数据:
双击“删除“按钮
private void ButDel_Click(object sender, System.EventArgs e)
{
mCfg=new Configuration();
mCfg.AddXmlFile (System.Web.HttpContext.Current.Server.MapPath(“Userhbm.xml“));
ISession vSession= mCfg.BuildSessionFactory().OpenSession();
ITransaction vTransaction = vSession.BeginTransaction();
try
{
EntityClass vEntity=(EntityClass) vSession.Load(typeof(EntityClass),TxtId.Text);//查找数据表中所要记录
vSession.Delete(vEntity);//向数据库删除数据
vTransaction.Commit();
Labmessage.Text=“OK“;
}
catch(Exception ex)
{
vTransaction.Rollback();
Labmessage.Text=“Error“;
}
finally
{
vSession.Close();
}
}

3.修改代码:
双击“修改“按钮
private void ButUpdata_Click(object sender, System.EventArgs e)
{
mCfg=new Configuration();
mCfg.AddXmlFile (System.Web.HttpContext.Current.Server.MapPath(“Userhbm.xml“));
ISession vSession= mCfg.BuildSessionFactory().OpenSession();
ITransaction vTransaction = vSession.BeginTransaction();
try
{
EntityClass vEntity=(EntityClass) vSession.Load(typeof(EntityClass),TxtId.Text);
vEntity.UserName=TxtName.Text;
vEntity.Password=TxtPassword.Text;
vEntity.EmailAddress=TxtEmail.Text;
vSession.Update(vEntity); //向数据库修改数据
vTransaction.Commit();
Labmessage.Text=“OK“;
}
catch(Exception ex)
{
vTransaction.Rollback();
Labmessage.Text=“Error“;
}
finally
{
vSession.Close();
}
}

NHibernate 连接多数据库怎么配置


在开发一些项目时,会使用到多个数据库。例如类A保存在数据库A,类B保存在数据库B。NHibernate在BuildSessionFactory之后,ISessionFactory就不能改变数据库的连接,即是说一个ISessionFactory只能对应一个数据库连接。但NHibernate可以在同一个应用中实例化多个ISessionFactory。实例化多个ISessionFactory,并让类A或类B找到自己所对应的ISessionFactory,获取ISession,即可实现多数据库连接。

如何通过类型获取ISessionFactory呢?ISessionFactory的Statistics.EntityNames中保存了所有映射了的实体类的类名。我们可以判断实体类的类名是否在EntityNames中,确定实体类所对应的ISessionFactory。

根据类型获取ISessionFactory:

public interface ISessionFactoryHolder
{
    ISessionFactory GetSessionFactoryForEntity《TEntity》() where TEntity : IEntity;
}
 public class SessionFactoryHolder : ISessionFactoryHolder
{
    private IDictionary《string, int》 entityDictionary;
    private IDictionary《int, ISessionFactory》 factoryDictionary;
    public SessionFactoryHolder()
    {
        this.entityDictionary = new Dictionary《string, int》();
        this.factoryDictionary = new Dictionary《int, ISessionFactory》();
    }
    #region ISessionFactoryHolder Members
    public ISessionFactory GetSessionFactoryForEntity《TEntity》() where TEntity : IEntity
    {
        int hashCode = 0;
        Asserts.Assert《MappingException》(
            this.EntityInDictionary(typeof(TEntity).FullName, out hashCode) == false
            , string.Format(“No persister for:{0}“, typeof(TEntity).FullName));
        return this.factoryDictionary[hashCode];
    }
    #endregion
    public void RegisterSessionFactory(ISessionFactory sessionFactory)
    {
        Asserts.IsNotNull(sessionFactory, “sessionFactory“);
        this.factoryDictionary[sessionFactory.GetHashCode()] = sessionFactory;
        this.MapingEntityNameToSessionFactoryHashCode(sessionFactory.Statistics.EntityNames
            , sessionFactory.GetHashCode());
    }
    private bool EntityInDictionary(string entityName, out int sessionFactoryHashCode)
    {
        return this.entityDictionary.TryGetValue(entityName, out sessionFactoryHashCode);
    }
    private void MapingEntityNameToSessionFactoryHashCode(string entityNames, int sessionFactoryHashCode)
    {
        foreach (var entityName in entityNames)
        {
            this.entityDictionary[entityName] = sessionFactoryHashCode;
        }
    }
}

根据类型获取ISession:

public interface ISessionHolder : IDisposable
{
    ISession GetSessionForEntity《TEntity》() where TEntity : IEntity;
}
 public class SessionHolder : ISessionHolder, IUnitOfWork
{
    private readonly ISessionFactoryHolder factoryHolder;
    private IDictionary《int, ISession》 sessionDictionary;
    public SessionHolder(ISessionFactoryHolder factoryHolder)
    {
        Asserts.IsNotNull(factoryHolder, “factoryHolder“);
        this.factoryHolder = factoryHolder;
        this.sessionDictionary = new Dictionary《int, ISession》();
    }
    #region ISessionHolder Members
    public ISession GetSessionForEntity《TEntity》() where TEntity : IEntity
    {
        if (this.sessionDictionary.ContainsKey(this.GetFactoryHashCode《TEntity》()) == false)
        {
            this.sessionDictionary[this.GetFactoryHashCode《TEntity》()] = this.OpenNewSession《TEntity》();
        }
        return this.sessionDictionary[this.GetFactoryHashCode《TEntity》()];
    }
    #endregion
    #region IDisposable Members
    //Dispose Code
     #endregion
    #region IUnitOfWork
    //IUnitOfWork
    #endregion
    private ISessionFactory GetFactory《TEntity》() where TEntity : IEntity
    {
        return this.factoryHolder.GetSessionFactoryForEntity《TEntity》();
    }
    private int GetFactoryHashCode《TEntity》() where TEntity : IEntity
    {
        return this.GetFactory《TEntity》().GetHashCode();
    }
    private ISession OpenNewSession《TEntity》() where TEntity : IEntity
    {
        return this.GetFactory《TEntity》().OpenSession();
    }
}

Repository:

public interface IRepository《TEntity》 where TEntity : IEntity
{
    void Save(TEntity entity);
    //......
}
public class NHibernateRepository《TEntity》 : IRepository《TEntity》 where TEntity : IEntity
{
    private readonly ISessionHolder sessionHolder;
    public NHibernateRepository(ISessionHolder sessionHolder)
    {
        Asserts.IsNotNull(sessionHolder, “sessionHolder“);
        this.sessionHolder = sessionHolder;
    }
    protected virtual ISession Session
    {
        get
        {
            return this.sessionHolder.GetSessionForEntity《TEntity》();
        }
    }
    public override void Save(TEntity entity)
    {
        this.Session.Save(entity);
    }
    //......
}

在C#中,用NHibernate对系统进行优化有哪些方式


最好是参考下官方文档,不然研究起来有可能走进一个误区。
其实也没有什么新鲜的东西,简单的项目没必要使用它。因为都是基于ADO.NET的。把ADO.NET学好,那自然就是水到渠成的事情了。
NHibernate是一个基于.Net,用于关系数据库的对象持久化类库.它是著名的Hibernate的.Net版本.
NHibernate用于把你的.Net对象持久化到底层的关系数据库中.你完全不用自己编写Sql语句去操作这些对象,NH会代替你做.你的代码里面只需要关心这些对象,NH生成sql语句并能为你取到正确的东西.
开发过程
HNibernate将会有一些工具帮助你,如:生成schema,根据映射文件(Mapping file)生成类,并更新schema(一个新开发者的建议).然而,在本文档中,前提是你已经手动的数据库的创建喝.Net类的编写...
这里是我们要做的:

1. 在数据库中创建把.Net类持久化的对应表.
2. 创建需要被持久化的.Net类.
3. 创建映射文件,以告诉NH怎样持久化这些类的属性.
4. 创建NH的配置文件,以告诉NH怎样连接数据库.
5. 使用NH提供的API.

步骤1:创建数据库表
步骤2:创建.Net类
步骤3:编写映射文件(Mapping File)
步骤4:创建数据库配置文件

NHibernate二级缓存问题


词条图片
CPU缓存(Cache Memory)位于CPU与内存之间的临时存储器,它的容量比内存小但交换速度快。在缓存中的数据是内存中的一小部分,但这一小部分是短时间内CPU即将访问的,当CPU调用大量数据时,就可避开内存直接从缓存中调用,从而加快读取速度。最初缓存只有一级,二级缓存(L2 CACHE)出现是为了协调一级缓存与内存之间的速度。二级缓存比一级缓存速度更慢,容量更大,主要就是做一级缓存和内存之间数据临时交换的地方用。实际上,现在Intel和AMD处理器在一级缓存的逻辑结构设计上有所不同,所以二级缓存对CPU性能的影响也不尽相同

如何使用Nhibernate动态连接Oracle数据库


  一、使用配置文件nfig)连接数据库
  下面以使用Nhibernate2.2连接Oracle10数据库为例,给出连接配置信息如下:
  《configSections》
  《section name=“hibernate-configuration“ type=“NHibernate.Cfg.ConfigurationSectionHandler, NHibernate“ /》
  《/configSections》
  《hibernate-configuration xmlns=“urn:nhibernate-configuration-2.2“》
  《session-factory name=“NHibernate.Test“》
  《property name=“connection.driver_class“》NHibernate.Driver.OracleClientDriver《/property》
  《property name=“nnection_string“》User ID=hzga;Password=hzga;Data Source=orcl;Persist Security Info=True;《/property》
  《property name=“show_sql“》false《/property》
  《property name=“dialect“》NHibernate.Dialect.Oracle10gDialect《/property》
  《property name=“query.substitutions“》true 1, false 0, yes ’Y’, no ’N’《/property》
  《property name=“proxyfactory.factory_class“》NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu《/property》
  《/session-factory》
  《/hibernate-configuration》
  二、通过提供一个IDictionary实例连接数据库
  下面还是以使用Nhibernate2.2连接Oracle10数据库为例,给出连接配置信息如下:
  cfg = new Configuration();
  IDictionary《string, string》 connProps = new Dictionary《string, string》();
  connProps.Add(“connection.driver_class“, “NHibernate.Driver.OracleClientDriver“);
  connProps.Add(“nnection_string“, “User ID=hzga;Password=hzga;Data Source=orcl;Persist Security Info=True;“);
  connProps.Add(“query.substitutions“, “true 1, false 0, yes ’Y’, no ’N’“);
  connProps.Add(“dialect“, “NHibernate.Dialect.Oracle10gDialect“);
  connProps.Add(“proxyfactory.factory_class“, “NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu“);
  cfg.SetProperties(connProps);
  cfg.AddAssembly(AssemblyName);
  sessions = cfg.BuildSessionFactory();
  三、如何使用Nhibernate动态直接连接Oracle数据库
  上述两种方式都可以成功连接到Oracle数据库,但是前提条件是运行程序时需要安装Oracle客户端。在程序发布部署的时候安装Oracle客户端是一件非常麻烦的事件,那么有没有一种比较好的方法可以直接连接Oracle数据库,同时又不必安装Oracle客户端呢。
  答案是肯定的,下面提供两种方式直接连接Oracle数据库:
  1、通过OleDB和Oracle公司的驱动
  cfg = new Configuration();
  IDictionary《string, string》 connProps = new Dictionary《string, string》();
  connProps.Add(“connection.driver_class“, “NHibernate.Driver.OleDbDriver“);
  connProps.Add(“nnection_string“, “Provider=OraOLEDB.Oracle.1;User ID=hzga;Password=hzga;Data Source=(DESCRIPTION = (ADDRESS_LIST= (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.13.148)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = orcl)))“);
  connProps.Add(“query.substitutions“, “true 1, false 0, yes ’Y’, no ’N’“);
  connProps.Add(“dialect“, “NHibernate.Dialect.Oracle10gDialect“);
  connProps.Add(“proxyfactory.factory_class“, “NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu“);
  cfg.SetProperties(connProps);
  cfg.AddAssembly(AssemblyName);
  sessions = cfg.BuildSessionFactory();
  2、通过OLEDB和微软公司的Oracle驱动
  cfg = new Configuration();
  IDictionary《string, string》 connProps = new Dictionary《string, string》();
  connProps.Add(“connection.driver_class“, “NHibernate.Driver.OleDbDriver“);
  connProps.Add(“nnection_string“, “ Provider=MSDAORA.1;User ID=lportal;Password=lportal;Data Source=(DESCRIPTION = (ADDRESS_LIST= (ADDRESS = (PROTOCOL = TCP)(HOST = zhbrserver)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = orcl)))“);
  connProps.Add(“query.substitutions“, “true 1, false 0, yes ’Y’, no ’N’“);
  connProps.Add(“dialect“, “NHibernate.Dialect.Oracle10gDialect“);
  connProps.Add(“proxyfactory.factory_class“, “NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu“);
  cfg.SetProperties(connProps);
  cfg.AddAssembly(AssemblyName);
  sessions = cfg.BuildSessionFactory();

在NHibernate 中一切必须是 Virtual 的吗求答案


老赵在博文中
我对NHibernate的感受(2):何必到处都virtual
提到这篇文章,顺便翻译一下。
如果你使用过 NHibernate 2.0 或者以后的版本,毫无疑问你将会遇到过几次下面的异常:
NHibernate.InvalidProxyTypeException: The following types may not be used as proxies:
NHibernateExamples.Entities.OrderLine: method get_UnitPrice should be ‘public/protected virtual’ or ‘protected internal virtual’
NHibernateExamples.Entities.OrderLine: method set_UnitPrice should be ‘public/protected virtual’ or ‘protected internal virtual’
对于这个问题的简单答案是:将成员设置为 virtual 是为了延迟加载。
更为详细的答案也更加有趣。 对于真正的 ORM 来说,必须具备的一个重要特征是透明的延迟加载。如果你通过 ORM 来获取一个对象,你不会希望它自动的将相关的整个对象图都拉过来(不包括默认情况),你也不会浪费你的代码来检查相关的对象是否已经加载了。应该在需要的时候加载它们,这是 ORM 的责任,理想情况下,如果这些数据还没有加载,在你第一次访问的时候,ORM 来加载需要的数据。
NHibernate 具有这种能力,不需要你继承任何的 NHibernate 基类或者实现任何的接口,或者类似的任何东西。那么,它如何工作呢?好,NHibernate 在需要延迟加载的时候通过你的类的代理来完成。那么,什么是代理?在这里,NHibernate 的代理是一种在初始化应用程序的时候自动生成的类型(这仅仅发生在应用程序启动的时候),一种代理类型对应一种没有明确不使用延迟加载的实体类型,代理类型将会派生自你定义的实体类型,然后注入你可能在这种类型上的操作。
让我们通过一个简单的例子来使这件事更加清楚一些,假设你定义了一个 Order 类,除了其他的成员之外,Order 类有像 Employee 和 Customer 的属性。当你加载 Order 实例的时候,你可能并不希望 Employee 属性已经包含了实际的 Employee 实体,类似地还有 Customer 属性,默认情况下,NHibernate 延迟加载每一个实体,除非明确配置为不延迟。所以,当 NHibernate 初始化的时候,它将会知道需要为 Employee 和 Customer 类型动态生成代理,假设相应的代理类型为 EmployeeProxyType 和 CustomerProxyType,实际的类型不是这些名称,但是不影响我们的讨论,现在,设想你获取了一个 Order 对象实例,你不希望 NHibernate 预先加载 Customer 和 Employee 数据,你没有请求 Customer 或者 Employee 数据,所以,现在还没有这些数据,对不对?但是他们也不应该是 null ,对吗?所以,NHibernate 赋予一个 CustomerProxyType 的实例给 Customer 属性,EmployeeProxyType 的实例给 Employee 属性,然后,初始化这两个属性,使其包含标识信息,这样,你就得到了内存中的订单数据。
你可以安全的使用 Order 实例,甚至可以访问 Employee 和 Customer 属性,但是,一旦你访问没有实际数据的代理成员,包括属性和方法,NHibernate 需要确信 Customer 或者 Employee 的数据从数据库已经获取,NHibernate 怎么处理呢?代理将会重写所有你的属性和方法,当其中任何一个被访问的时候,如果数据还没有实际获取,NHibernate 将会加载数据,然后执行原来属性或者方法的实现逻辑,如果数据已经获取,那么,就会直接调用原来的实现逻辑。
这是基本的面向对象,你定义的实体对于 NHibernate 代理来说是一个基类,这些代理需要扩展你定义实体的行为,来完成上述的功能,NHibernate 需要 override 任何的公共成员来确信在适当的时间触发这些行为。现在,有不少的人不喜欢这种要求。首先,认为这是一个主要的性能花费,访问虚拟成员要比访问非虚拟成员费时,然而,这种性能损失非常小,几乎在任何情况下都可以完全忽略不计。这种花费与真正的性能花费完全不能相比,比如数据库访问的花费。另外一个不喜欢的原因是他们不希望派生类 override 他们的任何成员,在某些情况下,这是一个有力的理由,但是,实际上没有价值。有其他的 ORM 实现不需要你的成员是 virtual 的情况下仍然可以延迟加载,但是,这些 ORM 实现经常要求你或者派生自某个特定的基类,或者实现一个或者多个 ORM 使用的接口,在这两种情况下,我认为 NHibernate 的做法对实体的影响远远低于其他的 ORM ,不过,这只是我的意见。
但是,如果你真的不需要成员是 virtual,而且不使用 NHibernate 的延迟加载,你只需要简单地映射你的实体不使用延迟加载即可,你的映射文件应该如下所示:《classname=“OrderLine“table=“OrderLine“lazy=“false“

C#中的nhibernate ORM的详解意思是什么


nhibernate是名字,以前叫hibernate,是java的,后来移植到.NET上,就叫nhibernate
ORM就是Object Relational Mapping,是一种技术,主要作用就是将数据库的记录转换成对象,使程序符合面向对象标准。nhibernate就是ORM的移植,其他的还有EF、iBatis等

NHibernate中的schema是干什么用的


关于NHibernate和NHibernate中的schema的问题,你可以参考一下以下文章:
什么是NHibernate
NHibernate 是一个基于.Net 的针对关系型数据库的对象持久化类库。Nhibernate 来源于非常优秀的基于Java的Hibernate 关系型持久化工具。
NHibernate 从数据库底层来持久化你的.Net 对象到关系型数据库。NHibernate 为你处理这些,远胜于你不得不写SQL去从数据库存取对象。你的代码仅仅和对象关联,NHibernat 自动产生SQL语句,并确保对象提交到正确的表和字段中去。
为什么写这个指南
任何熟悉Hibernate的人会发现这篇指南和Glen Smith 的 A Hitchhiker’s Guide to Hibernate 非常相近。这里的内容正是基于他的指南,因此所有的感谢都应该给与他。
NHibernate的文档并非每处都和Hibernate的文档一致。然而,项目的相似应该能使读者通过读Hibernate的文档来很好的理解NHibernate如何工作。
这篇文档意在让你尽可能快的开始使用NHibernate。它将介绍如何持久化一个简单的对象到一张表里。想得到更多的复杂的例子,可以参考NUnit测试及附带代码。
开发的过程
Nhibernate未来将会提供一些工具帮助你自动产生schema文件(现在还是基于代码)或是通过映射文件产生类(在筹措阶段)或是更新schema(来自于一个新开发者的建议)。然而,这里我们的例子是假定一切来自于完全手写,包括设置表和.Net类的编写。我们将进行以下步骤。
1.新建一个将要持久化.Net对象的表
2.构建一个需要被持久化的.Net类
3.构建一个可以让NHibernate知道如何持久化对象属性的映射文件
4.构建一个让NHibernate知道如何连接数据库的配置文件]
5.使用NHibernate的API
第一步:写构建表的SQL
这里我们将使用的是一个非常简单的例子。假设你正在为你的网站开发一个基本的用户管理子系统。我们将使用如下的一张User表(假定你已经设置好一个数据库—在的例子里我称它为NHibernate)。
use NHibernate
go

CREATE TABLE users (
LogonID nvarchar(20) NOT NULL default ’0’,
Name nvarchar(40) default NULL,
Password nvarchar(20) default NULL,
EmailAddress nvarchar(40) default NULL,
LastLogon datetime default NULL,
PRIMARY KEY (LogonID)
)
go
我使用的是MS Sql Server 2000, 但也可以使用任何数据库,只要你有关于它们的基于.Net数据提供驱动程序。我们将得到一个含有LogonID,Name, Password, Email 和LastLogon的表. 经过以上标准步骤,我们下一步是写一个.Net类处理一个给定的User对象。
第二步:产生一个.Net 类文件
当内存中有一堆User对象的时候,我们需要某种对象去保存它们。NHibernate通过对象属性的反射来工作,因此我们需要添加我们希望持久化的对象属性。一个可以被NHibernate持久化的类应该看起来象下面的样子:

using System;

namespace NHibernate.Demo.QuickStart
{
public class User
{
private string id;
private string userName;
private string password;
private string emailAddress;
private DateTime lastLogon;
public User()
{
}

public string Id
{
get { return id; }
set { id = value; }
}

public string UserName
{
get { return userName; }
set { userName = value; }
}

public string Password
{
get { return password; }
set { password = value; }
}

public string EmailAddress
{
get { return emailAddress; }
set { emailAddress = value; }
}

public DateTime LastLogon
{
get { return lastLogon; }
set { lastLogon = value; }
}

}
}
在上面的例子里,我们的属性和构建函数 是public,但这个对NHibernate不是必要的.它可以使用public, protected, internal或者甚至是用private来持久化数据。
第三步:写映射文件
现在我们有数据表和需要去映射它的.Net类。我们需要一种方式去让NHibernate知道如何从一个映射到另一个。这个任务依赖于映射文件来完成。最易于管理的办法是为每一个类写一个映射文件,如果你命名它是YourObject.hbm.xml 并且把它放在和类的同一个目录里,NHiberante将会使得事情简单起来。下面是一个User.hbm.xml的例子:

《?xml version=“1.0“ encoding=“utf-8“ ?》
《hibernate-mapping xmlns=“urn:nhibernate-mapping-2.0“》
《class name=“NHibernate.Examples.QuickStart.User, NHibernate.Examples“ table=“users“》
《id name=“Id“ column=“LogonId“ type=“String“ length=“20“》
《generator class=“assigned“ /》
《/id》
《property name=“UserName“ column= “Name“ type=“String“ length=“40“/》
《property name=“Password“ type=“String“ length=“20“/》
《property name=“EmailAddress“ type=“String“ length=“40“/》
《property name=“LastLogon“ type=“DateTime“/》
《/class》

《/hibernate-mapping》

让我们来看看这个文件中让我们感兴趣的某些行。第一个有趣的标签是class。这里我们将映射类型名称(类名和装配件)到我们数据库中的User表,这里和Hibernate有一点点的不同。你将不得不告诉NHibernate从何处提取对象。在这个例子里我们从装配件NHibernate.Examples装载类NHibernate.Examples.QuickStart.User 。NHibernate 遵循和.Net Framework同样的规则来加载类型。因此如果你在如何指定类型的方面有些混淆,请参看.Net Framework SDK。
让我们先跳过id标签,来讨论property标签。简要看一下,你将发现NHibernate所要做的工作。name属性的值正是我们.Net 类的属性,column属性值将是我们数据库里的字段。type属性是可选的(如果你不标明,NHibernate将利用反射进行最佳的推测)。
好了,让我们回到标签id, 你可以猜测到这个标签将是映射数据库表的主键,的确如此,id标签的组成和我们刚才看的property标签是相似的。我们映射属性到目标数据库的字段。
内嵌的generator 标签告诉NHibernate 如何生成主键(它将恰当的为你生成主键,不管你指定何种类型,但你必须告诉它)。在我们的例子里,我们设定为assigned,意味着我们对象将自己生成主键(毕竟User对象常常需要一个UserID)。如果你执意要NHiberante为你生成主键,你感兴趣于设定uuid.hex和uuid.string(从文档中获取更多信息)
提示:如果你使用Visual Studio.Net 去编译的话,请将user.hbm.xml的Build Action属性设置为Embedded Resource。映射文件将成为装配件的一部分。更详细的细节重点将在后面展示。
提示:如果你仅仅是改变映射文件,你不能使用build 而应该Rebuild项目。Visual Studio.Net 不会重新编译有改变的映射文件。
第四步:为你的数据库产生一个配置文件
我们至今还没有告诉NHibernate 去哪里连接数据库。最直接的办法是在你的应用程序的配置文件里设置一个NHibernate配置节。这和在Hibernate里使用属性文件是等价的。如下配置:
《?xml version=“1.0“ encoding=“utf-8“ ?》
《configuration》
《configSections》
《section name=“nhibernate“ type=“System.Configuration.NameValueSectionHandler, System, Version=1.0.3300.0,Culture=neutral, PublicKeyToken=b77a5c561934e089“ /》
《/configSections》

《nhibernate》
《add
key=“hibernate.connection.provider“
value=“NHibernate.Connection.DriverConnectionProvider“
/》
《add
key=“hibernate.dialect“
value=“NHibernate.Dialect.MsSql2000Dialect“
/》
《add
key=“hibernate.connection.driver_class“
value=“NHibernate.Driver.SqlClientDriver“
/》
《add
key=“hibernate.connection.connection_string“
value=“Server=localhost;initial catalog=nhibernate;Integrated Security=SSPI“
/》
《/nhibernate》
《/configuration》

上面的例子里用了SqlClient 驱动,在本地连接名称为NHibernate 的数据库,提供用户名和密码。那里有一堆属性你需要调整来确定如何让NHibernate来访问数据库。再次说明,你可以在文档里获取更多信息。
请注意以上的配置里并没有涉及到log4net的配置信息。NHibernate使用log4net来记录内部发生的一切。在一个应用程序产品里,在你特定环境里,我推荐配置log4net,并为NHibernate设置一定的日志级别。
第五步:开始展现NHibernate的魔力
所有艰苦的工作已经完成。你将有以下内容
User.cs ----你需要持久化的C#类
User.hbm.xml ----你的NHibernate映射文件
App.config ---对ADO.NET连接的配置信息(如果你愿意,你可以在代码中实现)。
你的数据库里有一张User表。
现在可以在你的代码中恰当简洁的使用NHibernate。简化的版本如下
创建一个Configuration对象
让Configuration知道你将存储何种类型的对象
为你选择的数据库创建一个Session对象
Load,Save和Query你的对象
通过Session的Flush()方法将对象提交给数据库。
为了让你更清晰,我们来看一些代码。
首先,创建一个Configuration对象
Configuration对象能够解析所有.Net对象和后台数据库中的映射关系。

Configuration cfg = new Configuration();
cfg.AddAssembly(“NHibernate.Examples“);

Configuration对象会搜索装配件里的任何以hbm.xml 结尾的文件。还有其他方法加载映射文件,但这种方式是最简单的。
下一步,创建一个Session对象
ISession对象提供一个到后台数据库的连接,ITransaction对象提供一个可以被NHibernate管理的事务。
ISessionFactory factory = cfg.BuildSessionFactory();
ISession session = factory.OpenSession();
ITransaction transaction = session.BeginTransaction();
接着来Load, Save和Query你的对象
现在你可以用使用传统的.Net方法来操纵对象。你想保存一个新对象到数据库吗?尝试下面的方法:
User newUser = new User();
newUser.Id = “joe_cool“;
newUser.UserName = “Joseph Cool“;
newUser.Password = “abc123“;
newUser.EmailAddress = “joe@cool.com“;
newUser.LastLogon = DateTime.Now;

// Tell NHibernate that this object should be saved
session.Save(newUser);

// commit all of the changes to the DB and close the ISession
transaction.Commit();
session.Close();
正如你所看到的,关于NHiberante重要的事情是如此简单。继续并且查询你的数据库,验证一下User表里的新记录。现在重要的事情就是你去操心业务对象并在进行处理的时候告诉NHibernate就可以了。
让我们来告诉你,当你有一个UserID的时候如何获取对象(举例说,登陆你的网站的时候)。仅仅一句话就可以打开Session,传入key就可以了
// open another session to retrieve the just inserted user
session = factory.OpenSession();

User joeCool = (User)session.Load(typeof(User), “joe_cool“);
你所获取的User对象还在生存周期内!改变它的属性,并通过Flush()持久化到数据库。
// set Joe Cool’s Last Login property
joeCool.LastLogon = DateTime.Now;

// flush the changes from the Session to the Database
session.Flush();
你所要做的就是通过NHibernate来进行你需要的改变,并调用Session的Flush()方法提交。验证一下数据库,查查用户ID为”joe_cool”的记录中”LastLogon”的更改。
还有更好的,你可以以System.Collections.IList的方式来获取从表中的对象。如下

IList userList = session.CreateCriteria(typeof(User)).List();
foreach(User user in userList)
{
System.Diagnostics.Debug.WriteLine(user.Id + “ last logged in at “ + user.LastLogon);
}

这个查询将会返回所有表记录。往往你需要做更多的控制,比如说获取从March 14, 2004 10:00 PM 以后登陆的用户,如下:

IList recentUsers = session.CreateCriteria(typeof(User))
.Add(Expression.Expression.Gt(“LastLogon“, new DateTime(2004, 03, 14, 20, 0, 0)))
.List();

foreach(User user in recentUsers)
{
System.Diagnostics.Debug.WriteLine(user.Id + “ last logged in at “ + user.LastLogon);
}
文档里还有一堆健壮的查询方式让你调用,这里仅仅让你对NHibernate所提供的强有力的工具有一定的了解。

最后调用Session对象的Close()方法,释放NHibernate所使用的ADO.Net连接资源

// tell NHibernate to close this Session
session.Close();
更确切地说…
你已经完成创建对象,持久化并通过条件查询或键值查询来返回它。相信你已经从中获得快乐。
现在你对NHibernate有了大致的了解,如果你能仔细阅读大量来自Hibernate 2.0.3文档,你将获得帮助(NHibernate文档还在早期阶段,现在还仅仅是对Hibernate的拷贝)。
Enjoy! And Happy NHibernating!
Mike Doerfler

推荐阅读

    学习写字楼新选择6000元主流配置

    学习写字楼新选择6000元主流配置,,这种配置需要考虑双核心的办公和娱乐平台,充分考虑办公室的办公需求和娱乐需求,以约6000元的预算和cost-e

    酷睿I7 配置

    酷睿I7 配置,配置,玩家国度啦华硕 Rampage II Extreme(3800元)如果米不够,也可以把Extreme改为Gene,不过是小板内存推荐金士顿6G DDR3 2000骇

    提高3A四核羿龙II游戏配置的性能

    提高3A四核羿龙II游戏配置的性能,,以节能环保为主题的IT产业,目前3A低端平台处理器、主板芯片组、独立开发卡性能突出,特别是在与AMD的处理

    苹果电脑如何连接和使用扫描仪

    苹果电脑如何连接和使用扫描仪,,扫描仪的使用 用苹果扫描图像。 连接扫描仪:在打开苹果电脑之前,你需要连接扫描仪和安装扫描仪驱动程序。扫

    opporeno8参数配置及价格

    opporeno8参数配置及价格,面部,亿元,Oppo的荣誉2020年1月4日,接近屏幕关闭传感器是否支持双卡:支持oppor11splus什么时候上市的Oppo R11S P

    查看配置:酷睿i3530集展示办公平台

    查看配置:酷睿i3530集展示办公平台,,由于时间和精力的关系,我们不可能对所有的配置进行评论,希望我们能理解,我希望我们的评论能在那些需要帮

    3500元超额值学生娱乐结构的优化配置

    3500元超额值学生娱乐结构的优化配置,,作为一个DIY的主流用户领域的学生,每个用户51学生攒机的高峰。因为学生用户没有稳定的收入来源,攒机

    1394连接是什么1394网络适配器知识

    1394连接是什么1394网络适配器知识,,今天有网友在QQ群中问了这样一个问题:1394连接是什么?。由于笔者对1394连接不清楚,通过百度搜索与谷歌