Asp.net core中Migration工具使用的交流分享
a,ul>li,em{
color:deeppink !important;
}
h2>a{
text-decoration:none;
}
ul>li{
padding:3px;
}
ul{
width:512px;
}
li>p{
color:#333;
margin:0 !important;
}
hr{
border-color:deeppink;
}
em{
font-style:normal;
}
.passage{
text-indent:2em;
font-size:18px;
}
-->
一、文章参数
二、开篇碎语
三、主要内容
四、篇后总结
一、文章参数
- 开发工具:
visual studio 2015 community update 3 + .net core tools(preview2) + sqlserver2012 express
- 开发环境:
win10(版本14393)+ .net core(版本 1.0.0-preview2-003121)
- 项目名称:
AirMusic
- 项目模板:
Asp.net core WebApi(这里不用mvc模板,是因为mvc模板初始的内容太多,这里用不到)
- AirMusic源码地址:
二、开篇碎语
记得去年第一次做项目,用了asp.net mvc5,因此也第一接触了EntityFramework(版本是EF6)。 现在打算用asp.net core来完成一个项目,air music是学习asp.net core时新建的demo项目,以后学习core中遇到的一些问题一般会从这个项目产生,今天这篇文章是在migration初始化数据库时发生的一些问题。
三、主要内容
1、初始化的实体模型
public class Song
{
public int Id { get; set; }
[Required]
public string SongName { get; set; }
public virtual ICollection<ArtistSong> Artists { get; set; }
public virtual ICollection<SongListSong> SongLists { get; set; }
} //歌手
public class Artist
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Album> Albums { get; set; }
public virtual ICollection<ArtistSong> Songs { get; set; }
} //song with artist n:n table
public class ArtistSong
{
[Key]
public int ArtistId { get; set; }
[Key]
public int SongId { get; set; }
} //专辑
public class Album
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
public virtual ICollection<Song> Songs { get; set; }
} //歌单
public class SongList
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
public string Describe { get; set; }
public virtual ApplicationUser User { get; set; }
public virtual ICollection<SongListSong> Songs { get; set; }
} // song with songlist n:n table
public class SongListSong
{
[Key]
public int SongListId { get; set; }
[Key]
public int SongId { get; set; }
}
Store Models
2、引用EFcoore相关的Nuget包
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0"
(依赖了好多ef重要组件)
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"
(引用了才可以试用migration)
"Microsoft.EntityFrameworkCore.SqlServer": "1.0.0"
(我觉得是ef连接sqlserver的必须组件)
还有就是必须在project.json里的tools节点中添加"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",不然输入命令”Add Migration“时就会报出下面这句错误。
"No parameterless constructor………“这句错误是因为ApplicationDbContext(数据库上下文类)没有写下面这个构造函数报的错误。
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
3、配置数据库连接
Webapi模板已经创建好了appsetting.json文件,这个文件的作用和web.config是一样的
4、文章包袱:Migration过程中遇到的问题
在ApplicationDbContext重写的方法OnModelCreating
中,有一行代码
base.OnModelCreating(builder)
当我把这行代码注释掉时,迁移过程中就会报出如下错误:
很明显,错误发生的原因是IdentityUser没有被映射到ApplicationDbContext,所以可以知道这句代码的作用,就是用来映射Identity的几个实体类的,没有这句,数据库中就不会自动生成Users、Roles……等Table了,我还没有去github看这个方法的源码,但我觉得实际上就是第一次Add-Migration时,生成的源文件ApplicationDbContextModelSnapshot.cs 中的代码:
protected override void BuildModel(ModelBuilder modelBuilder)
{
modelBuilder
.HasAnnotation("ProductVersion", "1.0.0-rtm-21431")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b =>
{
b.Property<string>("Id"); b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken(); b.Property<string>("Name")
.HasAnnotation("MaxLength", ); b.Property<string>("NormalizedName")
.HasAnnotation("MaxLength", ); b.HasKey("Id"); b.HasIndex("NormalizedName")
.HasName("RoleNameIndex"); b.ToTable("AspNetRoles");
}); modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd(); b.Property<string>("ClaimType"); b.Property<string>("ClaimValue"); b.Property<string>("RoleId")
.IsRequired(); b.HasKey("Id"); b.HasIndex("RoleId"); b.ToTable("AspNetRoleClaims");
}); modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser", b =>
{
b.Property<string>("Id"); b.Property<int>("AccessFailedCount"); b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken(); b.Property<string>("Discriminator")
.IsRequired(); b.Property<string>("Email")
.HasAnnotation("MaxLength", ); b.Property<bool>("EmailConfirmed"); b.Property<bool>("LockoutEnabled"); b.Property<DateTimeOffset?>("LockoutEnd"); b.Property<string>("NormalizedEmail")
.HasAnnotation("MaxLength", ); b.Property<string>("NormalizedUserName")
.HasAnnotation("MaxLength", ); b.Property<string>("PasswordHash"); b.Property<string>("PhoneNumber"); b.Property<bool>("PhoneNumberConfirmed"); b.Property<string>("SecurityStamp"); b.Property<bool>("TwoFactorEnabled"); b.Property<string>("UserName")
.IsRequired()
.HasAnnotation("MaxLength", ); b.HasKey("Id"); b.HasIndex("NormalizedEmail")
.HasName("EmailIndex"); b.HasIndex("NormalizedUserName")
.IsUnique()
.HasName("UserNameIndex"); b.ToTable("AspNetUsers"); b.HasDiscriminator<string>("Discriminator").HasValue("IdentityUser");
}); modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd(); b.Property<string>("ClaimType"); b.Property<string>("ClaimValue"); b.Property<string>("UserId")
.IsRequired(); b.HasKey("Id"); b.HasIndex("UserId"); b.ToTable("AspNetUserClaims");
}); modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider"); b.Property<string>("ProviderKey"); b.Property<string>("ProviderDisplayName"); b.Property<string>("UserId")
.IsRequired(); b.HasKey("LoginProvider", "ProviderKey"); b.HasIndex("UserId"); b.ToTable("AspNetUserLogins");
}); modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId"); b.Property<string>("RoleId"); b.HasKey("UserId", "RoleId"); b.HasIndex("RoleId"); b.HasIndex("UserId"); b.ToTable("AspNetUserRoles");
}); modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId"); b.Property<string>("LoginProvider"); b.Property<string>("Name"); b.Property<string>("Value"); b.HasKey("UserId", "LoginProvider", "Name"); b.ToTable("AspNetUserTokens");
}); modelBuilder.Entity("AirMusic.Models.ApplicationUser", b =>
{
b.HasBaseType("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser"); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
.WithMany("Claims")
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
}); modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser")
.WithMany("Claims")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
}); modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser")
.WithMany("Logins")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
}); modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
.WithMany("Users")
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade); b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser")
.WithMany("Roles")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
}
一个让我很困惑的问题在进行第一次Migration时出现了。AirMusic的实体中,有这样一种关系:
但是神奇的事情发生了(我不想这样的):
migrationBuilder.CreateTable(
name: "ArtistSongs",
columns: table => new
{
ArtistId = table.Column<int>(nullable: false),
SongId = table.Column<int>(nullable: false),
//ArtistId1 = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ArtistSongs", x => new { x.ArtistId, x.SongId });
table.ForeignKey(
name: "FK_ArtistSongs_Artists_ArtistId",
column: x => x.ArtistId,
principalTable: "Artists",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
//table.ForeignKey(
// name: "FK_ArtistSongs_Artists_ArtistId1",
// column: x => x.ArtistId1,
// principalTable: "Artists",
// principalColumn: "Id",
// onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_ArtistSongs_Songs_SongId",
column: x => x.SongId,
principalTable: "Songs",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}); migrationBuilder.CreateTable(
name: "SongListSongs",
columns: table => new
{
SongListId = table.Column<int>(nullable: false),
SongId = table.Column<int>(nullable: false),
//SongListId1 = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_SongListSongs", x => new { x.SongListId, x.SongId });
table.ForeignKey(
name: "FK_SongListSongs_Songs_SongId",
column: x => x.SongId,
principalTable: "Songs",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_SongListSongs_SongLists_SongListId",
column: x => x.SongListId,
principalTable: "SongLists",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
//table.ForeignKey(
// name: "FK_SongListSongs_SongLists_SongListId1",
// column: x => x.SongListId1,
// principalTable: "SongLists",
// principalColumn: "Id",
// onDelete: ReferentialAction.Restrict);
});
初次Migration中发生意外的代码(注释的那些)
自动添加了带artist1和songlist1的字段,我很希望知道的朋友告诉我解决的办法!!我实在不知道怎么让EF不自动添加这个多余的字段,所以我把那些多余的字段都注释掉后,才update-database到数据库:
song-artist[N:N] , song-songlist[N:N]
在ApplicationDbContext的OnModelCreating方法里,可以手动的配置数据库中的关系,像什么组合主键啦,组合外键啦等等各种约束,都可以 实现。特别是数据库中实体的关系配置(1:1,1:N,N:N),例如:用方法builder.HasOne().WithMany()就可以建立[1:N]的关系。AirMusic初次Migration中,我也手动的配置了一些关系:
var entityAS=builder.Entity<ArtistSong>();
entityAS.HasKey("ArtistId", "SongId");
entityAS.HasOne<Artist>()
.WithMany()
.HasForeignKey("ArtistId"); var entitySS = builder.Entity<SongListSong>();
entitySS.HasKey("SongListId", "SongId");
entitySS.HasOne<SongList>()
.WithMany()
.HasForeignKey("SongListId");
上面代码的作用是,ArtistId和SongId设为ArtistSong的组合主键,ArtistSong的ArtistId设为Artist的外键。entitySS的作用也大致相同。
四、篇后总结
第一次完整的写一篇博文,晚上去吃饭是电脑自动重启更新了,vscode里的代码都没保存,打开博客园文章管理发现什么都没了,难过的就去听歌睡觉了。第二天起来打算从新来过时,发现有一行“自动保存恢复”,那个感觉就和中了100块的彩票一样。
希望有人看完这篇文章吧,新写手最需要的就是多给建议呀!谢谢
Asp.net core中Migration工具使用的交流分享的更多相关文章
- ASP.NET Core 中文文档 第二章 指南(4.6)Controller 方法与视图
原文:Controller methods and views 作者:Rick Anderson 翻译:谢炀(Kiler) 校对:孟帅洋(书缘) .张仁建(第二年.夏) .许登洋(Seay) .姚阿勇 ...
- 如何在ASP.NET Core中实现一个基础的身份认证
注:本文提到的代码示例下载地址> How to achieve a basic authorization in ASP.NET Core 如何在ASP.NET Core中实现一个基础的身份认证 ...
- 在ASP.NET Core中实现一个Token base的身份认证
注:本文提到的代码示例下载地址> How to achieve a bearer token authentication and authorization in ASP.NET Core 在 ...
- 如何在ASP.NET Core中应用Entity Framework
注:本文提到的代码示例下载地址> How to using Entity Framework DB first in ASP.NET Core 如何在ASP.NET Core中应用Entity ...
- [转]如何在ASP.NET Core中实现一个基础的身份认证
本文转自:http://www.cnblogs.com/onecodeonescript/p/6015512.html 注:本文提到的代码示例下载地址> How to achieve a bas ...
- 在 ASP.NET Core 中集成 Skywalking APM
前言 大家好,今天给大家介绍一下如何在 ASP.NET Core 项目中集成 Skywalking,Skywalking 是 Apache 基金会下面的一个开源 APM 项目,有些同学可能会 APM ...
- ASP.NET Core中使用GraphQL - 第四章 GraphiQL
ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 ASP ...
- ASP.NET Core中使用GraphQL - 第六章 使用EF Core作为持久化仓储
ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 ASP ...
- 在Asp.Net Core中集成Kafka
在我们的业务中,我们通常需要在自己的业务子系统之间相互发送消息,一端去发送消息另一端去消费当前消息,这就涉及到使用消息队列MQ的一些内容,消息队列成熟的框架有多种,这里你可以读这篇文章来了解这些MQ的 ...
随机推荐
- Android学习笔记_40_系统结构 目录结构
1.系统结构: 一.应用程序层 Android平台不仅仅是操作系统,也包含了许多应用程序,诸如SMS短信客户端程序.电话拨号程序.图片浏览器.Web浏览器等应用程序.这些应用程序都是用Java语言编写 ...
- django写一个简单的登陆注册
要写这个,前提还是需要知道三个知识: 一个是urls.py,它是写我们的路由关系的,之前我写了通过wsgiref写一个简单的服务端,也用到了路由,就是 请求过来的url和视图函数的对应关系. 二是就是 ...
- Spring的声明式事务----Annotation注解方式(2)
使用步骤: 步骤一.在spring配置文件中引入<tx:>命名空间<beans xmlns="http://www.springframework.org/schema/b ...
- JS基础——浅谈前端页面渲染和性能优化
加载html中的静态资源 其中,加载静态资源的过程,一般为浏览器根据DNS服务器得到域名的IP地址,然后向这个IP的机器发送http请求,服务器收到.处理并返回http请求,浏览器得到返回http请求 ...
- BZOJ1030: [JSOI2007]文本生成器(AC自动机)
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 5984 Solved: 2523[Submit][Status][Discuss] Descripti ...
- Linux外在设备的使用
参考高峻峰 著 循序渐进Linux(第二版) 软盘在linux下对应的设备文件为/dev/fdx.主设备号fd是软盘驱动器(floppydisk)的缩写,次设备号x是软盘驱动器的相应编号.例如,/de ...
- 二进制部署etcd集群
kuberntes 系统使用 etcd 存储所有数据,本文档介绍部署一个三节点高可用 etcd 集群的步骤,这三个节点配置复用 ,我在这里没有做认证,如果有需要也可以做. 下载二进制文件 到 http ...
- 关于mysql8.0.11版本在win10安装
新的mysql版本没有.exe文件一键安装,网上找了教程,自己搞了下 首先是在菜鸟教程 http://www.runoob.com/mysql/mysql-install.html 根据它的提示下载w ...
- php-5.6.26源代码 - hash存储结构 - 初始化
初始化 有指定析构函数,在销毁hash的时候会调用,如:“类似extension=test.so扩展”也是存放在HashTable中的,“类似extension=test.so扩展”的module_s ...
- x-pack本地安装方式
一.首先下载本地安装包,我使用的ELK是5.6.1版本: https://artifacts.elastic.co/downloads 二.进入到elasticsearch/bin(所有节点)和kib ...