不得不說微軟的技術迭代仍是很快的,上了微軟的船就得跟着她走下去,前文一塊兒學ASP.NET Core 2.0學習筆記(一): CentOS下 .net core2 sdk nginx、supervisor、mysql環境搭建搭建好了.net core linux的相關環境,今天就來講說ef core相關的配置及遷移:html
簡介:mysql
Entity Framework(如下簡稱EF) 是微軟以 ADO.NET 爲基礎所發展出來的對象關係對應 (O/R Mapping) 解決方案,EF Core是Entity framework得下一版本,相比EF原來版本(4-6.1),顯得更加輕量級,相比一樣出身名門的dapper仍是顯得有點龐大,不過魚與熊掌向來不可兼得,想一想一堆堆語法糖,方便的linq查詢以及lambda表達式,能夠很大程度上從T-SQL語法上脫身出來不少,在配置過程當中也碰到一些問題,記錄下來,以便後期翻閱:linux
一.poco的建立以及Fluent Api關係配置nginx
1.一對多關係:sql
項目中最多見的就是一對多關係了,以語言及語言爲例mongodb
語言(Language)類數據庫
1 public partial class Language : BaseEntity<int> 2 { 3 private ICollection<LocaleStringResource> _localeStringResources; 4 5 /// <summary> 6 /// Gets or sets the name 7 /// </summary> 8 9 public string Name { get; set; } 10 11 /// <summary> 12 /// Gets or sets the language culture 13 /// </summary> 14 15 public string LanguageCulture { get; set; } 16 17 /// <summary> 18 /// Gets or sets the unique SEO code 19 /// </summary> 20 21 public string UniqueSeoCode { get; set; } 22 23 /// <summary> 24 /// Gets or sets the flag image file name 25 /// </summary> 26 27 public string FlagImageFileName { get; set; } 28 29 /// <summary> 30 /// Gets or sets a value indicating whether the language supports "Right-to-left" 31 /// </summary> 32 33 public bool Rtl { get; set; } 34 35 36 /// <summary> 37 /// Gets or sets a value indicating whether the language is published 38 /// </summary> 39 40 public bool Published { get; set; } 41 42 /// <summary> 43 /// Gets or sets the display order 44 /// </summary> 45 46 public int DisplayOrder { get; set; } 47 48 public bool IsDefault { get; set; } 49 50 /// <summary> 51 /// Gets or sets locale string resources 52 /// </summary> 53 public virtual ICollection<LocaleStringResource> LocaleStringResources 54 { 55 get { return _localeStringResources ?? (_localeStringResources = new HashSet<LocaleStringResource>()); } 56 protected set { _localeStringResources = value; } 57 }
語言資源(LocaleStringResource):windows
1 public partial class LocaleStringResource : BaseEntity<int> 2 { 3 /// <summary> 4 /// Gets or sets the language identifier 5 /// </summary> 6 public int LanguageId { get; set; } 7 8 /// <summary> 9 /// Gets or sets the resource name 10 /// </summary> 11 public string ResourceName { get; set; } 12 13 /// <summary> 14 /// Gets or sets the resource value 15 /// </summary> 16 public string ResourceValue { get; set; } 17 18 /// <summary> 19 /// Gets or sets a value indicating whether this resource was installed by a plugin 20 /// </summary> 21 public bool? IsFromPlugin { get; set; } 22 23 /// <summary> 24 /// Gets or sets a value indicating whether this resource was modified by the user 25 /// </summary> 26 public bool? IsTouched { get; set; } 27 28 /// <summary> 29 /// Gets or sets the language 30 /// </summary> 31 public virtual Language Language { get; set; } 32 33 }
其中語言及資源主外鍵關係配置以下服務器
1 public partial class LanguageMapper : IEntityTypeConfiguration<Language> 2 { 3 public void Configure(EntityTypeBuilder<Language> builder) 4 { 5 builder.ToTable("Language"); 6 builder.HasKey(r => r.Id); 7 builder.HasIndex(r => r.LanguageCulture); 8 builder.HasIndex(r => r.Name); 9 builder.HasIndex(r => r.UniqueSeoCode); 10 } 11 }
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); } }
二、父子關係 :app
1 public class TechCategory:BaseEntity<int> 2 { 3 /// <summary> 4 /// 名稱 5 /// </summary> 6 public string Name { get; set; } 7 /// <summary> 8 /// 分類描述 9 /// </summary> 10 public string Descript { get; set; } 11 /// <summary> 12 /// meta標題 13 /// </summary> 14 public string MetaTitle { get; set; } 15 /// <summary> 16 /// meta描述 17 /// </summary> 18 public string MetaDescript { get; set; } 19 /// <summary> 20 /// 縮略圖 21 /// </summary> 22 public string Thumb { get; set; } 23 /// <summary> 24 /// 圖片 25 /// </summary> 26 public string Image { get; set; } 27 /// <summary> 28 /// 排序 29 /// </summary> 30 public int Sort { get; set; } 31 /// <summary> 32 /// 父級分類 33 /// </summary> 34 public int? ParentId { get; set; } 35 36 /// <summary> 37 /// 父級分類 38 /// </summary> 39 40 public virtual TechCategory Parent { get; set; } 41 public virtual ICollection<Technology> Technologys { get; set; } 42 /// <summary> 43 /// 子級 44 /// </summary> 45 public virtual ICollection<TechCategory> Childs { get; set; } 46 /// <summary> 47 /// 關鍵詞 48 /// </summary> 49 public string Slug { get; set; } 50 /// <summary> 51 /// 建立時間 52 /// </summary> 53 public long CreatedOn { get; set; } 54 }
1 public class TechCategoryMapper : IEntityTypeConfiguration<TechCategory> 2 { 3 public void Configure(EntityTypeBuilder<TechCategory> builder) 4 { 5 builder.ToTable("TechCategory"); 6 builder.HasKey(r => r.Id); 7 builder.HasMany(r => r.Childs).WithOne(x => x.Parent) 8 .HasForeignKey(fk => fk.ParentId); 9 builder.HasIndex(r => r.Name); 10 } 11 }
2、數據庫上下文:
根據前面建立的相關實體類 以及相關mapper類型,咱們能夠重現DbContext的OnModelCreating的方法,反射出實現了IEntityTypeConfiguration接口的相關mapper類型建立相關實體-數據表的相關對應關係
1 public class DefaultContext : DbContext 2 { 3 public DefaultContext(DbContextOptions<DefaultContext> opt) 4 :base(opt) 5 { 6 AutoCommitEnabled = true; 7 } 8 protected override void OnModelCreating(ModelBuilder builder) 9 { 10 base.OnModelCreating(builder); 11 var mappingInterface = typeof(IEntityTypeConfiguration<>); 12 // Types that do entity mapping 13 var mappingTypes = GetType().GetTypeInfo().Assembly.GetTypes() 14 .Where(x => x.GetInterfaces().Any(y => y.GetTypeInfo().IsGenericType && y.GetGenericTypeDefinition() == mappingInterface)); 15 16 // Get the generic Entity method of the ModelBuilder type 17 var entityMethod = typeof(ModelBuilder).GetMethods() 18 .Single(x => x.Name == "Entity" && 19 x.IsGenericMethod && 20 x.ReturnType.Name == "EntityTypeBuilder`1"); 21 22 foreach (var mappingType in mappingTypes) 23 { 24 25 // Get the type of entity to be mapped 26 var genericTypeArg = mappingType.GetInterfaces().Single().GenericTypeArguments.Single(); 27 28 // Get the method builder.Entity<TEntity> 29 var genericEntityMethod = entityMethod.MakeGenericMethod(genericTypeArg); 30 31 // Invoke builder.Entity<TEntity> to get a builder for the entity to be mapped 32 var entityBuilder = genericEntityMethod.Invoke(builder, null); 33 34 // Create the mapping type and do the mapping 35 var mapper = Activator.CreateInstance(mappingType); 36 mapper.GetType().GetMethod("Configure").Invoke(mapper, new[] { entityBuilder }); 37 } 38 foreach (var relationship in builder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys())) 39 { 40 relationship.DeleteBehavior = DeleteBehavior.Restrict; 41 } 42 } 43 }
3、多數據庫支持:
多數據庫的支持,並非意味着同時對多種數據庫操做,固然,後面,咱們會嘗試同時對多種數據庫操做,這可能須要多個上下文,暫且不論。分佈式數據庫。咱們的項目多是在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引用列表
1 <ItemGroup> 2 <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" /> 3 <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" /> 4 <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" /> 5 <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.0.0-rtm-10058" /> 6 </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版本便可。
祝願你在碼農道路上越走越順暢;