ABP Framework:移除 EF Core Migrations 项目,统一数据上下文

原文:Unifying DbContexts for EF Core / Removing the EF Core Migrations Project[1]

导读:软件开发的一切都需要平衡

在 ABP Framework V4.4 RC 新增功能介绍 中,对应用程序启动解决方案模板做了一个重要改变:删除 EntityFrameworkCore.DbMigrations 项目。

本文将详细解读背后的原因和解决方案。

1.理解动机很重要:为什么先前的版本要将要数据上下文进行分离,而现在为什么要合并?2.合并之后存在什么缺陷,以及如何解决?

这篇文件演示如何将解决方案中 EntityFrameworkCore.DbMigrations 项目移除,并实现使用 单个 DbContext 进行数据实体映射数据迁移

本篇文章项目源码[3]

关注 ABP Framework 最新开发进度,后面还会陆续发布新功能详解新功能示例等系列文章,敬请关注! ABP Framework 研习社(QQ群:726299208) 专注 ABP Framework 学习,经验分享、问题讨论、示例源码、电子书共享,欢迎加入!

动机

如果使用启动模板生成解决方案,数据库提供程序是 Entity Framework Core,那么在解决方案中会存在依赖 EF Core的两个项目:

•.EntityFrameworkCore•.EntityFrameworkCore.DbMigrations

.EntityFrameworkCore项目:包含应用程序真实的 DbContext**、数据库映射仓储实现**。

.EntityFrameworkCore.DbMigrations项目:包含另一个 DbContext 只用于创建数据迁移。包含所有正在使用的模块的数据实体映射,生成统一的数据库表结构。

分离的原因有两个:

1.让真实 DbContext 保持简单和专注。只包含当前项目相关的实体,而与在应用程序使用的模块的实体和数据上下文无关,因为每个模块都有自己的 DbContext ,而将模型创建方法单独放在 EntityFrameworkCore.DbMigrations 项目中。2.复用依赖模块中的表,通过创建自己的类,映射到依赖模块中的表。举例,自定义 AppUser 实体映射到数据库中 AbpUsers 表,实际上该表由 Identity 模块[4] 的 IdentityUser 实体映射生成。他们共用相同的数据库表。和 IdentityServer 实体相比 AppUser 包含的属性更少,可以根据需要在 AppUser 中添加所需的属性,只需要设置好数据库映射,新增字段会添加到映射表中。

我们详细的描述了这种结构[5]。然而,对于开发者,仍然存在问题,因为当需要复用依赖模块中的表时,这种结构会使的数据实体映射变得复杂。

许多开发者在映射这些类时容易产生误解犯错,特别是当试图使用的实体与其他实体存在关联关系时。

所以我们在 V4.4 版本中决定取消这种分离,删除 EntityFrameworkCore.DbMigrations 项目。新的启动方案将带只有一个 EntityFrameworkCore 项目和一个 DbContext 类。

如果你想在你的解决方案中加入今天的内容,请遵循本文的步骤。

警告

新的设计有一个缺点。我们必须删除 AppUser 实体,因为不能在同一个 DbContext 中很好地处理没有继承关系的两个类映射到同一张表中。在本文的后面会介绍这个问题,并提供处理它的建议。

如果您使用 ABP Commercial 商业版,ABP套件代码生成功能还不会采用本文中提到的设计方法,建议等待下一个版本。

步骤

我们的目标是删除 EntityFrameworkCore.DbMigrations 项目,在 EntityFrameworkCore 项目中启用数据库迁移,替换迁移项目的依赖。

原解决方案是基于 v4.3 创建一个新的解决方案,然后在 pull request 中记录所有的修改,所以你可以逐行看到所有的修改。虽然这篇文章将涵盖所有的内容,但如果你在实现过程中遇到问题,你可能想检查这个PR中所做的修改[6]

第一步:添加 Microsoft.EntityFrameworkCore.Tools 包到 EntityFrameworkCore 项目

将下面代码添加到 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>

第二步:创建设计时 DbContext 工厂

在 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...DbSchemaMigrator(省略号表示项目命名)类到 EntityFrameworkCore 项目中,修改 MigrateAsync 方法中的代码,以使用真实 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 中包含 builder.ConfigureXXX() 对应每个使用的模块的数据实体映射配置。移动这些配置到 EntityFrameworkCore 项目的 真实 DbContext 中,并移除 AppUser 数据库实体映射。

可以选择将自己定义的实体数据库映射代码从...DbContextModelCreatingExtensions类中移到 真实 DbContext 的 OnModelCreating 方法中,并删除该静态扩展类。

示例解决方案中,最终 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 项目引用。

