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源码地址:

    https://github.com/boomyao/Blogs

二、开篇碎语

记得去年第一次做项目,用了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工具使用的交流分享的更多相关文章

  1. ASP.NET Core 中文文档 第二章 指南(4.6)Controller 方法与视图

    原文:Controller methods and views 作者:Rick Anderson 翻译:谢炀(Kiler) 校对:孟帅洋(书缘) .张仁建(第二年.夏) .许登洋(Seay) .姚阿勇 ...

  2. 如何在ASP.NET Core中实现一个基础的身份认证

    注:本文提到的代码示例下载地址> How to achieve a basic authorization in ASP.NET Core 如何在ASP.NET Core中实现一个基础的身份认证 ...

  3. 在ASP.NET Core中实现一个Token base的身份认证

    注:本文提到的代码示例下载地址> How to achieve a bearer token authentication and authorization in ASP.NET Core 在 ...

  4. 如何在ASP.NET Core中应用Entity Framework

    注:本文提到的代码示例下载地址> How to using Entity Framework DB first in ASP.NET Core 如何在ASP.NET Core中应用Entity ...

  5. [转]如何在ASP.NET Core中实现一个基础的身份认证

    本文转自:http://www.cnblogs.com/onecodeonescript/p/6015512.html 注:本文提到的代码示例下载地址> How to achieve a bas ...

  6. 在 ASP.NET Core 中集成 Skywalking APM

    前言 大家好,今天给大家介绍一下如何在 ASP.NET Core 项目中集成 Skywalking,Skywalking 是 Apache 基金会下面的一个开源 APM 项目,有些同学可能会 APM ...

  7. ASP.NET Core中使用GraphQL - 第四章 GraphiQL

    ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 ASP ...

  8. ASP.NET Core中使用GraphQL - 第六章 使用EF Core作为持久化仓储

    ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间件 ASP ...

  9. 在Asp.Net Core中集成Kafka

    在我们的业务中,我们通常需要在自己的业务子系统之间相互发送消息,一端去发送消息另一端去消费当前消息,这就涉及到使用消息队列MQ的一些内容,消息队列成熟的框架有多种,这里你可以读这篇文章来了解这些MQ的 ...

随机推荐

  1. serlvet配置xml和@WebServlet

    简单介绍 XML元素不仅是大小写敏感的,而且它们还对出现在其他元素中的次序敏感.例如,XML头必须是文件中的第一项,DOCTYPE声明必须是第二项,而web-app元素必须是第三项.在web-app元 ...

  2. Ubuntu连接上海大学校园网(ShuWlan-1x & Shu(For All))

    1.连接Shu(For All):直接连接,打开网页后可能会自动弹出登录页面,也可能需要点击浏览器菜单栏下方的跳转按钮. 2.连接ShuWlan-1x配置注意点: 认证方式:Protected EAP ...

  3. P3909 异或之积

    P3909 异或之积 为什么叫做异或之积? 答曰:只要不关乎Alice和Bob就行 做完这道水题,感觉自己弱爆了. 一开始就要考虑暴力\(O(n^3)\)的优化. 然后就注意到了题目中的\(6\)为什 ...

  4. Java虚拟机垃圾回收(二) :垃圾回收算法(转载)

    1.标记-清除算法 标记-清除(Mark-Sweep)算法是一种基础的收集算法. 1.算法思路 "标记-清除"算法,分为两个阶段: (A).标记 首先标记出所有需要回收的对象: 标 ...

  5. 菜鸟笔记 -- Chapter 6.2.5 代码块

    6.2.5  代码块 在编程过程中我们通常会遇到如下这种形式的程序: package democlass; public class CodeBlock { { System.out.println( ...

  6. oracle-sql脚本导出EXCEL数据

    在数据库中,经常有业务人员提出需求导出数据库中的业务数据,而且是每天.每周或每月定时导出.为了方便,可将sql查询的脚本 通过下面脚本来导出EXCEL数据. 1.将查询sql脚本(AAA.sql)放到 ...

  7. element组件dialog关闭时Message消息提示抖动问题

    在页面内容较多,出现滚动条时使用element组件里的dialog组件,当关闭dialog组件的同时弹出Message消息提示时,Message会抖动一下. 在页面有滚动条的情况先打开dialog时, ...

  8. C/C++使用keybd_event模拟键盘按键

    #include <stdio.h> #include <Windows.h> /* 设置键盘大小写状态 big:为TRUE则切换大写状态,否则切换小写状态 */ VOID M ...

  9. SAP销售订单屏幕字段控制隐藏,必输等

    1.T-CODE:shd0 创建变式  , 点击确认按钮后,SAP进入下一个屏幕,然后重复上面的操作,直到所有屏幕已完成设置. 如果后续屏幕不需要设置,可点击“退出并保存”按钮.保存后,进入下图所示页 ...

  10. LVS-DR模式实现调度负载

    本篇文章主要梳理一下LVS前端调度过程及用户请求过程 实验架构 准备工作 添加各主机路由联通主机通信 Client IP route add default gw 172.20.17.19 Route ...