这两天看了Terrylee的ActiveRecord学习实践系列,使我对Castle的ActiveRecord有了一个初步的认识。今天先把实践中遇到的一些小问题作个记录,便于日后总结、修正。
最初遇到的一个问题就是:在做Many-Many关系映射,用实体类生成数据表的时候出现异常,如下:
************** Exception Text **************
Castle.ActiveRecord.Framework.ActiveRecordException: Could not create the schema
---> NHibernate.HibernateException: Column names in each table must be unique. Column name 'blog_id' in table 'Blog_Community' is specified more than once.
---> System.Data.SqlClient.SqlException: Column names in each table must be unique. Column name 'blog_id' in table 'Blog_Community' is specified more than once.
...
实体类设计如下:
[ActiveRecord(
"
Blogs
"
)]
public
class
Blog : ActiveRecordBase
<
Blog
>
{
private
int
_id;
private
String _name;
private
String _author; [PrimaryKey(PrimaryKeyType.Native,
"
blog_id
"
)]
public
int
Id {
get
{
return
_id; }
set
{ _id
=
value; } } [Property(
"
blog_name
"
, NotNull
=
true
)]
public
String Name {
get
{
return
_name; }
set
{ _name
=
value; } } [Property(
"
blog_author
"
, NotNull
=
true
)]
public
String Author {
get
{
return
_author; }
set
{ _author
=
value; } }
private
IList _posts; [HasMany(
typeof
(Post), Table
=
"
Posts
"
, ColumnKey
=
"
post_blogid
"
)]
public
IList Posts {
get
{
return
_posts; }
set
{ _posts
=
value; } }
private
IList _community; [HasAndBelongsToMany(
typeof
(Community), Table
=
"
Blog_Community
"
, ColumnRef
=
"
community_id
"
, ColumnKey
= "blog_id "
)]
public
IList Communities {
get
{
return
_community; }
set
{ _community
=
value; } } } [ActiveRecord(
"
Posts
"
)]
public
class
Post : ActiveRecordBase
<
Post
>
{
private
int
_id;
private
String _title;
private
String _contents;
private
String _category;
private
DateTime _created;
private
bool
_published;
private
Blog _blog;
public
Post() { _created
=
DateTime.Now; }
public
Post(Blog blog, String title, String contents, String category) :
this
() { _blog
=
blog; _title
=
title; _contents
=
contents; _category
=
category; } [PrimaryKey(PrimaryKeyType.Native,
"
post_id
"
)]
public
int
Id {
get
{
return
_id; }
set
{ _id
=
value; } } [Property(
"
post_title
"
, NotNull
=
true
)]
public
String Title {
get
{
return
_title; }
set
{ _title
=
value; } } [Property(Column
=
"
post_contents
"
, ColumnType
=
"
StringClob
"
)]
public
String Contents {
get
{
return
_contents; }
set
{ _contents
=
value; } } [Property(
"
post_categories
"
)]
public
String Category {
get
{
return
_category; }
set
{ _category
=
value; } } [BelongsTo(
"
post_blogid
"
)]
public
Blog Blog {
get
{
return
_blog; }
set
{ _blog
=
value; } } [Property(
"
post_created
"
)]
public
DateTime Created {
get
{
return
_created; }
set
{ _created
=
value; } } [Property(
"
post_published
"
)]
public
bool
Published {
get
{
return
_published; }
set
{ _published
=
value; } } } [ActiveRecord(
"
Communities
"
)]
public
class
Community : ActiveRecordBase
<
Community
>
{
private
int
_id;
private
String _name;
private
String _intro; [PrimaryKey(PrimaryKeyType.Native,
"
community_id
"
)]
public
int
Id {
get
{
return
_id; }
set
{ _id
=
value; } } [Property(
"
community_name
"
, NotNull
=
true
)]
public
String Name {
get
{
return
_name; }
set
{ _name
=
value; } } [Property(
"
community_intro
"
)]
public
String Intro {
get
{
return
_intro; }
set
{ _intro
=
value; } }
private
IList _blog; [HasAndBelongsToMany(
typeof
(Blog), Table
=
"
Blog_Community
"
, ColumnRef
=
"
blog_id
"
, ColumnKey
=
"
community_id
"
)]
public
IList Blogs {
get
{
return
_blog; }
set
{ _blog
=
value; } } }
当时以为是Many–Many的映射在正向生成数据表时,由于成对出现的HasAndBelongsToMany属性,导致重复创建Blog_Community表的列(blog_id,community_id)而导致以上错误。虽然这个问题应该是不会出现的,但实在没找出具体原因,也只能暂且认为是AR本身的问题了 -_-! 于是乎就跳过它,接着搞。
在做过另一些实验后,回过头来突然发现Many–Many的映射在正向生成数据表时又执行成功了.... 一阵莫名其妙&*%^*%^$ 仔细地对照了前后的代码,发现原因出在空格符上(实体类代码中红色背景部分)。
在Sql里不区分大小写,一般的空格符也会被忽略掉,例如这个小例子:
create table T_tmp (t_id int, t_name varchar(25))
alter table T_tmp add t_id int --报错 (这里的 t_id前有个空格)
错误信息:
Msg 2705, Level 16, State 4, Line 2
Column names in each table must be unique. Column name 'id' in table 'T_tmp' is specified more than once.
create table [ T_tmp](t_id int) --成功创建了表 T_tmp
select * from T_tmp
select * from [ T_tmp]
回到C#里,C#是区分大小写的,而且"blog_id "(右边有空格)和"blog_id"是不同的。所以在生成数据表时,应该就会去创建"blog_id "和"blog_id"两个字段,而到数据库中则认为这两个列名是相同的,异常就这样产生了。同理大小写的不同也会造成以上错误。
看来学习还是严谨点好,尤其是在一些细节上。又一次教训!
另外发现AR里ActiveRecordBase挺好用的,它已经为我们重写了基础的静态方法,如Find(),TryFind(),DeleteAll(),FindAll()。这样不仅减少了我们的代码量,也保证了类型安全。要提一下的是,其中Find()在没有找到符合的结果时会抛出"Castle.ActiveRecord.NotFoundException"类型的异常。如果不希望抛出异常则可以使用TryFind(),它只返回null值。
留下几个待进一步实践学习的东西
1. 关于延时加载 lazy
2. 有继承关系的类怎样较好地转化为AR的实体类
最后,感谢Terrylee以及许多无私奉献的前辈们!
文章来源:
http://www.agilelabs.cn/blogs/%e8%8c%83%e4%bf%8a/archive/2006/05/14/1211.aspx