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

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

我给杰弗里·格罗森巴赫展示了一些英孚核心代码,当时我们正在谈论在我放松下来做一个更严肃的课程之前,在英孚核心上一个一个接一个的游戏来实现多元化。杰弗里查看了所有用于构建我的对象以种子数据库的代码,并说“哇,这是很多代码。你不能用JSON之类的吗?”(注意:我已经厌倦了在WordPress中对代码进行漂亮的格式化,但你明白了……对吗?)

private static list buildWeatherEvents()var events=new list weatherEvent.create(datetime.now,weatherType.sun,新名单
         
          新的[]“朱莉”,“哦,太阳光了!”})weatherEvent.create(datetime.now.adddays(-2),weatherType.rain),weatherEvent.create(datetime.now.adddays(-3),weatherType.sun,新名单
          
           新的[]“朱莉”,“哦,可爱的夏日阳光!太糟糕了,我在电脑上“,新的[]“佛蒙特州的每个人”,“万岁,我们去玩吧!”}“桑普森,”“我想去游泳,求求你!”}}weatherEvent.create(datetime.now.adddays(-4),weatherType.cloudy)weatherEvent.create(datetime.now.adddays(-5),weatherType.rain),weatherEvent.create(datetime.now.adddays(-6),weatherType.sun);var lastevent=weatherevent.create(datetime.now.adddays(-1),天气类型。雪,新名单
           
            新的[]“朱莉”,“雪?七月?好吧,这对VT来说也是荒谬的!”});lastevent.reactions.firstOrDefault().comments.add(new comment text=“get over it,朱莉!”(});事件。添加(lastevent);返回事件;}
           
          
         

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

我的域是weatherevent,它是我的efcore演示中的域,位于https://github.com/julielerman/efcore-aspnetcore-webapi-rtm,(我还没有更新它来演示如何使用JSON数据)。

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

[“日期”:“2016-07-27t00:00:00”,“time”:“22:09:13.8216230”,“类型”:5,“reactions”:[“name”:“朱莉”,“引述”:“哦,阳光明媚!”,“comments”:[]],“mostcommonword”:空,“日期”:“2016-07-25t00:00:00”,“time”:“22:09:13.8237230”,“类型”:1,“反应”:[],“mostcommonword”:空,“日期”:“2016-07-24t00:00:00”,“time”:“22:09:13.8238740”,“类型”:5,“reactions”:[“name”:“朱莉”,“引言”:“哦,可爱的夏日阳光!太糟糕了,我在我的电脑上“,“comments”:[],“name”:“佛蒙特州的每个人”,“引号”:“万岁,我们去玩吧!”,“comments”:[],“name”:“sampson”,“引言”:“我想去游泳,求求你!”,“comments”:[]],“mostcommonword”:空,“日期”:“2016-07-23t00:00:00”,“time”:“22:09:13.8239130”,“类型”:6,“反应”:[],“mostcommonword”:空,“日期”:“2016-07-22t00:00:00”,“time”:“22:09:13.8239210”,“类型”:1,“反应”:[],“mostcommonword”:空,“日期”:“2016-07-21t00:00:00”,“time”:“22:09:13.8239290”,“类型”:5,“反应”:[],“mostcommonword”:空,“日期”:“2016-07-26t00:00:00”,“time”:“22:09:13.8239360”,“类型”:2,“reactions”:[“name”:“朱莉”,“报价”:“雪?”七月?好吧,这对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.UMVC.();var datatext=system.io.file.readalltext(@“weatherdataset.json”);seeder.seedit(数据文本,app.applicationservices);
          }
         

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

使用系统;使用system.linq;使用system.collections.generic;使用Microsoft.Extensions.DependencyInjection;使用efcorewebapi;使用newtonsoft.json;使用jsonnet.privatesetterscontractresolvers;公共静态类seeder公共静态void seedit(string jsondata,iServiceProvider ServiceProvider)JSonserializerSettings settings=new JSonserializerSettings ContractResolver=new privateSetContractResolver()表
         
          事件=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)中没有构造函数。所以我得换个班。但是,我是否必须在启动时实例化seeder,然后使用服务以某种方式传递weatherContext实例?我遗漏了一些东西,因为我不知道如何神奇地将上下文实例获取到seeder类,而且它看起来更复杂(因为我不知道)。我知道你在悉尼国家数据中心,所以不急,但有趣和好奇。

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

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

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

  4. 很高兴看到这个解决方案的发展历程,因此我对ASP.NET核心中的DI和作用域有了更多的了解,谢谢!

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

    创建表协定(
    ConId int
    符号varchar(4…)

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

    从合同中选择*。

    1. 嗨,Nick,

      是的,作弊和老派,大声笑。它只在SQL Server中工作。我刚刚在一些单元测试中使用了这种技术。非常有帮助。我们正在使用PostgreSQL,因此您的建议不是一个选项。

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

  6. 你好,酷文章。

    几周前我发布了一个名为cherryseed的.NET库,您可以用它从任何源(csv,XMLGherkinSpecFlow等)到任何目的地。这是解决方案的下一步。

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

    如果你检查一下Cherryseed,问我你对图书馆的看法,那就太好了。

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

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

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

    公共静态IEnumerable AddRange(
    这个idbset数据库集,
    IEnumerable EntitiesToAdd)其中Tentity:类
    {
    返回((dbset)dbset).addrange(entitiestoadd);
    }

    谢谢你所做的一切。

    杰夫

  8. 朱莉再次感谢你。我正在实现IdentityServer4,并试图避免使用服务定位器模式。(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应用程序,环境卫生部,我的工厂日志工厂,ISeviceScopeFactory服务ScopeFactory)

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

  9. 今天在一个ASP.NET核心2.1 Web应用程序上使用了它,它运行得非常完美。

    谢谢你,朱莉

  10. Pingback: 网络博客

留下答复

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

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