问题:

    从现有数据库生成模型。

解决方案:

    数据库关系图如下所示:

wKiom1ZbrcrhY27NAAFEdfj2tLk211.png    

如图所示:Poem(诗)同Poet(诗人)和Meter(韵律)之间是一个多对一的关系。另外数据库中还有一个视图用以连接这些表使其更方便的显示数据。

    如果在你的数据库中还未建立上图中的表和视图,请在数据库中执行以下代码:

use [EF6Recipes]
go

create table Chapter2.Meter(
MeterId int primary key identity,
MeterName varchar(50) not null);

create table Chapter2.Poet(
PoetId int primary key identity,
FirstName varchar(20) not null,
MiddleName varchar(20),
LastName varchar(20) not null);

create table Chapter2.Poem(
PoemId int primary key identity,
Title varchar(100) not null,
PoetId int foreign key references Chapter2.Poet(PoetId),
MeterId int foreign key references Chapter2.Meter(MeterId));
go

create view Chapter2.vwLibrary as
select ta.FirstName,ta.MiddleName,ta.LastName,tb.Title,tc.MeterName
from Chapter2.Poet as ta inner join Chapter2.Poem as tb on tb.PoetId=ta.PoetId
	inner join Chapter2.Meter as tc on tb.MeterId=tc.MeterId


    导入数据库的视图、表及关系的步骤如下:

    1、在项目中新建一个ADO.NET 视图数据模型:右击项目,选择添加->新建项,在弹出的窗口中依次选择已安装->Visual C#项->数据,选择ADO.NET 视图数据模型。修改模型默认名称为Recipe2。点击添加。

    2、在实体数据模型向导中,选择模型内容为来自数据库的EF设计器,点击下一步。

    3、选择数据连接。因为我们在前一节已经产生了一个数据连接,直接点击下一步。也可以把将App.config中的连接设置另存为:的值进行修改或取消前面的复选框。

    4、选择EF版本为6.x。

    5、在选择您的数据库对象和设置窗口,按下图所示进行设置。

wKioL1ZbusGxkJIXAACyLV69R0s093.png

    选择Meter、Poem、Poet3张表和vmLibrary视图。确保2个复选框被勾选。点击完成。

    这里会出现一个警告:错误 6002: 表/视图“EF6Recipes.Chapter2.vwLibrary”未定义主键。已推断出该键,并将定义创建为只读的表/视图。EF根据视图相关表的NOT NULL属性推断视图实体的主键,如果这里视图相关的表的字段都是NULL的话,这视图实体生成将失败。如果真的遇到这种情况的话,可以参照http://tancfeng.blog.51cto.com/4079342/1718151进行修改。最后EF设计器将被打开,如图:

wKiom1Zb6wHS3M2aAARBZbcHi0g377.png

    一般来说,数据库视图时不允许进行insert\delete\update操作的,(如果针对一张表的视图则根据具体情况有可能进行CRUD操作)。但在EF中视图实体只能是只读的,如果需要对视图实体进行其他操作,可以采用存储过程进行。

原理:

    在生成的实体数据模型中,我们注意到这些实体既有标量属性也有导航属性。标量属性映射到数据库表的列,导航属性源自表之间的关系。

    在数据库图表中,诗(poem)有1个诗人(poet)并属于一个韵律(meter)。这被表现为Meter和Poet导航属性。如果存在一个Poem实体的实例,则Poet导航属性将保存一个Poet实体的实例,Meter导航属性保存一个Meter实体的实例。

    一个诗人(Poet)可以是任意多首诗(Poem)的作者。Poems导航属性是一个包含Poem实体实例的集合,当然集合可能为空。对于Meter实体,Poems导航属性也是一个集合,表示所有属于给定韵律的诗。SQL Server不支持视图间的关系,所以在EDM中的视图实体的导航属性为空。

    当然,我们也注意到导入向导是相当智能的,所有的集合类的导航属性都被标记为复数。甚至我们实体的实体集名称也被标记为复数形式。当然这也不是一定的,还记得person实体集的名称是people么?这些都是因为我们在选择您的数据库对象和设置界面中勾选了确定所生成对象的单复数形式。该界面中另外一个选项在模型中包括外键列选项的勾选,促使在实体中也包含了外键。虽然有时候外键列同导航属性看起来有点重复,不过外键列也有其自身优势,可以运用于特定场景。

    以下代码将演示如何生成3个实体的实例并将其保存到数据库中,并查询模型从数据库中获取数据。在此之前我们需要重命名EDM的实体容器名称为:EF6RecipesContext;并将数据库架构改为:Chapter2;

    1、方便起见,直接在Main方法中编写代码.

            using (var context = new EF6RecipesContext())
            {
                var poet = new Poet { FirstName = "John", LastName = "Milton" };
                var poem = new Poem { Title = "Paradise Lost" };
                var meter = new Meter { MeterName = "Iambic Pentameter" };
                poem.Meter = meter;
                poem.Poet = poet;
                context.Poems.Add(poem);

                poem = new Poem { Title = "Paradise Regained" };
                poem.Meter = meter;
                poem.Poet = poet;
                context.Poems.Add(poem);

                poet = new Poet { FirstName = "Lewis", LastName = "Carroll" };
                poem = new Poem { Title = "The Hunting of the Shark" };
                meter = new Meter { MeterName = "Anapestic Tetrameter" };
                poem.Meter = meter;
                poem.Poet = poet;
                context.Poems.Add(poem);

                poet = new Poet { FirstName = "Lord", LastName = "Byron" };
                poem = new Poem { Title = "Don Juan" };
                poem.Meter = meter;
                poem.Poet = poet;
                context.Poems.Add(poem);

                context.SaveChanges();
            }

            using (var context=new EF6RecipesContext())
            {
                Console.WriteLine("Output by normal entities:");
                var poets = context.Poets;
                foreach (var poet in poets)
                {
                    Console.WriteLine("{0} {1}", poet.FirstName, poet.LastName);
                    foreach (var poem in poet.Poems)
                    {
                        Console.WriteLine("\t{0} ({1})", poem.Title, poem.Meter.MeterName);
                    }
                }
                
            }

            // using our vwLibrary view
            using (var context = new EF6RecipesContext())
            {
                Console.WriteLine("Output using view entity:");
                var items = context.vwLibraries;
                foreach (var item in items)
                {
                    Console.WriteLine("{0} {1}", item.FirstName, item.LastName);
                    Console.WriteLine("\t{0} ({1})", item.Title, item.MeterName);
                }
            }
            Console.ReadLine();

    执行结果如下:

wKioL1Zb-ifySvDWAAAfW2AagBY562.png