使用JSON数据和EF Core种子数据库

我非常习惯使用标准代码(c#和EF api)来让EF帮助我建立数据库。你知道的,实例化一个对象,填充的字段,可能向相关列表添加对象。然后将整个工具包添加到DbContext并调用SaveChanges。

我向Geoffrey Grossenbach展示了一些EF Core代码,当时我们正在讨论如何在我开始认真学习一门更严肃的课程之前,在EF Core上为Pluralsight做一个接一个的演示。Geoffrey查看了所有用于构建我的对象来创建数据库的代码,然后说:“哇,代码真多。你不能用JSON之类的吗?”(注意:我已经厌倦了在wordpress中格式化这些代码,但你明白了……对吗?)

私有静态列表BuildWeatherEvents() {var events = new List {WeatherEvent.Create(date . time . now,WeatherType.Sun,新列表
         
          {new []{"Julie","Oh so sunny!"}}),WeatherType.Rain WeatherEvent.Create (DateTime.Now.AddDays (2)),WeatherType.Sun WeatherEvent.Create (DateTime.Now.AddDays (3),新列表
          
           {“朱莉”,“哦,可爱的夏日阳光!”太糟糕了,我在电脑上。new[]{“佛蒙特州的每个人”,“万岁,我们去玩吧!”新[]{“桑普森”,“我想去游泳,请!”},}),WeatherType.Cloudy WeatherEvent.Create (DateTime.Now.AddDays (4)),weatherEvent.create(datetime.now.adddays(-5),weatherType.rain),weatherEvent.create(datetime.now.adddays(-6),weatherType.sun);var lastEvent = WeatherEvent.Create(date . now . adddays (-1)),WeatherType.Snow,新列表
           
            {new[] {"Julie",“雪?7月吗?好吧,这对VT来说也太荒谬了!”}});lastEvent.Reactions.FirstOrDefault().Comments.Add       (new Comment { Text = "Get over it,朱莉!”});events.Add (lastEvent);返回事件;}
           
          
         

哦,那该多漂亮啊。下面是我用EF Core做的,但是你也可以用同样的概念来做EF6。

我的域名是WeatherEvent,它是我EFCore demo中的域名https://github.com/julielerman/EFCore-ASPNetCore-WebAPI-RTM,(我还没有更新以演示如何使用JSON数据)。

这是我存储在一个名为weatherdatasee .json文件中的json。

[{"date": "2016-07-27T00:00:00",“时间”:“22:09:13.8216230”,“类型”:5" response ": [{"name": "Julie",引文:“哦,阳光明媚!”“comments”:[]],“mostCommonWord”:零},{“日期”:“2016 - 07 - 25 t00:00:00”,“time”:“22:09:13.8237230”,“类型”:1、“反应”:[],“mostCommonWord”:零},“日期”:“2016-07-24t00:00:00”,“时间”:“22:09:13.8238740”,“类型”:5" response ": [{"name": "Julie",引文:“哦,可爱的夏日阳光!”太糟糕了,我在电脑上。“评论”:[]},{"name": "Everyone in vermont",引文:“万岁,我们去玩吧!”“评论”:[]},{" name ":“山”,“引言”:“我想去游泳,请!”“comments”:[]],“mostCommonWord”:零},{“日期”:“2016 - 07 - 23 t00:00:00”,“时间”:“22:09:13.8239130”,“类型”:6,“反应”:[],“mostCommonWord”:零},{“日期”:“2016 - 07 - 22 t00:00:00”,“时间”:“22:09:13.8239210”,“类型”:1、“反应”:[],“mostCommonWord”:零},{“日期”:“2016 - 07 - 21 t00:00:00”,“time”:“22:09:13.8239290”,“类型”:5“反应”:[],“mostCommonWord”:零},{“日期”:“2016 - 07 - 26 t00:00:00”,“time”:“22:09:13.8239360”,“类型”:2" response ": [{"name": "Julie",“引号”:“雪?7月吗?好吧,这对VT来说也是荒谬的!”,"comments": [{"text": "Get over it,朱莉!”}],“最常用词”:null}]

这不仅仅是数据,而是有3个层次关系的层次数据。用json表示它要简单得多、漂亮得多可读的而不是用c#构建所有这些,创建对象,等。

现在当然是魔法的时候了JSON.NET这使得将这些数据导入EF变得简单而甜蜜成为可能。

这是我使用EF从JSON中播种数据库的完整代码。

我在configure方法内的ASP.NET核心Web API中从startup.cs调用它。Here I'm just reading the file with System.IO.File.ReadAllText and then passing that text into my Seedit method.还要注意ConfigureServices,我在其中设置了DbContext及其所需的连接字符串。

注意:这篇文章中的代码有一些变动肖恩Wildermuth我和戴夫·福勒一起在推特上学习,aspnet团队的核心领导者之一。我根据Shawn的一个很好的建议,修改了我的原始代码来简化它,但是Dave指出了其中的一些范围问题。现在样本回到了原始版本,其中seedit方法负责创建一个新的ServiceScope并实例化上下文。

public void ConfigureServices(IServiceCollection services) {services. adddbcontext
         
          (       options=> options.UseNpgsql(         Configuration["Data:PostgreConnection:ConnectionString"]));services.AddMvc ();} public void Configure(IApplicationBuilder app,IHostingEnvironment env,{loggerFactory. addconsole (Configuration.GetSection("Logging"));loggerFactory.adddebug();app.UseMvc ();var datatext=system.io.file.readalltext(@“weatherdataset.json”);Seeder.Seedit (dataText app.ApplicationServices);
          }
         

这是Seedit方法,which uses JSON.NET to deserialize the json into a list of  WeatherEvent objects.契约序列化器是为了克服WeatherEvent类中的私有setter。我是从Daniel Wertheim的github repo报道。然后,我使用ASP.NET核心服务提供程序获取在启动时设置的服务,该服务将实例化weatherContext以及在启动中指定的连接字符串。

使用系统;使用system.linq;使用system.collections.generic;使用Microsoft.Extensions.DependencyInjection;使用EFCoreWebAPI;使用Newtonsoft.Json;使用JsonNet.PrivateSettersContractResolvers;public static void Seedit(string jsonData,iServiceProvider ServiceProvider)JSonserializerSettings settings=new JSonserializerSettings ContractResolver=new privateSetContractResolver()列表
         
          事件= JsonConvert.DeserializeObject
          
           > (jsonData设置);使用(var serviceScope = serviceProvider .GetRequiredService
           
            ().CreateScope() {var context = serviceScope .ServiceProvider.GetService
            
             ();if (!context.WeatherEvents.Any()) {context.AddRange(events);context.SaveChanges ();}}}}
            
           
          
         

实例化上下文之后,我要检查一下数据库中是否有天气事件,这样我就不会重新播种了。(This is logic I want for seeding during my demo so you may have different rules for the seeding.) Now I call context.AddRange passing in the list of WeatherEvent objects.我可以直接使用DbSet或上下文来调用AddRange。最后,SaveChanges。

关键是,无论您使用的是EFCore还是EF6(所以服务的使用是特定于我的应用程序是一个ASPNET Core api这一事实的),只是在读取JSON文件,反序列化数据并将其添加到上下文中。这比强制创建所有数据要简单得多。

根据您的数据的形状,它可能并不总是答案,但对于这个特定的模型和我需要的种子数据来说,它是完美的。

注册我的新闻稿所以你不会错过我的会议和多元化视野课程公告!

关于“使用JSON数据和EF Core种子数据库

    1. 嗯,看起来我需要学习更多关于如何使用aspnet core DI。静态类(播种器)中没有构造函数。所以我必须改变那个类。但是,我是否必须在启动时实例化seeder,然后使用服务以某种方式传递weatherContext实例?我遗漏了一些东西,因为我不知道如何神奇地将上下文实例获取到播种器类,而且它看起来更复杂(因为我不知道什么)。我知道你在悉尼NDC,所以不急,但有趣和好奇。

  1. 两个注意事项:
    1)记住,如果你有私人setter,您将需要使用json网络契约解析器。我肯定会在回购中加上这个。我需要!
    2) Getting some comments on twitter from David Fowler from the ASP.NET team and want to ensure this solution makes him happy before I post to github.

  2. 嗨,朱莉,自从EF最初发布以来已经发生了很大的变化,开发人员会发现读一本关于EF的书很有用吗?如果是这样,你推荐哪本书?谢谢

    1. 你好,Dom,
      我认为这本大书(编程ef第二版)对于理解ef的一些内部原理有一定的价值。DbContext & Code First非常相关。还有其他作者的新书。然而,我把所有的精力都放在为多元化视野创造内容上,而不是写书。所以你可以从我这里找到关于英孚的同样深度的信息。从…开始multuralsight.com/authors/julie-lerman

  3. 这当然是作弊,但是您可以只使用SQL Server 2016 json支持。你仍然需要在web应用程序中编写所有的EF来CRUD数据库。

    创建表的合同(
    ConId int,
    varchar(4)象征…)

    插入合同
    选择合同。*
    从OPENROWSET(批量C:\Data\Contract.json'),SINGLE_CLOB j)
    交叉应用OPENJSON (BulkColumn)
    (ConId int,
    象征varchar (4),……
    )合同
    WHERE NOT EXISTS(SELECT ConId FROM Contract c WHERE c.ConId = ConId)

    从合同中选择*

    1. 嗨,尼克,

      是的,作弊和老派,哈哈它只在SQL Server中工作。我只是在一些单元测试中使用了这种技术。很有帮助。我们正在使用PostgreSQL,所以您的建议不是一个选项。

      希望一切都好。如果你还在这个地区工作,我们应该见面喝杯啤酒。

  4. 你好,酷的文章。

    几周前我发布了一个。net库,名为CherrySeed,你可以用它从任何来源(CSV,XML小黄瓜,SpecFlow,等)到任何目的地。这是你解决问题的下一步。

    在specFlow中,我们还必须将许多数据植入数据库。因此,我针对SpecFlow的使用创建了一个易于使用的CherrySeed包装器。

    如果你查一下CherrySeed,问问我你对图书馆有什么看法,那就太好了。

    这里是介绍文章的链接https://medium.com/@michael_altmann/why-seeding-test-data-into-database-using-cherryseed-net-c-529da467ffd9#.t29hgtvlt

    文章中有一些链接到wiki,github,等。

      1. 可能是EF6中的IDbSet没有公开AddRange(或RemoveRange)。我不知道为什么。我必须创建一个变通方法。

  5. 你好,朱莉。我真不敢相信你总是那么快就回复新帖子。你们一定有十七个人。不管怎么说,是––我创建了一个静态方法,并使用它代替context.addrange():

    公共静态IEnumerable AddRange(
    这IDbSet dbset,
    其中TEntity: class
    {
    返回((dbset)dbset).addrange(entitiestoadd);
    }

    谢谢你所做的一切。

    杰夫

  6. 朱莉,再一次谢谢你。我正在实现IdentityServer4,并试图避免teh服务定位器模式(http://odetocode.com/blogs/scott/archive/2016/02/18/avoiding-the-service-locator-pattern-in-asp-net-core.aspx)

    所以“GetService”是我想要检查的代码味道。我现在明白了,在应用程序级别上,获得一个有作用域的项实际上是一个单例,因为我们不在请求作用域中。

    但我认为,至少取消您第一次使用“GetService”是安全的。seedIt方法可以使用IServiceScopeFactory,它可以安全地注入配置参数。

    公共void配置(IApplicationBuilder应用程序,IHostingEnvironment env,我的工厂日志工厂,IServiceScopeFactory aServiceScopeFactory)

    我认为工厂的单一模式是安全的。

  7. 广播: .NET博客

留下答复马特取消回复

您的电子邮件地址将不会被公布。必填字段已标记*

这个站点使用Akismet来减少垃圾邮件。了解如何处理您的评论数据