ABP Vnext 4.4:统一Ef Core的DbContext/移除EF Core Migrations项目

Abp vnext 4.4出现了一个比较重大的变更:在Startup template中移除了EF Core Migrations项目,本文翻译自community.abp.io/articl

由于本文发布的时候Abp vnext的版本还没有到4.4,所以本文演示了如何从4.4以前的版本移除EntityFrameworkCore.DbMigrations这个项目,并且使用唯一的一个DbContext来进行数据库的映射和基于Code-First模式的迁移。

该项目的github地址如下:github.com/abpframework

动机/背景

如果你使用Ef core作为数据库provider创建一个解决方案,那么会有两个与ef core有关的项目:

EntityFrameworkCore这个项目包含了你的应用的真正的DbContext,它包含了所有的数据库映射和你的Repository的实现。

另一方面,EntityFrameworkCore.DbMigrations 项目包含了另一个DbContext用来创建和施行数据库迁移。它包含了你所使用的所有模块的数据库映射,所以你有一个单独并统一的数据库架构/方案。

当时这么做主要有两个原因:

  1. 你真正的DbContext保持了简单和集中(focused)。它只包含了你自己应用中的实体相关的内容并且不包含你所使用的关于其他模块的内容。

  2. 你可以创建自己的类,映射到依赖模块的表。例如,AppUser实体(包含在下载的解决方案中)映射到数据库中的AbpUsers表,而AbpUsers表实际上映射到Identity Module的IdentityUser实体。这意味着它们共享相同的数据库表。与IdentityServer相比,AppUser包含的属性更少。您只添加您需要的属性,而不是更多。这还允许您根据自定义需求向AppUser添加新的标准(类型安全)属性,只要您仔细地管理数据库映射。

对于这个方面的说明我们在官方的文档中有详细的说明。然而,当你重用那些你依赖的模块的表时,会存在一些问题,那就是这样的架构会导致你的数据库映射变得复杂。许多开发者在做一些诸如映射这些类/实体的工作时,会变得迷茫和犯错,特别是当他们想要将这些实体和其他实体联系起来时。

所以,我们决定在4.4的版本中取消这种分离,删除EntityFrameworkCore.DbMigrations这个项目。新版本的abp vnext中将只包含EntityFrameworkCore这个项目并且只拥有一个DbContext。

如果你今天就想尝试这么干,请接着往下看。

警告

新的设计有一个缺点(软件开发中的一切都是一种权衡)。我们需要删除AppUser实体,因为EF Core不能在没有继承关系的情况下将两个类映射到单个表。我将在本文后面介绍这一点,并提供处理它的建议。

步骤

我们的目标是在EntityFrameworkCore项目中启用数据库迁移,移除EntityFrameworkCore.DbMigrations项目并根据该包重新访问代码。

第一步:为EntityFrameworkCore添加Microsoft.EntityFrameworkCore.Tools包

在EntityFrameworkCore.csproj文件中添加如下代码:

<ItemGroup><PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.*"><IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets><PrivateAssets>compile; contentFiles; build; buildMultitargeting; buildTransitive; analyzers; native</PrivateAssets></PackageReference>
</ItemGroup>

第二步,创建design time DbContext factory

在EntityFrameworkCore项目中创建一个实现了IDesignTimeDbContextFactory<T>的类:

