码迷,mamicode.com
首页 > Web开发 > 详细

.NET - EntityFramework 实体关系数据模型

时间:2017-08-23 10:17:59      阅读:271      评论:0      收藏:0      [点我收藏+]

标签:class   空值   bit   not   设置   tip   环境   nvarchar   fluent   

EntityFramework 实体关系数据模型(DO.NET Entity Framework)

ADO.NET Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对应 (O/R Mapping) 解决方案。该框架曾经为.NET Framework的一部分,但version 6之后从.NET Framework分离出来。

 

在项目中使用Entity Framework

要得到最高版本的Entity Framework 程序包,可以通过扩展与更新或者右击项目-引用-管理NuGet程序包。

技术分享技术分享

 

创建Entity实体关系模型

右击项目 - 添加 - 数据 - ADO.NET实体数据模型

技术分享

来自数据库的EF设计器:通过已经事先创建的数据库和表,EF框架自动根据数据库生成表实体。

空EF设计器模型:通过EF设计器的可视化界面设计实体关系图,EF框架自动根据关系图生成数据库、表和对应的实体类。

Code First模型:通过全手工创建实体,运行代码后自定生成数据库和表。

添加完成后在项目中会包含一个后缀为edmx文件,此文件描述模型的架构。这三个文件分别是模型的XML表示,数据库构架的XML表示、映射表与实体的关系的XML表示。

xxx.context.tt(数据库操作上下文)

xxx.tt(实体模型)

 

Code First模式

DbContext类(System.Data.Entity.DbContext)

这是一个操作实体的上下文对象,它比ObjectContex更轻量级,推荐使用DbContext。DbContext内部维护了数据库连接、管理实体数据、生成数据库操作语句、将数据持久化到数据库。它包含所有的实体对象的集合(可查询数据集),通过它的泛型集合属性DbSet<T>存储这些数据集。你所创建的类是如何成为Entity实体的呢?很简单,完成以下三步:

1.创建一个类库,命名为DataAccess,用以表示数据访问层,创建一个BreakAwayContext的类,使其从DbContext派生。键入以下代码:   

技术分享
using System.Data.Entity;
using Model;

namespace DataAcess
{
    public class BreakAwayContext : DbContext
    {
        public BreakAwayContext ( ) : base ( "name=DBConnection" ) { } //name=配置文件中的数据库连接字符串的名称
        public DbSet<Destination> Destinations { getset; } //你创建的实体类Destination,实体代表了一张表,此处通过DbSet泛型集合表示该表的所有记录
        public DbSet<Lodging> Lodgings { getset; } //你创建的实体类Lodging,实体代表了一张表,此处通过DbSet泛型集合表示该表的所有记录

        //使用此静态构造函数指定数据库的初始化方式,无论如何请先关闭打开的数据库、关闭vs中的服务器资源管理器中的数据库连接,否则以下任务不会完成
        static BreakAwayContext ( )
        {
            Database.SetInitializer ( new CreateDatabaseIfNotExists<BreakAwayContext> ( ) ); //默认,参数可为null,当数据库不存在时,自动创建数据库          
            Database.SetInitializer ( new DropCreateDatabaseAlways<BreakAwayContext> ( ) ); //无论怎样,删除同名数据库,再重新创建
            Database.SetInitializer ( new DropCreateDatabaseIfModelChanges<BreakAwayContext> ( ) ); //如果实体模型发生改变,则先删除同名数据库,再重新创建
        }
    }
}
DataAccess

2.创建一个类库,命名为Model,用以表示实体层,创建两个实体类:Destination和Lodging。前者表示旅行的目的地,后者表示住宿。键入以下代码:  

技术分享
namespace Model
{
    /// <summary>
    /// 目的地
    /// </summary>
    public class Destination
    {
        public int DestinationId { getset; }
        public string Name { getset; }
        public string Country { getset; }
        public string Description { getset; }
        public byte [ ] Photo { getset; }
        //Lodgings集合是Lodging类,该表会被识别为外键表,因为这表示了一个Destination(目的地)对应多个Lodgings(住宿)的关系。
        public List<Lodging> Lodgings { getset; }
    }
}
Destination
技术分享
namespace Model
{
    /// <summary>
    /// 住宿
    /// </summary>
    public class Lodging
    {
        public int LodgingId { getset; }
        public string Name { getset; }
        public string Owner { getset; }
        public bool IsResort { getset; }
        //作为外键引用了Destination表的主键,此处可以写成public Destination Destination,效果是一样的,都会被识别为对Destination表的主键的引用
        public int DestinationId { getset; }
    }
}
Lodging

3.创建一个控制台应用程序,命名为BreakAwayConsole,用以表示显示层。添加对Entity framework的引用,这样会自动在App.config中生成默认的数据库配置信息节点:<entityFramework>,将其全部删除,再添加一个ConnectionString,configSections好像必须是configuration的第一个配置节,所以ConnectionString配置节只能放在configSections后面。

