Programming Entity Framework CodeFirst--数据库约定和配置

这一章主要主要讲的是我们的模型如何映射到数据库,而不影响模型,以及不同的映射场景。

一、表名和列名

1.指定表名

[Table("PersonPhotos")]
public class PersonPhoto

[Table("Locations", Schema="baga")]
public class Destination

Schema修改数据库架构,默认是dbo。

API:

modelBuilder.Entity<Destination>().ToTable("Locations", "baga");

2.列名

[Column("LocationID")]
public int DestinationId { get; set; }
[Required, Column("LocationName")]
public string Name { get; set; }

API:

Property(d => d.Nam
.IsRequired().HasColumnName("LocationName");
Property(d => d.DestinationId).HasColumnName("LocationID");

二、表分割

将一个模型拆成两张表,比如Destination。

public class Destination
    {
        [Key]
        public int DestinationId { get; set; }
        [Required]
        public string Name { get; set; }
        public string Country { get; set; }
        [MaxLength(500)]
        public string Description { get; set; }
        [Column(TypeName = "image")]
        public byte[] Photo { get; set; }
        public List<Lodging> Lodgings { get; set; }
    }

API:(DataAnnotations不能处理子对象)

 modelBuilder.Entity<Destination>()
                .Map(m =>
                {
                    m.Properties(d => new {d.Name, d.Country, d.Description});
                    m.ToTable("Locations");
                })
                .Map(m =>
                {
                    m.Properties(d => new {d.Photo});
                    m.ToTable("LocationPhotos");
                });

运行后,Destination 拆分成了Locations和LocationPhotos

当Destination添加数据的时候,这个两个表的主键都会增加。

  

三、数据库映射控制

1.模型要映射到数据库中有三种方式。

1).将对象加入到Dbset中。

2).在别的类型中,引用当前类型。(Person包含PersonPhoto,PersonPhoto是不需要加人Dbset的。)

3).通过API在DbModelBuilder方法中配置。

前面两种我们前面都已经尝试过,对于第三种,不使用Dbset 就需要使用EntityTypeConfiguration。 可以建立一个空的:

public class ReservationConfiguration :EntityTypeConfiguration<Reservation>
{}

再加入modelBuider

modelBuilder.Configurations.Add(new ReservationConfiguration());

2.忽略类型映射。

如果不想数据库映射某个类型,我们可以将其忽略掉。

[NotMapped]
public class MyInMemoryOnlyClass
//API:
modelBuilder.Ignore<MyInMemoryOnlyClass>();

3.属性映射类型

1)只能是EDM支持的类型。

Binary, Boolean, Byte, DateTime, DateTimeOffset, Decimal, Double, Guid, Int16, Int32, Int64, SByte, Single, String, Time

枚举类型现在已经支持了。MyType是个枚举类型,Flag是Uint型,不支持EF就自动忽略了。

2)可获取的属性

.Public属性会自动映射。

.Setter可以是限制访问,但Getter必须是Public。

.如果想非Public的属性也映射,就需要通过API来配置。

如果想配置私有属性,这样就需要将Config类置于内部。如下,Name是private的,PersonConfig想要获取这个类型就需要置于Person内部了:

public class Person
{
public int PersonId { get; set; }
private string Name { get; set; }
public class PersonConfig : EntityTypeConfiguration<Person>
{
public PersonConfig()
{
Property(b => b.Name);
}
}
public string GetName()
{
return this.Name;
}
public static Person CreatePerson(string name)
{
return new Person { Name = name };
}
}

3)属性忽略

.没有setter

如果People包含FullName属性,EF是不会映射这个属性的。

public string FullName
{
get { return String.Format("{0} {1}", FirstName.Trim(), LastName); }
}

.直接忽略

 [NotMapped]
 public string TodayForecast{get;set;}
 //API:
Ignore(d => d.TodayForecast);

四、继承类型映射

1)默认继承 Table Per Hierarchy (TPH)  子类父类在一张表中。

public class Lodging
    {
        public int LodgingId { get; set; }
        [Required]
        [MaxLength(200)]
        [MinLength(10)]
        public string Name { get; set; }
        [StringLength(200, MinimumLength = 2)]
        public string Owner { get; set; }
        public bool IsResort { get; set; }
        public Destination Destination { get; set; }
        public int DestinationId { get; set; }
        public List<InternetSpecial> InternetSpecials { get; set; }
        [InverseProperty("PrimaryContactFor")]
        public Person PrimaryContact { get; set; }
        [InverseProperty("SecondaryContactFor")]
        public Person SecondaryContact { get; set; }

    }

    public class Resort : Lodging
    {
        public string Entertainment { get; set; }
        public string Activities { get; set; }
    }

