zoukankan      html  css  js  c++  java
  • 一起学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)类

     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         }
    View Code

    语言资源(LocaleStringResource):

     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     }
    View Code

    其中语言及资源主外键关系配置如下

     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     }
    View Code
     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、父子关系 :

     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     }
    View Code
     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     }
    View Code

    二、数据库上下文:

    根据前面创建的相关实体类 以及相关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     }
    View Code

    三、多数据库支持:

    多数据库的支持,并不是意味着同时对多种数据库操作,当然,后面,我们会尝试同时对多种数据库操作,这可能需要多个上下文,暂且不论。分布式数据库。我们的项目可能是在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>
    View Code

    相关配置文件修改

     "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版本即可。

    祝愿你在码农道路上越走越顺畅;

  • 相关阅读:
    原创:USB HID读卡器数据解析(R321-13.56MHZ读卡器)
    你对USB了解吗?--USB 协议分析之 HID 设备
    Python中的单例设计模式【多测师_王sir】
    把一个json文件写入到csv文件当中【多测师_王sir】
    pip安装本地文件报错处理方法【多测师_王sir】
    ddt数据驱动常见的用法【多测师_王sir】
    读取json数据转换为字典存入到列表当中【多测师_王sir】
    读取json数据输入键拿到对应的值【多测师_王sir】
    为什么要用cookie和session【多测师_王sir】
    Python2和Python3的区别【多测师_王sir】
  • 原文地址:https://www.cnblogs.com/shatanku/p/7455420.html
Copyright © 2011-2022 走看看