把Castle.DynamicProxy.dllIesi.Collections.dll
log4net.dll
NHibernate.dll
SQLite.NET.dll
2:添加引用
各项目之间添加引用 UI引用BLL , Model; BLL引用DAL , Model ; DAL引用Model。
对 DAL 添加
Castle.DynamicProxy.dll
Iesi.Collections.dll
log4net.dll
NHibernate.dll
SQLite.NET.dll的引用。
3:拷贝数据库文件lstx.db和sqlite3.dll 到UI项目下,并且在文件属性中,将文件的“复制到输出目录”设置为“如果较新则复制”。
准备工作做好了 我们在Model里写实体类,我就先挑个简单的User类来写吧。
User类在我的数据库中对应o_user表,表中有userID INTEGER,userName VARCHAR,userPwd VARCHAR,playerID INT , 其中playerID 为外键,对应到o_player表中的playerID。类结构如下:
public class User { #region 成员变量 private int userID { get; set; } private String userName { get; set; } private String userPwd { get; set; } private int playerID { get; set; } #endregion #region 构造函数 public User() { } public User(int uid, String uname, String upwd, int pid) { this.userID = uid; this.userName = uname; this.userPwd = upwd; this.playerID = pid; } #endregion }}
因为另一个Player类还没有创建 暂时这里的playerID就用一个int来代替吧,我想先看看能不能正常的插入单表数据。
接下来写该类的映射文件
在Model项目里添加一个xml文件User.hbm.xml。
<?xml version="1.0" encoding="utf-8" ?><hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Model" namespace="Model" default-lazy="false"> <class name="Model.User, Model" table="o_user"> <id name="userID" column="userID " type="int" unsaved-value="0"> <generator class="increment" /> </id> <property name="userName" column="userPwd" unique="true" not-null="true" type="String" /> <property name="userPwd" column="userPwd" not-null="true" type="String" /> <property name="playerID" column="playerID" type="String"/> </class></hibernate-mapping>
assembly="Model" 这是程序集的名称
namespace="Model" 这是命名空间的名称
class name="Model.User, Model" 指向命名空间下的类文件,
table="o_user" 指向数据库中该类对应的表名
接下来id标签设置主键
unsaved-value 判断被操作的对象究竟是一个已经持久化过的持久对象还是临时对象
默认unsaved-value="null"
主键是对象类型,hebernate判断project的主键是否位null,来判断project是否已被持久化
是的话,对project对象发送save(project),
若自己设置了主键则直接生成update的sql,发送update(project),即便数据库里没有那条记录。
其它的值还有 none,any等 ,但主键是基本类型如int/long/double/ 的话 一般就设置为0,
这样的话save和update操作都不会报错。
再接下来的property标签就没有什么好说的了。最后不要忘记把这个文件的属性设置为嵌入的资源。否则出现“ failed: NHibernate.MappingException : No persister for: NHibernateSample.Domain.Entities.Customer”异常。
然后我们去UI项目中添加一个App.config文件,在其中配置hibernate和log4net等
<?xml version="1.0" encoding="utf-8" ?><configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /> <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/> </configSections> <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" > <session-factory> <property name="hibernate.show_sql">true</property> <property name="hibernate.connection.release_mode">on_close</property> <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property> <property name="connection.driver_class">NHibernate.Driver.SQLiteDriver</property> <property name="connection.connection_string">Data Source=<!-- 数据库名-->lstx.db;Version=3</property> <property name="dialect">NHibernate.Dialect.SQLiteDialect</property> <property name="query.substitutions">true=1;false=0</property> <!-- 在这里添加assembly程序集的话可以减少后面设置程序集的麻烦 它将自动映射Model下所有的配置 --> <mapping assembly="Model" /> </session-factory> </hibernate-configuration> <log4net> <appender name="console" type="log4net.Appender.ConsoleAppender, log4net"> <layout type="log4net.Layout.PatternLayout,log4net"> <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p %c{1}:%L - %m%n" /> </layout> </appender> <appender name="fileAppender" type="log4net.Appender.FileAppender"> <file value="log-file.txt" /> <appendToFile value="true" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> </layout> </appender> <root> <level value="WARN" /> <appender-ref ref="console" /> <appender-ref ref="fileAppender" /> </root> </log4net></configuration>
在DAL项目中实现对SQLite的操作访问
可能大家的设计思路不一样,我只是介绍我自己的一种方案,高手可以直接跳过去。
我觉得一个通用的DAO应该具备以下几种方法:
public interface IGenericDao { Object save(Object entity); //增加 bool delete(Object entity); //删除 bool deleteById(Type type, object id);//根据主键删除 Object modify(Object obj); //修改 Object findById(Type type, object id);//根据主键查找 IList findByCriteria(ICriteria criteria, Object obj);//QBC查询,我喜欢用,当然你也可以用别的 List<Object> findAll(Type type);//查询所有 List<Object> findByQueryString(String queryString);//字符串查询 }
我先实现save方法来测试一下是否能正常对SQLlite插入数据
首先实现IGenericDao:
然后创建接口IUserDao,它的实现类UserDao继承自GenericDao.
using System;
namespace DAL
{
public interface IUserDao
{
void regUser(Model.User user);
}
}
到这里DAL就可以先放下了 去BLL里写业务逻辑层
在BLL里创建接口 IUserService,它的实现类UserService中有一个IUserDao类型的变量.
using System;
namespace BLL
{
public interface IUserService
{
void regUser(Model.User user);
}
}
好BLL也写完了,最后是去UI里创建一个测试的窗体Reg.cs.
namespace UI{
public partial class Reg : Form
{
public Reg()
{
InitializeComponent();
}
private IUserService service = new UserService();
private void btnReg_Click(object sender, EventArgs e)
{
String name = this.txtUserName.Text;
String pwd = this.txtUserPwd.Text;
int pid = Int32.Parse(this.txtPlayerID.Text);
User user = new User(0, name, pwd, pid);
service.regUser(user);
}
}
}
到这里我们这个Hibernate+SQLite+MVC基本的配置就写完了
来一张现在的解决方案截图;
could not insert: [Model.User#1][SQL: INSERT INTO o_user (userPwd, userPwd, playerID, userID ) VALUES (?, ?, ?, ?)]
不难看出 是我的列名写错了 有两个userPwd,我们去User.hbm.xml中看一下,果然。
property name="userName" column="userPwd" 把这里的userPwd改成userName。再试一次。
这次点击注册后没有任何反应了,起码我们知道没有报错了。去数据库里看看。
我懒得打命令 正好SQL Expert又是打开的 所以我直接进去看了。嗯 ,还真有。
证明我们之前的配置可以正常的使用Hibernate来操作SQLite。
今天写太多了,不知道有没有人发现playerID是一个外键,但是我随便输入了一个Int值它都可以正常插入,
这样的看来外键似乎没有起到什么作用。其实我在之前就说过了,不明白的人可以回去看看。就到这里,下次见。