同样地,将模块依赖 ...EntityFrameworkCoreDbMigrationsModule 替换为 ...EntityFrameworkCoreModule 。

示例项目中,涉及的项目为 DbMigrator Web 和 Web and EntityFrameworkCore.Tests 。

第六步:移除 AppUser 实体

我们需要将 AppUser 这个实体移除,因为 EF Core 不能两个非继承关系的类映射到单个表。所以,删除这个类和所有的对该类的使用。如果你需要在应用程序代码中查询用户,可以用 IdentityUser 替换。更多信息请参见 AppUser 实体和自定义属性部分。

第七步:创建数据迁移

如果需要使用数据迁移历史记录,可以直接将 EntityFrameworkCore.DbMigrations 项目中生成的 migrations 复制到 EntityFrameworkCore 项目,并手动修改其中的 DbContext 类型。

如果需要在已经应用了数据迁移的数据库中,继续应用新的数据迁移,在 EntityFrameworkCore 项目中,创建新的数据库迁移,执行命令:

dotnet ef migrations add InitialUnified

你可以指定一个不同的迁移名称,这将创建一个迁移类,其中包含你在数据库中已有的所有数据库表。注意,删除 Up 和 Down 方法中的所有内容,然后就可以将迁移应用到数据库中。

dotnet ef database update

数据库不会有任何变化,因为迁移是空的,什么都不做。从现在开始,可以在改变实体时,创建新的迁移,就像平时做的那样。

DbContext 合并已经完成。接下来将解决如何基于这种设计为依赖模块的实体添加自定义属性

AppUser 实体 和自定义属性

数据库映射逻辑、解决方案结构和数据迁移,变得简单和易于管理。

带来的弊端是,我们必须移除 AppUser 实体,因为其与 Identity 模块中 IdentityUser 实体共享 AbpUsers 表。幸运的是,ABP提供了一个灵活的系统来 扩展现有的实体[7] ,如果你需要定义一些自定义属性的话。

在本节中,我将展示如何向 IdentityUser 实体添加一个自定义属性,并在你的应用程序代码和数据库查询中使用它。

我已经把这部分的所有修改作为一个单独的PR完成了,所以如果你在实现上有问题,你可能想检查这个PR中的修改[8]

定义一个自定义属性

应用程序启动模板提供一个配置点,为实体添加自定义属性,位于 Domain.Shared 项目中 ...ModuleExtensionConfigurator.cs 类,在 ConfigureExtraProperties 方法中,添加代码:

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

设置完成后,只要运行应用程序就可以看到用户表上的新属性。

新的SocialSecurityNumber属性也将在创建和编辑模式中应用添加的验证规则。

参看 模块实体扩展[9] 文档,理解和使用自定义属性。

映射到数据库表

ABP默认将所有自定义属性作为一个 Json 对象保存到 ExtraProperties 字段。如果要为自定义属性创建表字段,可以在 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

将在项目汇总添加一个新的数据迁移类,接着可以通过运行 .DbMigrator 应用或如下命令应用修改到数据库:

dotnet ef database update

将会在数据库 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");}
}

提示:使用 SetProperty 和 GetProperty 使用字符串属性名可能会很繁琐,而且容易出错。建议创建以下扩展方法:

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 来实现?有两种方式实现在应用程序中使用EF Core API:(这与自定义属性无关,与 EF Core有关。)

1.领域层或应用层引用 Microsoft.EntityFrameworkCore[10] Nuget包,在那个项目中引用取决于你要在哪需要使用 EF Core API。(DDD中数据提供程序无关性原则冲突)2.在领域层创建仓储接口,然后在 EntityFrameworkCore 项目中实现接口。

推荐使用第二种方式,在 Domain 项目中定义一个新的仓储接口:

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();}}
}

提示:应该使用一个常量代替SocialSecurityNumber魔术字符串。(不会产生拼写错误)

现在,我可以在应用服务中依赖注入 IMyUserRepository 使用仓储接口:

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);}
}

使用自定义仓储接口 IMyUserRepository 代替泛型仓储接口 IRepository<IdentityUser, Guid>

讨论 Github

这篇文章演示了,如何将 EntityFrameworkCore.DbMigrations 项目从解决方案中移除,以简化数据库实体映射、数据迁移和应用程序中的代码。

在下一个版本(4.4),将作为默认处理。

讨论:Consider to remove EntityFrameworkCore.DbMigrations project from the solution #8776[11]

References