using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;namespace UnifiedContextsDemo.EntityFrameworkCore
{public class UnifiedContextsDemoDbContextFactory : IDesignTimeDbContextFactory<UnifiedContextsDemoDbContext>{public UnifiedContextsDemoDbContext CreateDbContext(string[] args){UnifiedContextsDemoEfCoreEntityExtensionMappings.Configure();var configuration = BuildConfiguration();var builder = new DbContextOptionsBuilder<UnifiedContextsDemoDbContext>().UseSqlServer(configuration.GetConnectionString("Default"));return new UnifiedContextsDemoDbContext(builder.Options);}private static IConfigurationRoot BuildConfiguration(){var builder = new ConfigurationBuilder().SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../UnifiedContextsDemo.DbMigrator/")).AddJsonFile("appsettings.json", optional: false);return builder.Build();}}
}

这些代码基本上是从EntityFrameworkCore.DbMigrations这个项目中粘贴过来的,重命名了一下并且将里面的DbContext替换成了EntityFrameworkCore项目中的那个DbContext。

第三步,创建数据库方案迁移类

将EntityFrameworkCore...DbSchemaMigrator(...代表了你项目的名字)类复制到EntityFrameworkCore项目下,并且将其中的DbContext替换成EntityFrameworkCore项目中的那个真正的DbContext,在我的示例项目中,代码是这样的:

using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using UnifiedContextsDemo.Data;
using Volo.Abp.DependencyInjection;namespace UnifiedContextsDemo.EntityFrameworkCore
{public class EntityFrameworkCoreUnifiedContextsDemoDbSchemaMigrator: IUnifiedContextsDemoDbSchemaMigrator, ITransientDependency{private readonly IServiceProvider _serviceProvider;public EntityFrameworkCoreUnifiedContextsDemoDbSchemaMigrator(IServiceProvider serviceProvider){_serviceProvider = serviceProvider;}public async Task MigrateAsync(){/* We intentionally resolving the UnifiedContextsDemoMigrationsDbContext* from IServiceProvider (instead of directly injecting it)* to properly get the connection string of the current tenant in the* current scope.*/await _serviceProvider.GetRequiredService<UnifiedContextsDemoDbContext>().Database.MigrateAsync();}}
}

第四步,转移模块的配置

迁移DbContext(在迁移项目中定义的那个DbContext)通常包含你使用的每个模块的builder.ConfigureXXX()这样的代码行。我们可以将这些行移动到EntityFrameworkCore项目中的实际DbContext中。另外,删除AppUser的数据库映射(我们将删除这个实体)。或者,你可以将你自己的实体的数据库映射代码从… DbContextModelCreatingExtensions类放在实际DbContext的OnModelCreating方法中,并删除静态扩展类。

注:上文提到的AppUser数据库映射这些代码是包含在EntityFramworkCore的DbContext中,具体如下:

   /* Configure the shared tables (with included modules) here */builder.Entity<AppUser>(b =>{b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "Users"); //Sharing the same table "AbpUsers" with the IdentityUserb.ConfigureByConvention();b.ConfigureAbpUser();/* Configure mappings for your additional properties* Also see the BlazorEfCoreEntityExtensionMappings class*/});

最终修改后的DbContext是下面这个样子的:

using Microsoft.EntityFrameworkCore;
using UnifiedContextsDemo.Users;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.IdentityServer.EntityFrameworkCore;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TenantManagement.EntityFrameworkCore;namespace UnifiedContextsDemo.EntityFrameworkCore
{[ConnectionStringName("Default")]public class UnifiedContextsDemoDbContext: AbpDbContext<UnifiedContextsDemoDbContext>{public DbSet<AppUser> Users { get; set; }/* Add DbSet properties for your Aggregate Roots / Entities here.* Also map them inside UnifiedContextsDemoDbContextModelCreatingExtensions.ConfigureUnifiedContextsDemo*/public UnifiedContextsDemoDbContext(DbContextOptions<UnifiedContextsDemoDbContext> options): base(options){}protected override void OnModelCreating(ModelBuilder builder){base.OnModelCreating(builder);builder.ConfigurePermissionManagement();builder.ConfigureSettingManagement();builder.ConfigureBackgroundJobs();builder.ConfigureAuditLogging();builder.ConfigureIdentity();builder.ConfigureIdentityServer();builder.ConfigureFeatureManagement();builder.ConfigureTenantManagement();/* Configure your own tables/entities inside here *///builder.Entity<YourEntity>(b =>//{//    b.ToTable(UnifiedContextsDemoConsts.DbTablePrefix + "YourEntities", UnifiedContextsDemoConsts.DbSchema);//    b.ConfigureByConvention(); //auto configure for the base class props//    //...//});}}
}

第五步,从解决方案中移除EntityFrameworkCore.DbMigrations 项目

将EntityFrameworkCore.DbMigrations移除并且将一切引用该项目替换为引用EntityFrameWorkCore项目。

同时,EntityFrameworkCore.DbMigrations项目的作用现在也变更为了EntityFrameworkCore项目。

在这个例子中,我需要将DbMigrator,WebEntityFrameworkCore.Tests 这三个项目的对EntityFrameworkCore.DbMigrations的引用变更为EntityframeworkCore项目。

第六步,删除AppUser实体类

你需要删除AppUser实体类,因为Abp没有办法在两个没有继承关系的类上面映射同一张表。

所以应该删除它以及和他相关的内容,如果你要查询有关用户的内容,你应该用IdentityUser来代替。可以在官方文档中查看与自定义属性和AppUser相关的内容。

第七步,创建或者移动迁移内容

现在我们已经删除了EntityFrameworkCore.DbMigrations项目。接下来我们要考虑关于数据库迁移的事情了。如果你要保持数据库的迁移历史,你需要从EntityFrameworkCore.DbMigrations项目吧Migrations目录中的内容拷贝到EntityFrameworkCore,并且将内容中的DbContext手工的替换为EntityFrameworkCore项目中定义的DbContext。

另一种做法是清除项目中的迁移历史,并在数据库中的已提交的迁移历史上继续,那你需要做的是在EntityFrameworkCore项目中创建一个数据库迁移,并在该项目的根目录下面执行下面的命令:

dotnet ef migrations add InitialUnified

你无疑需要为这个迁移命令起一个全新的名字,这个迁移肯定会生成一堆内容,你需要小心的将Up和Down这两个方法中的内容全部删除,然后就可以将这个迁移(实际上是一个空的迁移)应用到数据库了:

dotnet ef database update

这个操作不会对数据库造成任何更改,毕竟你已经将Up和Down方法里面的内容全删除了。接下来,你就可以像平常一样进行接下来的操作了。

AppUser 实体和自定义扩展属性

现在数据库映射逻辑、解决方案结构、迁移以及我们接下来要做的事情变得更简单了。

作为缺点来说,我们需要删除AppUser实体,它和Identity Module中定义的IdentityUser共享了数据库中的同一张表。幸运的是,当你需要在已存在的实体上(比如Identity module中定义的IdentityUser)增加一些自定义的属性时,Abp提供了一个相当灵活的系统。在这一节中,我将演示如何在IdentityUser上面增加一些自定义的属性,并在程序编码和数据库查询上应用这些自定义的字段。

关于这些内容我已经作为单独的pr发布到github上,你可以点击这个链接进行查看:

https://github.com/abpframework/abp-samples/pull/89github.com

声明一个自定义的属性

启动模板中有一个关于在已存在实体上自定义属性的入口,这个入口在Domain.Share项目下面,...ModuleExtensionConfigurator.cs(...代表你项目的名称)这个文件中。打开这个文件并在ConfigureExtraProperties方法中下如下代码:

ObjectExtensionManager.Instance.Modules().ConfigureIdentity(identity =>{identity.ConfigureUser(user =>{user.AddOrUpdateProperty<string>( //property type: string"SocialSecurityNumber", //property nameproperty =>{//validation rulesproperty.Attributes.Add(new RequiredAttribute());property.Attributes.Add(new StringLengthAttribute(64));});});}); 

完事儿后,运行程序并在User table上面你可以看到这个属性:

新的SocialSecurityNumber属性也会在创建和更新Modal中显示并应用校验规则。查看如下链接了解关于扩展属性的一切信息:

https://docs.abp.io/en/abp/latest/Module-Entity-Extensionsdocs.abp.io

映射到数据库表

默认情况下,Abp将所有自定义的属性保存在数据库表中的ExtraProperties属性上,作为一个JSON保存 。如果你想要将自定义的字段作为单独的表字段保存,你需要在EntityFrameworkCore项目中定义的...EfCoreEntityExtensionMappings.cs文件(...代表你项目的名字)上进行编码定义(在OneTimeRunner.Run方法中):

ObjectExtensionManager.Instance.MapEfCoreProperty<IdentityUser, string>("SocialSecurityNumber",(entityBuilder, propertyBuilder) =>{propertyBuilder.HasMaxLength(64).IsRequired().HasDefaultValue("");});

这个完事儿后,你需要定义新的数据库迁移方案,将你的新扩展的属性进行迁移(在EntityframeworkCore项目下):

dotnet ef migrations add Added_SocialSecurityNumber_To_IdentityUser

这会在EntityframeworkCore项目下面新增一个迁移文件,然后你要将这个迁移应用到数据库:

dotnet ef database update

你也可以运行.DbMigrator项目来应用迁移,这个项目的作用就在于此。

这会在数据库AbpUsers表上创建一个SocialSecurityNumber字段。

在应用程序代码中使用自定义字段

现在,我们可以在IdentityUser实体上使用GetProperty和SetProperty这两个方法来使用我们自定义的属性:

public class MyUserService : ITransientDependency
{private readonly IRepository<IdentityUser, Guid> _userRepository;public MyUserService(IRepository<IdentityUser, Guid> userRepository){_userRepository = userRepository;}public async Task SetSocialSecurityNumberDemoAsync(string userName, string number){var user = await _userRepository.GetAsync(u => u.UserName == userName);user.SetProperty("SocialSecurityNumber", number);await _userRepository.UpdateAsync(user);}public async Task<string> GetSocialSecurityNumberDemoAsync(string userName){var user = await _userRepository.GetAsync(u => u.UserName == userName);return user.GetProperty<string>("SocialSecurityNumber");}
} 
上面的代码中我们使用了”SocialSecurityNumber“硬编码来直接调用,更好的做法是我们可以定义一些扩展方法来包装这种调用。

下面我们改进这种做法:

public static class MyUserExtensions
{public const string SocialSecurityNumber = "SocialSecurityNumber";public static void SetSocialSecurityNumber(this IdentityUser user, string number){user.SetProperty(SocialSecurityNumber, number);}public static string GetSocialSecurityNumber(this IdentityUser user){return user.GetProperty<string>(SocialSecurityNumber);}
}

定义后扩展方法后,我们改进一开始的那种调用:

public async Task SetSocialSecurityNumberDemoAsync(string userName, string number)
{var user = await _userRepository.GetAsync(u => u.UserName == userName);user.SetSocialSecurityNumber(number); //Using the new extension propertyawait _userRepository.UpdateAsync(user);
}public async Task<string> GetSocialSecurityNumberDemoAsync(string userName)
{var user = await _userRepository.GetAsync(u => u.UserName == userName);return user.GetSocialSecurityNumber(); //Using the new extension property
}

自定义属性的查询

你可能会基于自定义的属性做一些查询,我们会使用Entity Framework的API来完成,基于此,我们这里给出两个解决方案:

1、引用Microsoft.EntityFrameworkCore包到你的项目中(Domain项目或者Application项目,具体看你的需求)。

2、在Domain中创建一个repository接口,并在EntityFrameworkCore项目中实现它。

我更倾向于第二个方案,所以我在repository接口中定义一些方法先:

using System;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;namespace UnifiedContextsDemo.Users
{public interface IMyUserRepository : IRepository<IdentityUser, Guid>{Task<IdentityUser> FindBySocialSecurityNumber(string number);}
} 

然后在EntityframeworkCore项目中实现它:

using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using UnifiedContextsDemo.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Identity;namespace UnifiedContextsDemo.Users
{public class MyUserRepository: EfCoreRepository<UnifiedContextsDemoDbContext, IdentityUser, Guid>,IMyUserRepository{public MyUserRepository(IDbContextProvider<UnifiedContextsDemoDbContext> dbContextProvider): base(dbContextProvider){}public async Task<IdentityUser> FindBySocialSecurityNumber(string number){var dbContext = await GetDbContextAsync();return await dbContext.Set<IdentityUser>().Where(u => EF.Property<string>(u, "SocialSecurityNumber") == number).FirstOrDefaultAsync();}}
}
注意:使用一个常量而不是字符串硬编码来搞这样更好一些。

现在,我们可以在Service里面注入repository来使用了:)

public class MyUserService : ITransientDependency
{private readonly IMyUserRepository _userRepository;public MyUserService(IMyUserRepository userRepository){_userRepository = userRepository;}//...other methodspublic async Task<IdentityUser> FindBySocialSecurityNumberDemoAsync(string number){return await _userRepository.FindBySocialSecurityNumber(number);}
}

总结

这篇文章描述了如何删除EntityFrameworkCore.DbMigrations项目来简化你的数据库映射、数据库迁移以及应用程序编码。在4.4这个版本中,我们已经在启动模板中移除了这个项目了。

源码

https://github.com/abpframework/abp-samples/tree/master/UnifiedEfCoreMigrations

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/299945.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

史上最变态高考数学题,让99%的考生献上膝盖,看完我惊了......

全世界只有3.14 %的人关注了青少年数学之旅今天超模君想问大家一个问题&#xff1a;如果在撒哈拉大沙漠或者是西伯利亚上建造一个大型装置&#xff0c;以便向地球之外的其他星球的朋友们表明地球上存在有智慧的生命&#xff0c;最适当的装置是什么呢&#xff1f;勾股定理&#…

C#操作Excel文件暨C#实现在Excel中将连续多列相同数据项合并

C#操作Excel文件(读取Excel&#xff0c;写入Excel) 看到论坛里面不断有人提问关于读取excel和导入excel的相关问题。闲暇时间将我所知道的对excel的操作加以总结&#xff0c;现在共享大家&#xff0c;希望给大家能够给大家带了一定的帮助。另外我们还要注意一些简单的问题1.exc…

猪肉上的红章和蓝章有啥不同?| 今日趣图

全世界只有3.14 %的人关注了青少年数学之旅亲眼看到金字塔你才会意识到它有多大&#xff01;&#xff08;图源光消失的地方&#xff0c;侵权删&#xff09;你女朋友的脸皮有多厚&#xff1f;&#xff08;图源程序员新视界&#xff0c;侵权删&#xff09;猪肉上的红章和蓝章有啥…

如何避免和人尬聊?

全世界只有3.14 %的人关注了青少年数学之旅想要和别人有聊不完的话题&#xff1f;当然是多读书多看新闻了解新鲜有趣的事物啦如果你没有时间去阅读那么关注以下公号将会让你收获更多信息~长按二维码&#xff0c;选择“识别图中二维码”订阅。▼看鉴ID:kanjian6666▲长按二维码“…

java 中的 io 系统总结

Java 流在处理上分为字符流和字节流。字符流处理的单元为 2 个字节的 Unicode 字符&#xff0c;分别操作字符、字符数组或字符串&#xff0c;而字节流处理单元为 1 个字节&#xff0c;操作字节和字节数组。 Java 内用 Unicode 编码存储字符&#xff0c;字符流处理类负责将外部的…

在VS Code中执行SQL查询,是怎样一种体验?

上次&#xff0c;我们演示了“如何使用Nuget包XPlot.Plotly.Interactive在.NET Interactive notebook中绘制图表”。这次&#xff0c;我们使用Nuget包Microsoft.DotNet.Interactive.SqlServer演示在.NET Interactive notebook中如何和SQL Server交互。安装Nuget包首先&#xff…

UVA 11090 Going in Cycle!! 二分答案 + bellman-ford

求平均值最小的环&#xff0c;如果平均值最小为x&#xff0c;则如果把每条边的权值都减(x1)&#xff0c;那么新图将会有负环&#xff0c;用bellman ford判断。 //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstri…

大数据:数据合集,你想要的或许这里都有

大数据时代&#xff0c;用数据做出理性分析显然更为有力。做数据分析前&#xff0c;能够找到合适的的数据源是一件非常重要的事情&#xff0c;获取数据的方式有很多种&#xff0c;不必局限。下面将从公开的数据集、爬虫、数据采集工具、付费API等等介绍。给大家推荐一些能够用得…

MVC5 - ASP.NET Identity登录原理 - Claims-based认证和OWIN

在Membership系列的最后一篇引入了ASP.NET Identity&#xff0c;看到大家对它还是挺感兴趣的&#xff0c;于是来一篇详解登录原理的文章。本文会涉及到Claims-based&#xff08;基于声明&#xff09;的认证&#xff0c;我们会详细介绍什么是Claims-based认证&#xff0c;它与传…

一步一步SharePoint 2007之四十三:实现自定义Workflow(2)——设置配置文件

下面将记录每一步的操作过程。1、首先采用Reflector等工具找到上一篇文章编译后的DLL的Assembly信息。2、找到并打开C:\Inetpub\wwwroot\wss\VirtualDirectories\9001\web.config文件&#xff0c;在System.Workflow.ComponentModel.WorkflowCompiler节点下的authorizedTypes中&…

动手造轮子 —— dotnet-HTTPie

动手造轮子 —— dotnet-HTTPieIntroHTTPie 是一个基于 Python 的 HTTP CLI 工具&#xff0c;这也意味着想用 HTTPie 就需要安装 Python 环境&#xff0c;不想装 Python 环境&#xff0c;于是想用 C# 也写一个类似的东西&#xff0c;HTTPie 的语法很简单、简洁而且功能强大&…

减肥瘦不下来的原因找到了

全世界只有3.14 %的人关注了青少年数学之旅&#xff08;图源蜻蜓队长&#xff0c;侵权删&#xff09;

大数据、java、python、区块链、人工智能哪个发展前景更好?

在这个信息时代高速发展的情况下&#xff0c;很多人会对自己该往哪个方向发展感到迷茫&#xff0c;下面我就浅显的给大家介绍一下五大流行区域的发展前景。 大数据的发展前景&#xff1a; 当前大数据行业真的是人才稀缺吗? 学了几年后&#xff0c;大数据行业会不会产能过剩…

2020年CNCF和开源项目开发速度

作者&#xff1a;Chris Aniszczyk回到 2017 年&#xff0c;我们洞察[1]了当时速度&#xff08;velocity&#xff09;最高的 30 个开源项目&#xff0c;结果非常有趣。今年&#xff0c;我们想看看 CNCF 的项目速度&#xff0c;以及 2020 年速度最高的 30 个开源项目。此外&#…

automation服务不能创建对象

automation服务器不能创建对象 昨天开机打开Visual Studio.Net&#xff0c;准备新建一个项目&#xff0c;却发生一件奇怪的事情&#xff0c;系统报告“automation服务器不能创建对象”错误。然后在解决方案中只见项目名&#xff0c;而不见项目文件了。真是奇怪。再尝试打开已有…

又一中国机械狗来了:腾跃呼啦圈、原地起跳顶飞皮球,还能自主充电

全世界只有3.14 %的人关注了青少年数学之旅哇这是什么情况竟然腾空后跳过了呼啦圈这是刚刚升级的新机械狗说起机械狗其实浙江大学也搞了一只名叫“绝影”就是刚才咱们看到的那只绝影也迭代好几次了说白了就是一代一代的升级了上楼梯、跑步都是稳如狗退也退的潇洒这只机械狗确切…

Http协议Get方式获取图片

一、 二、 我试了试&#xff0c;Post方式也行啊&#xff0c;干嘛要叫强调Get方式&#xff0c;费解~~ 答曰&#xff1a;get是向服务器请求数据&#xff0c;post是提交数据。 三、 package com.hpu.test;import java.io.FileOutputStream; import java.io.IOException; import ja…

2018最新大数据职业划分和薪资介绍(大数据从事者须知)

相信接触大数据这个行业的人都知道大数据这个行业涉及很广泛&#xff0c;那么相应的也有很多职业诞生出 来&#xff0c;很多刚刚接触大数据的不知道该往哪方面发展&#xff0c;下面我就给大家介绍一下大数据行业的职业规划。 数据管理类 1&#xff0c;首席数据官 2&#xff…

dotnet 是 前30个增长最快速度的开源项目中排名第一的开发平台

CNCF 的博客 发了一篇文章 《Update on CNCF and Open Source Project Velocity 2020》&#xff0c;中文翻译参见 2020年CNCF和开源项目开发速度, 这个数据在2017年发布过一次&#xff0c;这次是3年来的再次更新的数据&#xff0c;往后每6个月就会更新一次数据-open source pro…

装了卡巴后VS 2003不能启动调试错误的解决方案

机器上同时安装vs2003和 vs2005 vs2005能调试&#xff0c;vs2003不能调试 &#xff0c;提示不在Debug Users权限组 经过一周时间的分析查找&#xff0c;知道问题原因 是ie浏览器的安全设置的问题&#xff0c;没有把当前用户信息带到IIS中。 一定是http://localhost,不能是local…