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()]
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.模型要映射到数据库中有三种方式。
前面两种我们前面都已经尝试过,对于第三种,不使用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)可获取的属性
如果想配置私有属性,这样就需要将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()]
[MinLength()]
public string Name { get; set; }
[StringLength(, MinimumLength = )]
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"));
也可以指定为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。
Resorts:
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()]
[MinLength()]
public string Name { get; set; }
[StringLength(, MinimumLength = )]
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最佳。
Programming Entity Framework CodeFirst--数据库约定和配置的更多相关文章
- 【读书笔记】Programming Entity Framework CodeFirst -- 初步认识
以下是书<Programming Entity Framework Code First>的学习整理,主要是一个整体梳理. 一.模型属性映射约定 1.通过 System.Component ...
- Programming Entity Framework CodeFirst -- 约定和属性配置
以下是EF中Data Annotation和 Fluenlt API的不同属性约定的对照. Length Data Annotation MinLength(nn) MaxLength(nn) ...
- Programming Entity Framework CodeFirst--表关系约定
表之间的关系分为一对多,多对多,一对一三种,实质就是对外键进行配置. 一.一对多 1. Required Destination包含Lodging>的集合. public class Desti ...
- entity framework codefirst 用户代码未处理DataException,InnerException基础提供程序在open上失败,数据库生成失败
警告:这是一个入门级日志,如果你很了解CodeFirst,那请绕道 背景:这篇日志记录我使用Entity FrameWork CodeFirst时出现的错误和解决问题的过程,虽然有点曲折……勿喷 备注 ...
- Entity Framework Codefirst的配置步骤
Entity Framework Codefirst的配置步骤: (1) 安装命令: install-package entityframework (2) 创建实体类,注意virtual关键字在导航 ...
- 第三篇:Entity Framework CodeFirst & Model 映射 续篇 EntityFramework Power Tools 工具使用
上一篇 第二篇:Entity Framework CodeFirst & Model 映射 主要介绍以Fluent API来实作EntityFramework CodeFirst,得到了大家一 ...
- 第二篇:Entity Framework CodeFirst & Model 映射
前一篇 第一篇:Entity Framework 简介 我有讲到,ORM 最关键的 Mapping,也提到了最早实现Mapping的技术,就是 特性 + 反射,那Entity Framework 实现 ...
- Entity Framework CodeFirst数据迁移
前言 紧接着前面一篇博文Entity Framework CodeFirst尝试. 我们知道无论是“Database First”还是“Model First”当模型发生改变了都可以通过Visual ...
- entity framework 删除数据库出现错误的解决方法--最土但是很有效的方法
无法删除数据库,因为该数据库当前正在使用. public ChinaerContext() : base("name=ContextConn") { // Database.Set ...
- Programming Entity Framework 翻译(2)-目录2-章节
How This Book Is Organized 本书组织结构 Programming Entity Framework, Second Edition, focuses on two ways ...
随机推荐
- ListView13添加2
Columns=//添加列总行的标题 GridLines=true //显示网格线 添加数据------------- listView1.Items.Add("123123123" ...
- 建站阿里云、amh主机面版
阿里云 Nginx+tomcat7+Mencached负载均衡集群配置 http://blog.csdn.net/zht666/article/details/38515147 apache2.2.1 ...
- php-4种排序
<?php$arr = array(1, 43, 54, 62, 21, 66, 32, 78, 36, 76, 39); //1. 冒泡排序 //在要排序的一组数中,对当前还未排好的序列,从前 ...
- cannot determine the location of the vs common tools folder
问题:打开"VS2010开发人员命令提示后",上面提示"cannot determine the location of the vs common tools fold ...
- kali linux 、 windows、ubuntu三系统的引导问题
'小飞机'是一个学生,所以接触的东西,虽广泛,但并不精通,在此利用随笔,记录自己的一些学习过程,以及自己的想法,既可以有时间自己复习,也可以顺便帮助别人. 近期由于同学的引诱以及男生天生对于破解的好奇 ...
- STM32 DAC的配置与使用
本博文转自:http://blog.chinaunix.net/uid-24219701-id-4101802.html STM32 的 DAC 模块(数字/模拟转换模块)是 12 位数字输入,电压输 ...
- ExtJS入门实例
一.去官网下载EXTJS包extjs5,这里采用的是5.0版本! 二.解压extjs包,找到 ext-all.js基础包(\ext-5.0.0\build): ext-all-debug.js基础包, ...
- FibonacciSequence
import java.util.Scanner; public class Fibonacci { public static void main(String[] args) { int n; f ...
- VMware 12 的vmware tools安装和如何使用(系统是CENTOS6.5)
1.用了一下虚拟机vmware12,但是总是没法使用它的vmware Tool ,网上一直说在哪个哪个文件夹,其实并没有 2.于是我用命令行找到了在系统中的VMware Tools 3.首先,保证li ...
- 无法打开注册表项 unknown 没有足够的权限访问
secedit /configure /cfg %windir%\inf\defltbase.inf /db defltbase.sdb /verbose 执行完,重新安装即可.