[1] Unifying DbContexts for EF Core / Removing the EF Core Migrations Project: https://community.abp.io/articles/unifying-dbcontexts-for-ef-core-removing-the-ef-core-migrations-project-nsyhrtna
[2] ABP Framework V4.4 RC 新增功能介绍: https://www.cnblogs.com/YGYH/p/14973806.html
[3] 项目源码: https://github.com/abpframework/abp-samples/tree/master/UnifiedEfCoreMigrations
[4] Identity 模块: https://docs.abp.io/en/abp/latest/Modules/Identity
[5] 描述了这种结构: https://docs.abp.io/en/abp/latest/Entity-Framework-Core-Migrations
[6] 这个PR中所做的修改: https://github.com/abpframework/abp-samples/pull/88
[7] 扩展现有的实体: https://docs.abp.io/en/abp/latest/Module-Entity-Extensions
[8] 检查这个PR中的修改: https://github.com/abpframework/abp-samples/pull/89
[9] 模块实体扩展: https://docs.abp.io/en/abp/latest/Module-Entity-Extensions
[10] Microsoft.EntityFrameworkCore: https://www.nuget.org/packages/Microsoft.EntityFrameworkCore
[11] Consider to remove EntityFrameworkCore.DbMigrations project from the solution #8776: https://github.com/abpframework/abp/issues/8776

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

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

相关文章

Hello Python