没有创建Resort表,而是Lodgings表中多了Restort的字段

而且还多了个Discriminator (辨别者)列,nvarchar(128) ,专门用来识别是哪个类型,插入2组数据。

  private static void InsertLodging()
        {
            var lodging = new Lodging
            {
                Name = "Rainy Day Motel",
                Destination = new Destination
                {
                    Name = "Seattle, Washington",
                    Country = "USA"
                }
            };
            using (var context = new BreakAwayContext())
            {
                context.Lodgings.Add(lodging);
                context.SaveChanges();
            }
        }
    private static void InsertResort()
        {
            var resort = new Resort
            {
                Name = "Top Notch Resort and Spa",
                Activities = "Spa, Hiking, Skiing, Ballooning",
                Destination = new Destination
                {
                    Name = "Stowe, Vermont",
                    Country = "USA"
                }
            };
            using (var context = new BreakAwayContext())
            {
                context.Lodgings.Add(resort); //没有去添加Dbset<Resort>
                context.SaveChanges();
            }
        }

同样我们可以定义discriminator的列名和类型的值。

 modelBuilder.Entity<Lodging>()
                .Map(m =>
                {
                    m.ToTable("Lodgings");
                    m.Requires("LodgingType").HasValue("Standard");
                })
                .Map<Resort>(m => m.Requires("LodgingType").HasValue("Resort"));

这里Requires和Hasvalue都是来定义discriminator 列的。

再次运行,列名和类型值也都已经改变。

也可以指定为bool类型。将这个任务交给IsResort

modelBuilder.Entity<Lodging>()
                .Map(m =>
                {
                    m.ToTable("Lodgings");
                    m.Requires("IsResort").HasValue(false);
                })
                .Map<Resort>(m => m.Requires("IsResort").HasValue(true));

要注意的是Lodging模型中不能再包含IsResort属性,在模型验证的时候就出错,EF它分不清这个IsResort和识别类型IsResort是不是同一个。不然会引发异常。

2)Table Per Type (TPT) Hierarchy (分开存储,派生类只存储自己独有的属性)

给派生类加上表名就是TPT了。

[Table("Resorts")]
public class Resort : Lodging
{
public string Entertainment { get; set; }
public string Activities { get; set; }
}

这样EF会创建一个新表,并拥有Lodging的key。

是插入两条数据:

Lodgings

Resorts:

API:

modelBuilder.Entity<Lodging>()
.Map<Resort>(m =>
{
m.ToTable("Resorts");
}
);

可以写在一起。

modelBuilder.Entity<Lodging>().Map(m =>
{
m.ToTable("Lodgings");
}).Map<Resort>(m =>
{
m.ToTable("Resorts");
});

3)Table Per Concrete Type (TPC) Inheritance  父类和派生各自拥有全部属性

好比Resorts作为一个表拥有所有的属性。只能通过API的MapInheritedProperties来实现。且ToTable方法不能少。

modelBuilder.Entity<Lodging>()
.Map(m =>
{
m.ToTable("Lodgings");
})
.Map<Resort>(m =>
{
m.ToTable("Resorts");
m.MapInheritedProperties();
});

这个时候运行会出错:

TPC要求使用TPC的类如果被引用必须有一个显示的外键属性。就像Lodging中的DestinationId对于Destination

public class Lodging
    {
        public int LodgingId { get; set; }
        [Required]
        [MaxLength(200)]
        [MinLength(10)]
        public string Name { get; set; }
        [StringLength(200, MinimumLength = 2)]
        public string Owner { get; set; }
        // public bool IsResort { get; set; }
         public Destination Destination { get; set; }
        public int DestinationId { get; set; }
        public List<InternetSpecial> InternetSpecials { get; set; }
         public Person PrimaryContact { get; set; }
        public Person SecondaryContact { get; set; }
    }

这里的PrimaryContact 和 SecondaryContact 没有指明外键。需要强制给它加上外键。这里会让有的人难受,因为EF的规则而去要改变自己的领域模型。

public class Lodging
    {
      //.....
        public int? PrimaryContactId { get; set; }
        public Person PrimaryContact { get; set; }
        public int? SecondaryContactId { get; set; }
        public Person SecondaryContact { get; set; }
    }