技术分享
<?xml version="1.0" encoding="utf-8"?>
<configuration>
          <connectionStrings>
                    <add name="DBConnection" 
                            connectionString="Data Source=(local); Database=stuEntity; User ID=sa; Password=123456; MultipleActiveResultSets=True" 
                            providerName="System.Data.SqlClient" />
          </connectionStrings>
</configuration>
app.config

4.添加DataAccess对Model的引用,添加BreakAwayConsole对DataAccess和Model的引用后,在控制台中创建一条记录并插入数据库,此时DbContext会自动为你创建数据库和表。

技术分享
using DataAccess;
using Model;

namespace BreakAwayConsole
{
    class Program
    {
        static void Main ( string [ ] args )
        {
            var destination = new Destination ( )
            {
                Country = "美国" ,
                Description = "风城" ,
                Name = "芝加哥"
            };
            using ( var context = new BreakAwayContext ( ) )
            {
                context.Destinations.Add ( destination );
                context.SaveChanges ( );
            }
        }
    }
}
控制台.program

ctrl+F5运行程序,等待片刻数据库就创建完毕了。 

技术分享

字段属性映射的默认约定

属性与主键约定:Id或类名Id将默认自动映射为主键。

属性与字符约定:字符类型的属性默认自动映射为nvarchar(max) null。

属性与bool约定:布尔值类型的属性默认自动映射为bit

属性与byte数组约定:byte数组类型的属性默认自动映射为varbinary ( max)

集合属性与主外键约定:泛型集合中的类会被视为外键表,外键表总是有一个外键引用了当前具有泛型集合的类,外键可以是一个int也可以直接是它所引用的类类型。如下:

public int DestinationId { getset; }
public Destination Destination { getset; }

配置实体字段属性

有两种方式可为字段增加描述性配置,Data Annotations和Fluent API,前者使用简单,后者提供更强大的清洁的配置。(如果不喜欢到处贴标签) 

1.Data Annotations配置(System.ComponentModel.DataAnnotations)  

技术分享
[Table ( "Animal" )] 
//将类映射为Animal表
[Key]
//主键,且种子增量每次+1,即自动增长,增量为1
[Key, DatabaseGenerated ( System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity )]
//如果主键类型是Guid,则必须配置此特性,否则不会自动生成唯一标识
[Required]
//不允许空值
[MaxLength ( 255 )]
//最大长度
[MinLength ( 10 )]
//最小长度
[Timestamp]
//并发时间戳,为开放式并发环境配置时间戳。一个实体只能有一个byte [ ] 类型的属性可设置此特性,Sql Server称其为TimeStamp(时间戳),其他数据库称其为RowVersion(行版本)
[ConcurrencyCheck]
//并发非时间戳,当并发冲突发生时,这将为并发提供检查确保不会发生异常。对应的字段类似:public int SocialSecurityNumber { get; set; }
配置实体字段属性

2.Fluent API配置 (System.Data.Entity.ModelConfiguration和System.Data.Entity)

System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<T>泛型类用以配置实体的属性,将其映射为数据库表字段的特性。为此,你应该创建一个表示为实体类增加配置的类,接着通过在构造函数中初始化这些配置信息。然后重写DbContext的OnModelCreating()方法,该方法会在创建表之前将配置信息应用到数据库,所以将每一个实体类的配置信息注册在modelBuilder.Configurations集合中即可。
技术分享
ToTable ( tableNameString)
//设置映射为数据库的表名
HasKey ( lambda)
//主键,且种子增量每次+1,即自动增长,增量为1
HasPrecision ( n1, n2)
//为decimal类型的属性保留有效位数和小数位数,n1为有效位数,n2为小数位数
Property ( lambda).HasDatabaseGeneratedOption ( System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity )
//如果主键类型是Guid,则必须配置此项,否则不会自动生成唯一标识
Property ( lambda).IsRequired ( )
//允许空
Property ( lambda).HasMaxLength ( )
//字符长度
Property ( lambda).HasColumnType ( "image" )
//列类型为二进制图像数据
Property ( lambda).IsRowVersion ( )
//并发时间戳,为开放式并发环境配置时间戳。一个实体只能有一个byte [ ] 类型的属性可设置此特性,Sql Server称其为TimeStamp(时间戳),其他数据库称其为RowVersion(行版本)
Property ( lambda).IsConcurrencyToken ( )
//并发非时间戳,当并发冲突发生时,这将为并发提供检查,确保不会发生异常。对应的属性字段的类型为int
配置实体字段属性
技术分享
using System.Data.Entity.ModelConfiguration;
using System.Data.Entity;
using Model;

