使用json数据和ef核心为数据库种子

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

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

private static list buildWeatherEvents()var events=new list weatherEvent.create(datetime.now,weatherType.sun,新列表
         
          新的[]“朱莉”,“哦,太阳光了!”})WeatherType.Rain WeatherEvent.Create (DateTime.Now.AddDays (2)),weatherEvent.create(datetime.now.adddays(-3),weatherType.sun,新列表
          
           新的[]“朱莉”,“哦,可爱的夏日阳光!太糟糕了,我在电脑上“,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(datetime.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数据)。

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

[“日期”:“2016-07-27t00:00:00”,“time”:“22:09:13.8216230”,“类型”:5," response ": [{"name": "Julie",引文:“哦,阳光明媚!”“评论”:[]},“mostcommonword”:空,“日期”:“2016-07-25t00: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-22t00: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”:“克服它,朱莉!“}],“mostcommonword”:空]

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

现在当然是魔法的时候了json.net网站这样就可以将这些数据简化为ef。

这是我用来从使用ef的JSON中为数据库种子的完整代码。

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

注意:本文中的代码有一些改动韦尔德莫斯我和戴夫·福勒在Twitter上学习过,ASPNET团队的核心领导之一。我根据肖恩的一个伟大建议修改了我的原始代码以简化它,但戴夫指出了一些范围问题。现在样本回到了原始版本,其中seedit方法负责创建新的servicescope并实例化上下文。

public void配置服务(IServiceCollection Services)services.adddbContext
         
          (options=>options.usenpgsql(configuration[“data:postgreconnection:connectionString”]);services.addmvc();}公共void配置(IApplicationBuilder应用程序,环境卫生部,iloggerFactory)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。最后,保存更改。

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

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

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

28“思考”使用json数据和ef核心为数据库种子

  1. 既然你在aspnet核心,实际上是避免使用静态类,而仅仅依赖di来创建类和依赖项,而不需要服务提供者实例。

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

      1. 肖恩,你太棒了。感谢您的帮助,并向我展示了如何实现它。我很高兴有一个ASPNET核心专家。.

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

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

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

  4. 当然是作弊,但您可以使用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,因此您的建议不是一个选项。

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

  5. 你好,酷的文章。

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

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

    如果你查一下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)。我不知道为什么。我必须创建一个变通方法。

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

    公共静态IEnumerable AddRange(
    这个idbset数据库集,
    其中TEntity: class
    {
    返回((DbSet) DbSet) .AddRange (entitiesToAdd);
    }

    谢谢你所做的一切。

    杰夫

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

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

    但我认为至少消除您第一次使用“getservice”是安全的。在这里,seedit方法只需要一个ISeviceScopeFactory,它可以安全地注入到配置参数中。

    公共void配置(IApplicationBuilder应用程序,环境卫生部,ILoggerFactory loggerFactory,ISeviceScopeFactory服务ScopeFactory)

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

  8. 平回: net的博客

答复yabo官网取消回复

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

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