这个时候还没完,EF并不清楚这些外键。需要再配置。

 modelBuilder.Entity<Lodging>()
                .Map(m => m.ToTable("Lodgings"))
                .Map<Resort>(m =>
                {
                    m.ToTable("Resorts");
                    m.MapInheritedProperties();
                });
 modelBuilder.Entity<Lodging>().HasOptional(l => l.PrimaryContact)
.WithMany(p => p.PrimaryContactFor)
.HasForeignKey(p => p.PrimaryContactId);
            modelBuilder.Entity<Lodging>().HasOptional(l => l.SecondaryContact)
.WithMany(p => p.SecondaryContactFor)
.HasForeignKey(p => p.SecondaryContactId);

生成的表如下。都带有三个外键。

对于基类是抽象类型,对EF来说没有多大的区别。至于这三种该怎么用。这里有博客:http://blogs.msdn.com/b/alexj/archive/2009/04/15/tip-12-choosing-an-inheritance-strategy.aspx

各种表现上面还是TPT最佳。

时间: 2024-10-10 04:50:20

Programming Entity Framework CodeFirst--数据库约定和配置的相关文章

Programming Entity Framework CodeFirst -- 约定和属性配置

以下是EF中Data Annotation和 Fluenlt API的不同属性约定的对照. Length Data Annotation MinLength(nn) MaxLength(nn) StringLength(nn) Fluent Entity<T>.Property(t=>t.PropertyName).HasMaxLength(nn) 在SQL Server中,string会转换为nvarchar(max),bit会转换为varbinary(max) 如果是SQL CE这里

Programming Entity Framework CodeFirst--表关系约定

表之间的关系分为一对多,多对都,一对一三种,实质就是对外键进行配置. 一.一对多 1. Required Destination包含Lodging>的集合. public class Destination { public int DestinationId { get; set; } public string Name { get; set; } public string Country { get; set; } public string Description { get; set

第二篇:Entity Framework CodeFirst &amp; Model 映射

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 前一篇 第一篇:Entity Framework 简介 我有讲到,ORM 最关键的 Mapping,也提到了最早实现Mapping的技术,就是 特性 + 反射,那Entity Framework 实现Mapping 又是怎样的呢? Entity

第三篇:Entity Framework CodeFirst &amp; Model 映射 续篇 EntityFramework Power Tools 工具使用

上一篇 第二篇:Entity Framework CodeFirst & Model 映射 主要介绍以Fluent API来实作EntityFramework CodeFirst,得到了大家一些支持,其中就有一位同学就提出.熟悉了EntityFramework CodeFirst 原理,就可以用微软的工具来生产代码.是的,今天就来讲一下,由微软EntityFramework小组开发的为EntityFramework CodeFirst Visual Studio小插件 “Entity Frame

[Programming Entity Framework] 第3章 查询实体数据模型(EDM)(一)

http://www.cnblogs.com/sansi/archive/2012/10/18/2729337.html Programming Entity Framework 第二版翻译索引 你可以使用各种方法查询实体数据模型.你选择有些方法是因为个人喜好,而其它的则是因为你可以利用特殊的效益.你很有可能已经听过LINQ to Entities和Entity SQL.你可以使用特殊的方法去查询,比如某些基于LINQ,而其它的基于EF的ObjectQuery类.这此查询方法中的每一个都会产生具

Entity Framework Code-First(20):Migration

Migration in Code-First: Entity framework Code-First had different database initialization strategies prior to EF 4.3 like CreateDatabaseIfNotExists, DropCreateDatabaseIfModelChanges, or DropCreateDatabaseAlways. However, there were some problems wit

ASP.NET MVC+Entity Framework 访问数据库

Entity Framework 4.1支持代码优先(code first)编程模式:即可以先创建模型类,然后通过配置在EF4.1下动态生成数据库. 下面演示两种情形: 1.代码优先模式下,asp.net mvc数据访问 2.传统模式,先创建数据库和表,配置连接字符串,再生成模型 第一种情况的步骤: (1)使用空模板,创建ASP.NET MVC3.0(或4.0)项目,假定项目名:MVC_Student 注意:创建完项目后,项目会自动引用EF4.1 (2)在Model文件夹下,创建数据库上下文类:

Entity Framework Code-First(23):Entity Framework Power Tools

Entity Framework Power Tools: Entity Framework Power Tools (currently in beta 3) has been released. EF Power Tools is useful mainly in reverse engineering and generating read-only entity data model for code-first. Download and install Power Tools fro

Entity Framework Code-First(21):Automated Migration

Automated Migration: Entity framework 4.3 has introduced Automated Migration so that you don't have to process database migration manually in the code file, for each change you make in your domain classes. You just need to run a command in Package Ma