namespace DataAcess
{
    //Destination表的列配置
    public class DestinationConfiguration : EntityTypeConfiguration<Destination>
    {
        public DestinationConfiguration ( )
        {
            ToTable ( "Destination" ); 
            HasKey ( d => d.DestinationId ); 
            Property ( d => d.Name ).HasMaxLength ( 255 ).IsRequired(); 
            Property ( d => d.Description ).HasMaxLength ( 255 ).IsRequired ( ); 
            Property ( d => d.Photo ).HasColumnType ( "image" );
        }
    }

    //Lodging表的列配置
    public class LodgingConfiguration : EntityTypeConfiguration<Lodging>
    {
        public LodgingConfiguration ( )
        {
            //……
        }
    }
    public class BreakAwayContext : DbContext
    {
        //使用此静态构造函数指定数据库的初始化方式,无论如何请先关闭数据库,否则以下任务不会完成
        static BreakAwayContext ( )
        {
            Database.SetInitializer ( new CreateDatabaseIfNotExists<BreakAwayContext> ( ) ); //默认,参数可为null,当数据库不存在时,自动创建数据库          
            Database.SetInitializer ( new DropCreateDatabaseAlways<BreakAwayContext> ( ) ); //无论怎样,删除同名数据库,再重新创建
            Database.SetInitializer ( new DropCreateDatabaseIfModelChanges<BreakAwayContext> ( ) ); //如果实体模型发生改变,则先删除同名数据库,再重新创建
        }

        public BreakAwayContext ( ) : base ( "name=DBConnection" ) { } //name=配置文件中的数据库连接字符串的名称
        public DbSet<Destination> Destinations { getset; } //你创建的实体类Destination,实体代表了一张表,此处通过DbSet泛型集合表示该表的所有记录
        public DbSet<Lodging> Lodgings { getset; } //你创建的实体类Lodging,实体代表了一张表,此处通过DbSet泛型集合表示该表的所有记录

        //实体被映射为表之前OnModelCreating会被运行,这将进行列配置检查并应用列配置
        protected override void OnModelCreating ( DbModelBuilder modelBuilder )
        {
            modelBuilder.Configurations.Add ( new DestinationConfiguration ( ) ); //注册Destination表的列配置
            modelBuilder.Configurations.Add ( new LodgingConfiguration ( ) ); //注册Lodging表的列配置
        }
    }
}
示例

实体关系的默认约定

假设有X和Y两个类。  

技术分享
//一对一:两个类分别包含对方的一个引用
namespace Model
{
    public class X
    {
        public int XId { getset; } //主键
        public Y y { getset; } //引用Y
    }

    public class Y
    {
        public int YId { getset; } //主键
        public X x { getset; } //引用X
    }
}
一对一
技术分享
// 一对多:两个类中分别包含一个集合属性和一个引用
namespace Model
{
    public class X
    {
        public int XId { getset; } //主键
        public List<Y> Ys { getset; } //一对多,一个X对多个Y 
    }

    public class Y
    {
        public int YId { getset; } //主键
        public X x { getset; } // 作为外键引用X 
    }
}
一对多
技术分享
//多对多:两个类分别包含对方的一个集合属性
namespace Model
{
    public class X
    {
        public int XId { getset; } //主键
        public List<Y> Ys { getset; } 
    }

    public class Y
    {
        public int YId { getset; } //主键
        public List<X> Xs { getset; } 
    }
}
多对多

 配置实体关系 

技术分享
HasRequired ( lambdaForForeignKey )
//设置当前表的哪个字段为必须的外键,该字段不可以为null
HasOptional( lambdaForForeignKey )
//设置当前表的哪个字段为不必须的外键,该字段可以为null
//示例:
//通常情况下应在外键表写关系 
HasRequired ( b => b.User );//当前表的哪个字段作为必须的外键并且是不可以为null的
HasOptional ( b => b.User ); //当前表的哪个字段作为不必须的外键并且是可以为null的
HasRequired ( b => b.User ).WithMany ( ); //当前表的哪个字段作为必须的外键并且是不可以为null的(HasRequired),该外键表对主键表的引用也可以是多个外键引用同一个主键(WithMany)
配置实体关系

 示例 

技术分享
//Lodging表的列配置
public class LodgingConfiguration : EntityTypeConfiguration<Lodging>
{
    public LodgingConfiguration ( )
    {
        HasRequired ( l=>l.Destination ); //外键不可以为null
        Property ( l=>l.Name ).HasMaxLength ( 20 ).IsRequired ( ); //可空字段
    }
}
示例

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

.NET - EntityFramework 实体关系数据模型

标签:class   空值   bit   not   设置   tip   环境   nvarchar   fluent   

原文地址:http://www.cnblogs.com/myrocknroll/p/7392360.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!