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

我非常习惯使用标准代码(c#和EF api)来让EF帮助我建立数据库。你知道的,实例化一个对象,填充的字段,可以将对象添加到相关列表中。然后将整个kit n'kaboodle添加到dbcontext并调用savechanges。

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

私有静态列表BuildWeatherEvents() {var events = new List {WeatherEvent.Create(date . time . now,WeatherType.Sun,新列表
         
          新的[]“朱莉”,“哦,太阳光了!”})WeatherType.Rain WeatherEvent.Create (DateTime.Now.AddDays (2)),WeatherType.Sun WeatherEvent.Create (DateTime.Now.AddDays (3),新列表
          
           新的[]“朱莉”,“哦,可爱的夏日阳光!太糟糕了,我在电脑上“,new[]{“佛蒙特州的每个人”,“万岁,我们去玩吧!”“桑普森,”“我想去游泳,请!”}}),weatherEvent.create(datetime.now.adddays(-4),weatherType.cloudy)WeatherType.Rain WeatherEvent.Create (DateTime.Now.AddDays (5)),WeatherEvent.Create (DateTime.Now.AddDays (6)、WeatherType.Sun)};var lastEvent = WeatherEvent.Create(date . now . adddays (-1)),天气类型。雪,新列表
           
            新的[]“朱莉”,“雪?7月吗?好吧,这对VT来说也太荒谬了!”}});lastevent.reactions.firstOrDefault().comments.add(new comment text=“get over it,朱莉!”});事件。添加(lastevent);返回事件;}
           
          
         

哦,那会是多么漂亮啊。下面是我如何用ef-core完成的,但是你当然可以用同样的概念来处理ef6。

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

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

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

这不仅仅是数据,而是有3个层次关系的层次数据。在JSON中表达它要容易得多,更漂亮,而且可读性比把这些都建在C,创建对象,等。

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

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

我在configure方法内的ASP.NET核心Web API中从startup.cs调用它。这里我只是用system.io.file.readalltext读取文件,然后将该文本传递到seedit方法中。还要注意ConfigureServices,我在其中设置了DbContext及其所需的连接字符串。

注意:本文中的代码有一些改动韦尔德莫斯我和戴夫·福勒一起在推特上学习,ASPNET团队的核心领导之一。我根据Shawn的一个很好的建议,修改了我的原始代码来简化它,但戴夫指出了一些范围问题。现在样本回到了原始版本,其中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 (@“weatherdataseed.json”);seeder.seedit(数据文本,app.applicationservices);
          }
         

这是Seedit方法,它使用json.net将json反序列化为weatherEvent对象列表。契约序列化器是为了克服WeatherEvent类中的私有setter。我从Daniel Wertheim的github repo报道。然后,我使用ASP.NET核心服务提供程序获取在启动时设置的服务,该服务将实例化weatherContext以及在启动中指定的连接字符串。

使用系统;使用来;使用System.Collections.Generic;使用Microsoft.Extensions.DependencyInjection;使用EFCoreWebAPI;使用Newtonsoft.Json;使用jsonnet.privatesetterscontractresolvers;public static void Seedit(string jsonData,{ContractResolver = new PrivateSetterContractResolver()};列表
         
          事件=jsonConvert.DeserializeObject
          
           >(詹森达,设置);使用(var serviceScope=serviceProvider.getRequiredService
           
            ().CreateScope() {var context = serviceScope .ServiceProvider.GetService
            
             ();如果(!)context.weatherEvents.any())context.addRange(事件);context.SaveChanges ();}}}}
            
           
          
         

实例化上下文之后,我用它来检查数据库中是否有任何天气事件,所以我没有重新播种。(这是我在我的演示期间想要播种的逻辑,因此您可能对播种有不同的规则。)现在,我在WeatherEvent对象列表中调用Context.AddRange传递。我可以直接使用DbSet或上下文来调用AddRange。最后,SaveChanges。

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

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

报名参加我的通讯所以你不会错过我的会议和多元化视野课程公告!

28“思考”使用JSON数据和EF Core种子数据库

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

  1. 两个笔记:
    1)记住,如果你有私人setter,您将需要使用json网络契约解析器。我肯定会在回购中加上这个。我需要!
    2)从ASP.NET团队的David Fowler那里得到一些关于twitter的评论,并希望在我发布到Github之前确保这个解决方案让他高兴。

  2. 嗨,朱莉,由于英孚在其最初发行后发生了一些变化,开发人员会发现读一本关于EF的书很有用吗?如果是这样,你会推荐哪本书?谢谢

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

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

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

    插入合同
    选择合同。*
    来自openrowset(批量C:\data\contract.json',单瓣)如J
    交叉应用OPENJSON (BulkColumn)
    (ConId int,
    符号varchar(4),…
    )合同
    如果不存在(从合同C中选择conid,其中c.conid=conid)

    从合同中选择*。

    1. 嗨,尼克,

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

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

  4. 你好,酷的文章。

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

    在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/avointing-the-service-locator-pattern-in-asp-net-core.aspx

    所以“GetService”是我想要检查的代码味道。我现在了解到,在应用程序级别,获得一个范围内的项目实际上是一个单例,因为我们不在请求范围内。

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

    公共void配置(IApplicationBuilder应用程序,IHostingEnvironment env,ILoggerFactory loggerFactory,IServiceScopeFactory aServiceScopeFactory)

    一个工厂的单件我想是安全的。

  7. 平回: net的博客

答复约翰·卡拉威取消回复

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

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