分享

写给新手:零起点学习数据库访问,使用刚刚发布的 EF 4.1。Entity Framewo...

 Cloud书屋 2013-01-04
注意,本文的源代码已经上传,位于http://download.csdn.net/source/3190793,欢迎下载。

如果你是一个新手,完全对数据库没有概念。你没听说过SQL,搞不清什么是表、什么是字段,也从来没有用过DataSet,DataTable。但是学习过C#语言,那么这篇文章可能会帮助到你。

微软刚刚发布了Entity Framework 4.1,提供了一个重要的新特性,Code First,这个特性的强大之处就在于,有了它,从此你完全不用了解数据库,一样可以轻松存取数据了。

为了开始,你需要安装如下的软件:
Windows 操作系统,为了保证不出意外,推荐安装原版的操作系统,Windows 7以及Windows Server 2008 R2为最佳。我安装的是Windows Server 2003 Enterprise。
首先安装Visual Studio 2010旗舰版,VS2010内置了SQL Server 2008 Express。之后需要安装 .NET Framework 3.5 SP1。然后安装 PowerShell 2.0。你可以选择安装 SQL Server 2008 R2 Management Studio Express。最后安装Visual Studio 2010 Service Pack 1。SP1安装的时间比较长一些,如果CPU不是很好的话。安装完这些,就可以正式开始了。

为了尽可能简单,我们一起来做一个最简单的案例。这个案例包括两个实体:用户组和用户,一个用户组包含N个用户,一个用户只能隶属于一个组。用户组只有一个属性,用户组名,用户有4个字段,用户名、密码、性别、所在城市。给用户组和用户一个 N:1 的关系。最后允许用户注册、登录,查询。

第一步,启动Visual Studio,新建一个Console Application。之所以选择控制台是考虑到一部分人用C#开发Web程序,另一部分人开发WinForms程序。而控制台无疑是最基本和简单的。

首先我们添加对 CodeFirst 的支持:

如图所示打开包管理器控制台。


NuGet是一个工具,可以方便地从社区下载开发库。但是这东西貌似还不完善,GUI版本会出错,所以使用控制台。

在控制台输入 install-package efcodefirst
回车

稍等片刻(在此期间VS会卡死一会儿)

出现
PM> install-package efcodefirst
'EntityFramework (≥ 4.1.10331.0)' not installed. Attempting to retrieve dependency from source...
Done
You are downloading EntityFramework from Microsoft, the license agreement to which is available at http://go.microsoft.com/fwlink/?LinkID=211010. Check the package for additional dependencies, which may come with their own license agreement(s). Your use of the package and dependencies constitutes your acceptance of their license agreements. If you do not accept the license agreement(s), then delete the relevant components from your device.
Successfully installed 'EntityFramework 4.1.10331.0'
Successfully installed 'EFCodeFirst 1.1'
Successfully added 'EntityFramework 4.1.10331.0' to ConsoleApplication1
Successfully added 'EFCodeFirst 1.1' to ConsoleApplication1

PM> 
表明安装成功。

第二步,我们定义实体类

新建一个代码文件,叫 Model.cs,为了方便起见,我们把所有用到的类都写在这里。

首先我们定义两个实体,代码非常简单:
C# code
1
2
3
4
5
6
7
8
9
10
11
12
13
    class User
    {
        public string UserName { getset; }
        public string Password { getset; }
        public bool Sex { getset; }
        public string City { getset; }
    }
 
    class UserGroup
    {
        public int ID { getset; }
        public string GroupName { getset; }
    }


之后我们做一点修饰,让UserName作为关键字,Password不能为空。至于ID,根据约定,默认EF就会把它当作关键字。这个体现了CoC(约定优于配置)的思想,也就是说,只有当你的想法和框架库不同,你才需要额外的工作,否则一切都已经做好了。

为此,首先加上 using System.ComponentModel.DataAnnotations;
我们用到的几个标记都属于Data Annotations。

我们给UserName加上Key标记,给Password加上Required标记。

然后我们来定义关系,非常简单:
在User类里面添加一个UserGroup类型的成员:
UserGroup Group { get; set; }
在UserGroup里面定义一个列表,表示它拥有的用户:
IList<User> Users { get; set; }

现在完整的代码如下:
C# code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    class User
    {
        [Key]
        public string UserName { getset; }
 
        [Required]
        public string Password { getset; }
 
        public bool Sex { getset; }
        public string City { getset; }
 
        public UserGroup Group { getset; }
    }
 
    class UserGroup
    {
        public int ID { getset; }
        public string GroupName { getset; }
 
        public IList<User> Users { getset; }
    }
}


现在我们还需要定义一个数据库对象,让EF知道我们程序里面哪些类是实体。

C# code
1
2
3
4
5
    class UserDB : DbContext
    {
        public DbSet<User> Users { getset; }
        public DbSet<UserGroup> UserGroup { getset; }
    }


如果之前使用过Linq To SQL或者EF,那么对DbContext应该不陌生。DbContext对象提供了我们和数据库打交道的入口。

全部定义数据库的代码全部搞好了,至于建立数据库表、关系、结构,这些事情全部都不需要了!你没有听错,这些全部是幕后实现的。

等等,我们还需要一点配置,让EF知道我们用什么数据库服务器,以及在哪里建立数据库。

如图,新建一个配置文件:


