一起学ASP.NET Core 2.0学习笔记(二): ef core2.0 及mysql provider 、Fluent API相关配置及迁移
不得不说微软的技术迭代还是很快的,上了微软的船就得跟着她走下去,前文一起学ASP.NET Core 2.0学习笔记(一): CentOS下 .net core2 sdk nginx、supervisor、mysql环境搭建搭建好了.net core linux的相关环境,今天就来说说ef core相关的配置及迁移:
简介:
Entity Framework(以下简称EF) 是微软以 ADO.NET 为基础所发展出来的对象关系对应 (O/R Mapping) 解决方案,EF Core是Entity framework得下一版本,相比EF原来版本(4-6.1),显得更加轻量级,相比同样出身名门的dapper还是显得有点庞大,不过鱼与熊掌向来不可兼得,想想一堆堆语法糖,方便的linq查询以及lambda表达式,可以很大程度上从T-SQL语法上脱身出来很多,在配置过程中也碰到一些问题,记录下来,以便后期翻阅:
一.poco的创建以及Fluent Api关系配置
1.一对多关系:
项目中最常见的就是一对多关系了,以语言及语言为例
语言(Language)类
public partial class Language : BaseEntity<int>
{
private ICollection<LocaleStringResource> _localeStringResources; /// <summary>
/// Gets or sets the name
/// </summary> public string Name { get; set; } /// <summary>
/// Gets or sets the language culture
/// </summary> public string LanguageCulture { get; set; } /// <summary>
/// Gets or sets the unique SEO code
/// </summary> public string UniqueSeoCode { get; set; } /// <summary>
/// Gets or sets the flag image file name
/// </summary> public string FlagImageFileName { get; set; } /// <summary>
/// Gets or sets a value indicating whether the language supports "Right-to-left"
/// </summary> public bool Rtl { get; set; } /// <summary>
/// Gets or sets a value indicating whether the language is published
/// </summary> public bool Published { get; set; } /// <summary>
/// Gets or sets the display order
/// </summary> public int DisplayOrder { get; set; } public bool IsDefault { get; set; } /// <summary>
/// Gets or sets locale string resources
/// </summary>
public virtual ICollection<LocaleStringResource> LocaleStringResources
{
get { return _localeStringResources ?? (_localeStringResources = new HashSet<LocaleStringResource>()); }
protected set { _localeStringResources = value; }
}
语言资源(LocaleStringResource):
public partial class LocaleStringResource : BaseEntity<int>
{
/// <summary>
/// Gets or sets the language identifier
/// </summary>
public int LanguageId { get; set; } /// <summary>
/// Gets or sets the resource name
/// </summary>
public string ResourceName { get; set; } /// <summary>
/// Gets or sets the resource value
/// </summary>
public string ResourceValue { get; set; } /// <summary>
/// Gets or sets a value indicating whether this resource was installed by a plugin
/// </summary>
public bool? IsFromPlugin { get; set; } /// <summary>
/// Gets or sets a value indicating whether this resource was modified by the user
/// </summary>
public bool? IsTouched { get; set; } /// <summary>
/// Gets or sets the language
/// </summary>
public virtual Language Language { get; set; } }
其中语言及资源主外键关系配置如下
public partial class LanguageMapper : IEntityTypeConfiguration<Language>
{
public void Configure(EntityTypeBuilder<Language> builder)
{
builder.ToTable("Language");
builder.HasKey(r => r.Id);
builder.HasIndex(r => r.LanguageCulture);
builder.HasIndex(r => r.Name);
builder.HasIndex(r => r.UniqueSeoCode);
}
}
public partial class LocaleStringResourceMapper : IEntityTypeConfiguration<LocaleStringResource>
{
public void Configure(EntityTypeBuilder<LocaleStringResource> builder)
{
builder.ToTable("LocaleStringResource");
builder.HasKey(r => r.Id);
builder.HasIndex(r => r.LanguageId);
builder.HasIndex(r => r.ResourceName);
builder.HasOne(r => r.Language).WithMany(b => b.LocaleStringResources)
.HasForeignKey(fk => fk.LanguageId);
}
}
2、父子关系 :
public class TechCategory:BaseEntity<int>
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 分类描述
/// </summary>
public string Descript { get; set; }
/// <summary>
/// meta标题
/// </summary>
public string MetaTitle { get; set; }
/// <summary>
/// meta描述
/// </summary>
public string MetaDescript { get; set; }
/// <summary>
/// 缩略图
/// </summary>
public string Thumb { get; set; }
/// <summary>
/// 图片
/// </summary>
public string Image { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 父级分类
/// </summary>
public int? ParentId { get; set; } /// <summary>
/// 父级分类
/// </summary> public virtual TechCategory Parent { get; set; }
public virtual ICollection<Technology> Technologys { get; set; }
/// <summary>
/// 子级
/// </summary>
public virtual ICollection<TechCategory> Childs { get; set; }
/// <summary>
/// 关键词
/// </summary>
public string Slug { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public long CreatedOn { get; set; }
}
public class TechCategoryMapper : IEntityTypeConfiguration<TechCategory>
{
public void Configure(EntityTypeBuilder<TechCategory> builder)
{
builder.ToTable("TechCategory");
builder.HasKey(r => r.Id);
builder.HasMany(r => r.Childs).WithOne(x => x.Parent)
.HasForeignKey(fk => fk.ParentId);
builder.HasIndex(r => r.Name);
}
}
二、数据库上下文:
根据前面创建的相关实体类 以及相关mapper类型,我们可以重现DbContext的OnModelCreating的方法,反射出实现了IEntityTypeConfiguration接口的相关mapper类型创建相关实体-数据表的相关对应关系
public class DefaultContext : DbContext
{
public DefaultContext(DbContextOptions<DefaultContext> opt)
:base(opt)
{
AutoCommitEnabled = true;
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
var mappingInterface = typeof(IEntityTypeConfiguration<>);
// Types that do entity mapping
var mappingTypes = GetType().GetTypeInfo().Assembly.GetTypes()
.Where(x => x.GetInterfaces().Any(y => y.GetTypeInfo().IsGenericType && y.GetGenericTypeDefinition() == mappingInterface)); // Get the generic Entity method of the ModelBuilder type
var entityMethod = typeof(ModelBuilder).GetMethods()
.Single(x => x.Name == "Entity" &&
x.IsGenericMethod &&
x.ReturnType.Name == "EntityTypeBuilder`1"); foreach (var mappingType in mappingTypes)
{ // Get the type of entity to be mapped
var genericTypeArg = mappingType.GetInterfaces().Single().GenericTypeArguments.Single(); // Get the method builder.Entity<TEntity>
var genericEntityMethod = entityMethod.MakeGenericMethod(genericTypeArg); // Invoke builder.Entity<TEntity> to get a builder for the entity to be mapped
var entityBuilder = genericEntityMethod.Invoke(builder, null); // Create the mapping type and do the mapping
var mapper = Activator.CreateInstance(mappingType);
mapper.GetType().GetMethod("Configure").Invoke(mapper, new[] { entityBuilder });
}
foreach (var relationship in builder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
{
relationship.DeleteBehavior = DeleteBehavior.Restrict;
}
}
}
三、多数据库支持:
多数据库的支持,并不是意味着同时对多种数据库操作,当然,后面,我们会尝试同时对多种数据库操作,这可能需要多个上下文,暂且不论。分布式数据库。我们的项目可能是在windows上开发的使用的是SqlServer,我们要发布到linux上,SqlServer 2017 据说是支持liunx的,但是还没出... 当然不是说 SqlServer 就不能装在liunx上,但是我们的Liunx服务器可能已经安装了MySql或 Oracle,我们希望使用现有的,又或者是,我们需要切换数据库。那么,我们需要可以随时切换数据库的支持,以上篇的mysql为例:
1.引用相关包,mysql我用的Pomelo.EntityFrameworkCore.MySql,国人开发的mysql for ef core的相关服务对象,ef
core 2.0中需要指定2.0版本(Install-Package Pomelo.EntityFrameworkCore.MySql -Version 2.0.0-rtm-10059),
2.需改配置文件依据相关配置动态加载数据库提供对象;相关代码及配置如下
nuget引用列表
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.0.0-rtm-10058" />
</ItemGroup>
相关配置文件修改
"ConnectionStrings": {
"MongoDbConnectionString": "mongodb://tchistory:tc123456@127.0.0.1/history",
"ConnectionString": "Data Source=127.0.0.1;Initial Catalog=farmdata;User ID=root;Password=123456",
"DataProvider": "MySql"
},
在startup.cs 的configureServices方法中添加数据库上下文
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DefaultContext>(option => option.UseFarmDatabase(Configuration));
services.UseFarmService(Configuration);
services.AddMvc(); }
数据库提供对象扩展方法如下:
public static DbContextOptionsBuilder UseFarmDatabase(this DbContextOptionsBuilder optionsBuilder, IConfiguration configuration)
{
string provider = configuration.GetConnectionString("DataProvider"), connection = configuration.GetConnectionString("ConnectionString");
if (provider.Equals(DataBaseServer.SqlServer, StringComparison.InvariantCultureIgnoreCase))
{
return optionsBuilder.UseSqlServer(connection);
}
else if (provider.Equals(DataBaseServer.MySql, StringComparison.InvariantCultureIgnoreCase))
{
return optionsBuilder.UseMySql(connection);
}
else
{
throw Error.Argument("UseDatabaseServer", "No databaseProvider");
}
}
在程序包管理控制台添加相关迁移 命令 add-migration init: 会在当前目录下生成相关迁移目录
执行update-database -Verbose提交更改到数据库,这样数据库迁移及更改就算完成了,其中要注意的地方是ef core 2.0 中有些数据库提供对象暂时是没有完全实现,如用Pomelo.EntityFrameworkCore.MySql -Version 1.1.2 可能会报方法未实现,更新2.0 rtm版本即可。
祝愿你在码农道路上越走越顺畅;
一起学ASP.NET Core 2.0学习笔记(二): ef core2.0 及mysql provider 、Fluent API相关配置及迁移的更多相关文章
- ASP.NET Core Web开发学习笔记-1介绍篇
ASP.NET Core Web开发学习笔记-1介绍篇 给大家说声报歉,从2012年个人情感破裂的那一天,本人的51CTO,CnBlogs,Csdn,QQ,Weboo就再也没有更新过.踏实的生活(曾辞 ...
- ASP.NET Core快速入门--学习笔记系列文章索引目录
课程链接:http://video.jessetalk.cn/course/explore 良心课程,大家一起来学习哈! 抓住国庆假期的尾巴完成了此系列课程的学习笔记输出! ASP.NET Core快 ...
- ASP.NET Core MVC 网站学习笔记
ASP.NET Core MVC 网站学习笔记 魏刘宏 2020 年 2 月 17 日 最近因为” 新冠” 疫情在家办公,学习了 ASP.NET Core MVC 网站的一些知识,记录如下. 一.新建 ...
- python3.4学习笔记(二十五) Python 调用mysql redis实例代码
python3.4学习笔记(二十五) Python 调用mysql redis实例代码 #coding: utf-8 __author__ = 'zdz8207' #python2.7 import ...
- ASP.NET Core快速入门学习笔记(第3章:依赖注入)
课程链接:http://video.jessetalk.cn/course/explore 良心课程,大家一起来学习哈! 任务16:介绍 1.依赖注入概念详解 从UML和软件建模来理解 从单元测试来理 ...
- ASP.NET Core快速入门学习笔记(第2章:配置管理)
课程链接:http://video.jessetalk.cn/course/explore 良心课程,大家一起来学习哈! 任务9:配置介绍 命令行配置 Json文件配置 从配置文件文本到c#对象实例的 ...
- ASP.NET Core快速入门学习笔记(第1章:介绍与引入)
课程链接:http://video.jessetalk.cn/course/explore 良心课程,大家一起来学习哈! 任务1:课程介绍 任务2:环境安装 下载地址:https://dotnet.m ...
- gRPC在 ASP.NET Core 中应用学习(二)
前言: 上一篇文章中简单的对gRPC进行了简单了解,并实现了gRPC在ASP.NET Core中服务实现.客户端调用:那么本篇继续对gRPC的4中服务方法定义.其他使用注意点进一步了解学习 一.gRP ...
- ASP.NET Core框架深度学习(二) 管道对象
4.HttpContext 第一个对象 我们的ASP.NET Core Mini由7个核心对象构建而成.第一个就是大家非常熟悉的HttpContext对象,它可以说是ASP.NET Core应用开发中 ...
随机推荐
- hdu_3746: Cyclic Nacklace
题目链接 给出一个字符串,你可以通过在首尾加入字符使其变成一个具有周期T(T>=2)的字符串,求所需加入的最少字符数. 所考察算法仍然是对next数组含义的理解 #include<cstd ...
- poj_3122:Pie(二分)
不算难的一道二分..各种玄学错误..eps小了T,大了WA..最后G++改成C++提交就AC了.. #include<iostream> #include<cstdio> #i ...
- CSS学习笔记一:css 画平面图形
最近在学习CSS,先从CSS画点平面图形入手,发现除了正方形.长方形此类比较简单,只要有长宽设置恰当即可,画圆要涉及radius,然后恢复到做界面的最讨厌的状态了,不断的修改设值,调整数据,所幸并不多 ...
- Linux基础(四)
一.系统监控 1.用top命令实时监测CPU.内存.硬盘状态 效果类似Windows的任务管理器,默认每5秒刷新一下屏幕上的显示结果. [root@localhost /]# top top - 17 ...
- 设计模式(3)抽象工厂模式(Abstract Factory)
设计模式(0)简单工厂模式 设计模式(1)单例模式(Singleton) 设计模式(2)工厂方法模式(Factory Method) 源码地址 0 抽象工厂模式简介 0.0 抽象工厂模式定义 抽象工厂 ...
- (转)Synchronized(对象锁)和Static Synchronized(类锁)的区别
场景:面试的时候经常用得到! 1 综述 Synchronized和Static Synchronized区别 一个是实例锁(锁在某一个实例对象上,如果该类是单例,那么该锁也具有全局锁的概念),一个是全 ...
- 【CSS】div父容器根据子容器大小自适应
Div即父容器不根据内容自动调节高度,我们看下面的代码: <div id="main"> <div id="content"></ ...
- webIDE 第二篇博文
这是我做webIDE过程中的第二篇博文,之所以隔了这么长时间没更,因为确实是没有啥进度啊,没什么可写的,现在虽然依然没啥进度,但中途遇到很多坑,这些坑还是有记录下来的必要的. 因个人水平问题,可能有的 ...
- Oracle 12C 新特性 - “可插拔数据库”功能
Oracle 12C加入了一个非常有新意的功能"可插拔数据库"特性,实现了数据库(PDB)在"容器"(CDB)上的拔功能,既能提高系统资源的利用率,也简化大面积 ...
- RSA简介(一)——数论原理
RSA是最常用的非对称加密算法. 所谓非对称加密,就是说有两个密钥,一个密钥加密只可以用另外一个密钥解密,一般一个作为公钥,公开给所有人用来加密用,而另一个用来解密其他拥有公钥的加密结果,叫做私钥.另 ...