2019独角兽企业重金招聘Python工程师标准>>> My first Python demo>>> movies["a","b","c"] >>> print(movies[0]) a >>> print(movies[1]) b >>> >>> print(movies) [a, b, c…

牛顿儿时成绩很差,5岁开始接触物理,也许是他如此伟大的唯一原因!

全世界只有3.14 % 的人关注了青少年数学之旅我们都知道&#xff0c;牛顿是伟大的物理学家&#xff0c;但是也许很多人不知道&#xff0c;牛顿也是平常的孩子&#xff0c;他不是神童&#xff0c;成绩很一般。那牛顿是如何成为如此伟大的物理学家的呢&#xff1f;原来&#xff0c…

C语言数据结构----递归的应用(斐波拉契数列、汉诺塔、strlen的递归算法)

本节主要说了递归的设计和算法实现&#xff0c;以及递归的基本例程斐波拉契数列、strlen的递归解法、汉诺塔和全排列递归算法。 一、递归的设计和实现 1.递归从实质上是一种数学的解决问题的思维&#xff0c;是一种分而治之的思想。 这个是常见的一种数学算法&#xff0c;其实它…

【物理动图】物理老师一针见血:50张动图看懂高中物理

全世界只有3.14 % 的人关注了青少年数学之旅相互作用作用力与反作用力的特点是什么&#xff1f;摩擦力的大小跟什么有关系&#xff1f;图中两个弹簧的弹力大小是否一样&#xff1f;若一样&#xff0c;为什么&#xff1f;自行车前后轮所受力的方向是什么&#xff1f;物块所受支持…

打造史上最小尺寸.Net Core单文件应用程序

.Net Core支持将应用程序发布成单文件进行部署和分发。以下示例将Windows应用作为独立的单文件应用程序发布&#xff1a;dotnet publish -r win-x64 -c Release /p:PublishSingleFiletrue /p:PublishTrimmedtrue /p:IncludeNativeLibrariesForSelfExtracttrue查看publish目录&a…

华硕路由器 linux上不了网,华硕ASUS路由器连不上网怎么办?

在本文中将给大家详细的介绍&#xff0c;华硕(ASUS)路由器连不上网/无法上网的解决办法&#xff0c;请按照下面的步骤进行操作。1. 首先&#xff0c;检查你的宽带是否可以正常使用&#xff0c;可以通过下面的方法进行测试。(1)观察光猫上的指示灯&#xff0c;如果光信号或者LOS…

NHibernate学习笔记(二):one-to-one关系映射

上一篇&#xff1a;NHibernate学习笔记&#xff08;一&#xff09;&#xff1a;初识NHibernate本文的内容&#xff1a;&#xff11;&#xff0e;介绍NH如何处理对象间one-to-ont的映射关系&#xff1b;经验教训&#xff1a;&#xff11;&#xff0e;操作一对一关联关系中的一个…

【汇总】多种方法教你绕过 TPM 2.0 安装 Windows 11 操作系统

此前我们曾介绍三种方法绕过 TPM 2.0 来安装 Windows 11 操作系统。方法一&#xff1a;删除 appraiserres.dll 文件方法二&#xff1a;替换 appraiserres.dll 文件方法三&#xff1a;替换 install.wim 文件今儿我们再谈谈“大法好”的注册表&#xff0c;希望能帮助大家成功安装…

【物理笑话】学过物理的人才能看懂的笑话,你能看明白几个?

全世界只有3.14 % 的人关注了青少年数学之旅1丈夫买了几斤廉价藕&#xff0c;满以为可对妻子炫耀了。不料妻子破口大骂&#xff1a;笨蛋&#xff01;为何不买别的菜&#xff0c;这藕一斤少说也有半斤窟窿啊&#xff01;还说便宜&#xff1f;2第一次坐飞机的两位老妇人在飞机起飞…

为什么国外程序员加班少?他们这样评价国内996和技术公众号

有人统计过&#xff0c;我们平均每天花在看内容上的时间是5-6小时与其每天被各种看过就忘的内容占据时间不如看点真正对你有价值的信息下面小编为你推荐几个高价值的公众号它们提供的信息能真正提高你生活的质量长按二维码&#xff0c;选择【识别图中二维码】关注Python爱好者社…

c语言编程每日一练教程,每日一练 | C语言之指针

原标题&#xff1a;每日一练 | C语言之指针练习导言学习 C 语言的指针既简单又有趣。通过指针&#xff0c;可以简化一些 C 编程任务的执行&#xff0c;还有一些任务&#xff0c;如动态内存分配&#xff0c;没有指针是无法执行的。所以&#xff0c;想要成为一名优秀的 C 程序员&…

dynamic flash xml news----滚动新闻

今天有人问起这个问题&#xff0c;抽出晚上的一点时间&#xff0c;做了一个&#xff0c;时间紧难免有不足之处&#xff0c;如果发现bug&#xff0c;请以在贴出。演示&#xff1a;代码&#xff1a;代码://copyright by webstudio.com.cn 2005-4-7 system.useCodepagetrue; Stage…

C# 代码生成二维码方法及代码示例(QRCoder)

背景二维码是越来越流行了&#xff0c;很多地方都有可能是使用到。如果是静态的二维码还是比较好处理的&#xff0c;通过在线工具就可以直接生成一张二维码图片&#xff0c;比如&#xff1a;草料二维码。但有的时候是需要动态生成的&#xff08;根据动态数据生成&#xff09;&a…

你对手机打字一无所知!| 今日最佳

全世界只有3.14 % 的人关注了青少年数学之旅&#xff08;视频源网络&#xff0c;侵权删&#xff09;你真的会打字吗↓ ↓ ↓

并行中的分区Partitioner

本篇介绍在C#中&#xff0c;把一个大集合&#xff0c;或大数组分成若干个区来执行。Demo中是把一组字符串放在list中&#xff0c;然后并行生成MD5串&#xff0c;返回回来。using System; using System.Collections.Generic; using System.Reflection; using System.Threading.T…

搞笑诺贝尔颁出,中国科学家入选!阿蟑有磁性、睾丸热不对称,10大奇葩研究来了...

全世界只有3.14 % 的人关注了青少年数学之旅Laugh and think&#xff0c;科学的另一面&#xff0c;就是有趣&#xff01;——在今天的哈佛大学桑德斯剧场&#xff0c;一群科学家身体力行地证明了这件事&#xff0c;在诺贝尔奖颁出前夕&#xff0c;率先发布了今年的“搞笑诺贝尔…

C++中的对象数组

类是对象的抽象&#xff0c;我们可以使用一个类来定义很多的对象&#xff0c;然后每个对象都有自己的属性。 当我们使用类来定义很多相同结构的对象的时候&#xff0c;我们可以采取对象数组的方法。 例如&#xff0c;一个班有50个学生&#xff0c;我们定义了一个学生类&#xf…

周杰伦新歌《说好不哭》彩蛋大汇总! | 今日最佳

全世界只有3.14 % 的人关注了青少年数学之旅一首单曲&#xff0c;就霸占了一半的微博热搜榜&#xff0c;除了周杰伦&#xff0c;估计也没别人能做得到了。回想起前段时间&#xff0c;周杰伦的中老年粉丝与ikun们围绕着“顶级流量”展开的那场battle...说实话&#xff0c;那场 b…

AI日报:2024年人工智能对各行业初创企业的影响

欢迎订阅专栏 《AI日报》 获取人工智能邻域最新资讯 文章目录 2024年人工智能对初创企业的影响具体行业医疗金融服务运输与物流等 新趋势 2024年人工智能对初创企业的影响 2023年见证了人工智能在各个行业的快速采用和创新。随着我们步入2024年&#xff0c;人工智能初创公司正…

Ant Design Blazor 组件库的路由复用多标签页介绍

前言Blazor 是 .NET 最新的前端框架&#xff0c;可以基于 WebAssembly 或 SignalR &#xff08;WebSocket&#xff09;构建前端应用程序&#xff0c;基于 WebAssembly 托管模型的 Blazor 甚至可以离线运行。再加上可以共用 .NET 类库&#xff0c;能使代码量比以往的基于 JS 的前…