在里面加入如下配置:
XML/HTML code
1
2
3
4
5
6
7
  <configuration>
    <connectionStrings>
      <add
        name="UserDB"
        providerName="System.Data.SqlClient"
        connectionString="Server=.\SQLEXPRESS;Database=ConsoleApplication1_db;Trusted_Connection=true;"/>
    </connectionStrings>

name和定义的数据库类名一致,至于Server=.\SQLEXPRESS,你可以设置成你自己的SQL Server服务器名。数据库名建议以程序名命名,以免混淆。

做好了这一切,我们就可以试下:

在主程序里面写:

C# code
1
2
3
4
5
6
7
8
UserDB db = new UserDB();
var ug = new UserGroup()
{
    ID = 1,
    GroupName = "Admin"
};
db.UserGroup.Add(ug);
db.SaveChanges();


这段代码会产生一个 UserGroup 对象,并且添加到数据库里面。

按 Ctrl + F5 运行。

因为需要初始化数据库,所有有些慢,等程序运行完毕,我们打开数据库看一下:

打开服务器资源管理器窗格,添加一个连接,在服务器名里面输入服务器名(我这里是 .\SQLEXPRESS),选择数据库名。

打开以后如图:


分别查看表关系、User表的定义和UserGroup表的数据:


你已经发现了,EF完美地为我们创建了数据库,并且正确地处理了变量类型、是否为空等属性。更为巧妙的是,它还自动产生了我们需要的 1:N 关系。

最后,我们的程序插入的数据也已经在 UserGroup 里面了。

当Model修改后,数据库结构和模型不匹配了,EF为了防止破坏现有的数据,会阻止程序访问数据库。

在程序调试阶段,我们不希望这样,为此,在Main函数里面我们给指定一个初始化策略:每次创建数据库前都把之前的删掉,从头开始,为此我们在Main()开始处增加如下代码:

C# code
1
Database.SetInitializer<UserDB>(new DropCreateDatabaseAlways<UserDB>());


下面,简单演示下数据库的几种基本操作,增加、删除、修改、查询。

首先我们需要提供一些初始化的数据,为此,我们从DropCreateDatabaseAlways继承一个类,把初始化工作放在里面:

C# code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
    class DBInitializer : DropCreateDatabaseAlways<UserDB>
    {
        protected override void Seed(UserDB context)
        {
            base.Seed(context);
 
            //添加用户组
            var uglist = new List<UserGroup>() 
            
                new UserGroup()
                {
                    GroupName = "Admin"
                },
                new UserGroup()
                {
                    GroupName = "User"
                },
                new UserGroup()
                {
                    GroupName = "Guest"
                }
            };
            uglist.ForEach(ug => context.UserGroup.Add(ug));
            //上面的 Lambda 表达式等同下面的语句。
            //foreach (var ug in uglist)
            //{
            //    context.UserGroup.Add(ug);
            //}
            context.SaveChanges();
 
            //添加管理员
            UserGroup ugadmin = (from x in context.UserGroup 
                            where x.GroupName == "Admin" select x).SingleOrDefault();
            if (ugadmin != null)
            {
                var adminuserlist = new List<User>() 
                
                    new User()
                    {
                        UserName = "张三",
                        City = "北京",
                        Password = "123456",
                        Sex = true,
                        Group = ugadmin
                    },
                    new User()
                    {
                        UserName = "李四",
                        City = "天津",
                        Password = "123456",
                        Sex = true,
                        Group = ugadmin
                    }
                };
                adminuserlist.ForEach(adminuser => context.Users.Add(adminuser));
            }
 
            //添加用户
            UserGroup uguser = (from x in context.UserGroup
                                 where x.GroupName == "User"
                                 select x).SingleOrDefault();
            if (uguser != null)
            {
                var userlist = new List<User>() 
                
                    new User()
                    {
                        UserName = "小红",
                        City = "上海",
                        Password = "xiaohong123",
                        Sex = false,
                        Group = uguser
                    },
                    new User()
                    {
                        UserName = "大军",
                        City = "唐山",
                        Password = "123456",
                        Sex = true,
                        Group = uguser
                    },
                    new User()
                    {
                        UserName = "丽丽",
                        City = "沧州",
                        Password = "88888888",
                        Sex = false,
                        Group = uguser
                    }
                };
                userlist.ForEach(user => context.Users.Add(user));
            }
            context.SaveChanges();
        }
    }


大家知道为什么中断了那么就没有往下写么?因为我也在摸索。

我发现导航属性(也就是User.Group和UserGroup.Users)没有办法正确获取数据。仔细检查代码,发现了原因。

切记要将导航属性标记为virtual的。

public virtual UserGroup Group { get; set; }

public virtual IList<User> Users { get; set; }

为了方便起见,我给两个实体类重写了 ToString() 方法。

完整的代码如下:
C# code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
    class User
    {
        [Key]
        public string UserName { getset; }
 
        [Required]
        public string Password { getset; }
 
        public bool Sex { getset; }
        public string City { getset; }
 
        public virtual UserGroup Group { getset; }
 
        public override string ToString()
        {
            return string.Format("用户名:{0}, 城市:{1}, 所属组:{2}, 性别:{3}.",
                UserName, City, Group, Sex == false  "女" "男");
        }
    }
 
    class UserGroup
    {
        public int ID { getset; }
        public string GroupName { getset; }
 
        public virtual IList<User> Users { getset; }
 
        public override string ToString()
        {
            return string.Format("用户组名:{0}.",
                GroupName);
        }
    }


一切就绪,下面正式进行数据库操作。

为了简单起见,所以的操作均硬编码到方法内,没有从键盘输入,除了登录以外。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多