EF Core 6 新功能汇总(三)

在这篇文章中,我将重点介绍 EF Core 6 中 LINQ 查询功能的增强。

这是 EF Core 6 新功能汇总的第三篇文章:

  • EF Core 6 新功能汇总(一)

  • EF Core 6 新功能汇总(二)

  • EF Core 6 新功能汇总(三)

1对 GroupBy 查询的更好支持

EF Core 6.0 对 GroupBy 查询有更好的支持。

  • 翻译 GroupBy 后面的 FirstOrDefault

  • GroupBy 之后使用 ThenBy

  • 支持从一个组中选择前 N 个结果

using var context = new ExampleContext();
var query = context.People.GroupBy(p => p.FirstName).Select(g => g.OrderBy(e => e.FirstName).ThenBy(e => e.LastName).FirstOrDefault()).ToQueryString();
Console.WriteLine(query);class Person
{public int Id { get; set; }public string FirstName { get; set; }public int LastName { get; set; }
}
class ExampleContext : DbContext
{public DbSet<Person> People { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6GroupBy");
}

翻译后的 SQL:

SELECT[t0].[Id], [t0].[FirstName], [t0].[LastName]
FROM (
SELECT[p].[FirstName]FROM [People] AS [p]GROUP BY [p].[FirstName]
) AS[t]
LEFT JOIN(SELECT[t1].[Id], [t1].[FirstName], [t1].[LastName]FROM (SELECT[p0].[Id], [p0].[FirstName], [p0].[LastName],ROW_NUMBER() OVER(PARTITION BY [p0].[FirstName]ORDER BY [p0].[FirstName], [p0].[LastName]) AS[row]FROM[People] AS[p0]) AS[t1]WHERE[t1].[row] <= 1
) AS[t0] ON[t].[FirstName] = [t0].[FirstName]

2三四个参数的 String.Concat 翻译

以前 EF Core 翻译 string.Concat 时只有两个参数。EF Core 6.0 支持翻译三个和四个参数的 string.Concat

using var context = new ExampleContext();
string fullName = "SamuelLanghorneClemens";
var query = context.Blogs.Where(b => string.Concat(b.FirstName, b.MiddleName, b.LastName) == fullName).ToQueryString();
Console.WriteLine(query);class Blog
{public int Id { get; set; }public string FirstName { get; set; }public string MiddleName { get; set; }public string LastName { get; set; }
}
class ExampleContext : DbContext
{public DbSet<Blog> Blogs { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6StringConcat");
}

翻译后的 SQL:

DECLARE @__fullName_0 nvarchar(4000) = N'SamuelLanghorneClemens';SELECT[b].[Id], [b].[FirstName], [b].[LastName], [b].[MiddleName]
FROM[Blogs] AS[b]
WHERE(COALESCE([b].[FirstName], N'') + (COALESCE([b].[MiddleName], N'') +COALESCE([b].[LastName], N ''))) = @__fullName_0

3EF.Functions.FreeText 支持二进制列

以前,尽管 SQL FreeText 函数支持二进制列,但你不能在二进制列上使用 EF.Functions.FreeText 方法。EF Core 6.0 解决了这个问题。

using var context = new ExampleContext();
var query = context.Posts.Where(p => EF.Functions.FreeText(EF.Property<string>(p, "Content"), "Searching text")).ToQueryString();
Console.WriteLine(query);class Post
{public int Id { get; set; }public string Title { get; set; }public byte[] Content { get; set; }
}
class ExampleContext : DbContext
{public DbSet<Post> Posts { get; set; }protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<Post>().Property(x => x.Content).HasColumnType("varbinary(max)");}protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6FlexibleTextSearch");
}

翻译后的 SQL:

SELECT "p"."Id", "p"."Name", "p"."PhoneNumber"
FROM "People" AS "p"
WHERE CAST("p"."PhoneNumber" AS TEXT) LIKE '%368%'

4EF.Functions.Random

EF Core 6.0 引入了一个新的 EF.Functions.Random 方法。它映射了 SQL 函数 RAND()。已经实现了对 SQL Server、SQLite 和 Cosmos 的翻译。

using var context = new ExampleContext();
var query = context.Posts.Where(p => p.Rating == (int)(EF.Functions.Random() * 5.0) + 1).ToQueryString();
Console.WriteLine(query);class Post
{public int Id { get; set; }public string Title { get; set; }public int Rating { get; set; }
}
class ExampleContext : DbContext
{public DbSet<Post> Posts { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6Random");
}

翻译后的 SQL:

SELECT[p].[Id], [p].[Rating], [p].[Title]
FROM[Posts] AS[p]
WHERE[p].[Rating] = (CAST((RAND() * 5.0E0) AS int) + 1)

5改进了 SQL Server 的 IsNullOrWhitespace 的翻译

以前,EF Core 将 string.IsNullOrWhiteSpace 翻译成在判断前将值进行 trim 操作。EF Core 6.0 已经不这么做了。

using var context = new ExampleContext();
var query = context.Entities.Where(e => string.IsNullOrWhiteSpace(e.Property)).ToQueryString();
Console.WriteLine(query);class Entity
{public int Id { get; set; }public string Property { get; set; }
}
class ExampleContext : DbContext
{public DbSet<Entity> Entities { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6IsNullOrWhiteSpace");
}

以前翻译的 SQL:

SELECT [e].[Id], [e].[Property]
FROM [Entities] AS[e]
WHERE [e].[Property] IS NULL OR (LTRIM(RTRIM([e].[Property])) = N'')

现在翻译的 SQL:

SELECT [e].[Id], [e].[Property]
FROM [Entities] AS[e]
WHERE [e].[Property] IS NULL OR ([e].[Property] = N'')

6为内存数据库定义查询

在 EF Core 6.0 中,你可以通过一个新的方法 ToInMemoryQuery 来定义一个针对内存数据库的查询。这对于创建内存数据库的视图是最有用的。

using var context = new ExampleContext();
var blogEn = new Blog
{Title = "All about .NET",Language = "English",Posts = new List<Post>{new Post { Title = "Post one", Content = "Some content" },new Post { Title = "Post two", Content = "Some content" }}
};
var blogPl = new Blog
{Title = "Wszystko o .NET",Language = "Polish",Posts = new List<Post>{new Post { Title = "Pierwszy post", Content = "Treść" }}
};
context.Blogs.Add(blogEn);
context.Blogs.Add(blogPl);
await context.SaveChangesAsync();var postsByLanguages = context.PostsByLanguages.ToList();
postsByLanguages.ForEach(p => Console.WriteLine($"{p.PostCount} posts in {p.Language}"));
// Output:
// 2 posts in English
// 1 posts in Polishclass Post
{public int Id { get; set; }public string Title { get; set; }public string Content { get; set; }
}
class Blog
{public int Id { get; set; }public string Title { get; set; }public string Language { get; set; }public ICollection<Post> Posts { get; set; }
}
class PostsByLanguage
{public string Language { get; set; }public int PostCount { get; set; }
}
class ExampleContext : DbContext
{public DbSet<Post> Posts { get; set; }public DbSet<Blog> Blogs { get; set; }public DbSet<PostsByLanguage> PostsByLanguages { get; set; }protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<PostsByLanguage>().HasNoKey().ToInMemoryQuery(() => Blogs.GroupBy(c => c.Language).Select(g =>new PostsByLanguage{Language = g.Key,PostCount = g.Sum(b => b.Posts.Count)}));}protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseInMemoryDatabase("ToInMemoryQuery");
}

7单参数的 Substring 翻译

以前,EF Core 只翻译有两个参数的 string.Substring 重载。EF Core 6.0 支持翻译单个参数的 string.Substring

using var context = new ExampleContext();
context.People.Add(new Person { Name = "John" });
context.People.Add(new Person { Name = "Bred" });
context.People.Add(new Person { Name = "Ron" });
await context.SaveChangesAsync();var result = await context.People.Select(a => new { Name = a.Name.Substring(1) }).ToListAsync();
result.ForEach(p => Console.WriteLine(p.Name));
// Output:
// ohn
// red
// onclass Person
{public int Id { get; set; }public string Name { get; set; }
}
class ExampleContext : DbContext
{public DbSet<Person> People { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6Substring");
}

翻译后的 SQL:

SELECT SUBSTRING([p].[Name], 1 + 1, LEN([p].[Name])) AS [Name]
FROM [People] AS [p]

8非导航集合的分割查询

EF Core 支持将一个 LINQ 查询拆分成多个 SQL 查询。EF Core 6.0 可以分割一个 LINQ 查询,其中非导航集合属性包含在查询投影中。

using var context = new ExampleContext();
var blog = new Blog { Name = ".NET Blog"};
blog.Posts.Add(new Post { Title = "First .NET post" });
blog.Posts.Add(new Post { Title = "Second Java post" });
blog.Posts.Add(new Post { Title = "Third .NET post" });
context.Blogs.Add(blog);
await context.SaveChangesAsync();var blogsWithDotnetPosts = await context.Blogs.Select(b => new{b,Posts = b.Posts.Where(p => p.Title.Contains(".NET")),}).AsSplitQuery().ToListAsync();class Blog
{public int Id { get; set; }public string Name { get; set; }public ICollection<Post> Posts { get; set; } = new List<Post>();
}
class Post
{public int Id { get; set; }public string Title { get; set; }public Blog Blog { get; set; }
}
class ExampleContext : DbContext
{public DbSet<Blog> Blogs { get; set; }public DbSet<Post> Posts { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6SplitQueries");
}

单个 SQL 查询(不用 AsSplitQuery):

SELECT [b].[Id], [b].[Name], [t].[BlogId], [t].[Title]
FROM [Blogs] AS [b]
LEFT JOIN (SELECT [p].[Id], [p].[BlogId], [p].[Title]FROM [Posts] AS [p]WHERE [p].[Title] LIKE N'%.NET%'
) AS [t] ON [b].[Id] = [t].[BlogId]
ORDER BY [b].[Id]

多个 SQL 查询(使用了 AsSplitQuery):

SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
ORDER BY [b].[Id]SELECT [t].[Id], [t].[BlogId], [t].[Title], [b].[Id]
FROM [Blogs] AS [b]
INNER JOIN (SELECT [p].[Id], [p].[BlogId], [p].[Title]FROM [Posts] AS [p]WHERE [p].[Title] LIKE N'%.NET%'
) AS [t] ON [b].[Id] = [t].[BlogId]
ORDER BY [b].[Id]

9删除最后的 ORDER BY 子句

当连接相关实体时,EF Core 添加了 ORDER BY 子句,以确保给定实体的所有相关实体被分组。然而,最后一个子句并不是必须的,而且会对性能产生影响。EF Core 6.0 删除了它。

using var context = new ExampleContext();
var query = context.Blogs.Include(b => b.Posts.Where(p => p.Rating > 3)).ToQueryString();
Console.WriteLine(query);class Blog
{public int Id { get; set; }public string Name { get; set; }public ICollection<Post> Posts { get; set; }
}
class Post
{public int Id { get; set; }public string Title { get; set; }public int Rating { get; set; }public Blog Blog { get; set; }
}
class ExampleContext : DbContext
{public DbSet<Blog> Blogs { get; set; }public DbSet<Post> Posts { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6RemoveLastOrderByClause");
}

EF Core 5.0 翻译的 SQL:

SELECT [b].[Id], [b].[Name], [t].[Id], [t].[BlogId], [t].[Rating], [t].[Title]
FROM [Blogs] AS [b]
LEFT JOIN (SELECT [p].[Id], [p].[BlogId], [p].[Rating], [p].[Title]FROM [Posts] AS [p]WHERE [p].[Rating] > 3
) AS [t] ON [b].[Id] = [t].[BlogId]
ORDER BY [b].[Id], [t].[Id]

EF Core 6.0 翻译的 SQL:

SELECT [b].[Id], [b].[Name], [t].[Id], [t].[BlogId], [t].[Rating], [t].[Title]
FROM [Blogs] AS [b]
LEFT JOIN (SELECT [p].[Id], [p].[BlogId], [p].[Rating], [p].[Title]FROM [Posts] AS [p]WHERE [p].[Rating] > 3
) AS [t] ON [b].[Id] = [t].[BlogId]
ORDER BY [b].[Id]

10用文件名和行号标记查询

从 EF Core 2.2 开始,你可以给你的查询添加一个标签,以达到更好的调试目的。EF Core 6.0 更进一步,现在你可以用 LINQ 代码的文件名和行号来标记查询。

using var context = new ExampleContext();
var query = context.Blogs.TagWithCallSite().OrderBy(b => b.CreationDate).Take(10).ToQueryString();
Console.WriteLine(query);class Blog
{public int Id { get; set; }public string Name { get; set; }public DateTime CreationDate { get; set; }
}
class ExampleContext : DbContext
{public DbSet<Blog> Blogs { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6TagWithCallSite");
}

翻译后的 SQL:

DECLARE @__p_0 int = 10;--File: D:\EFCore6\TagWithCallSite\TagWithCallSite\Program.cs:6SELECT TOP(@__p_0) [b].[Id], [b].[CreationDate], [b].[Name]
FROM[Blogs] AS[b]
ORDER BY[b].[CreationDate]

11自有可选从属关系处理

EF Core 6.0 改变了一些对自有可选从属关系的处理。当一个模型有自己的可选从属关系时,EF Core 会在你保存它时警告你所有缺失的属性。

using var context = new ExampleContext();
var person = new Person
{FirstName = "Oleg",LastName = "Kyrylchuk",Address = new Address()
};
context.People.Add(person);
await context.SaveChangesAsync();class Person
{public int Id { get; set; }public string FirstName { get; set; }public string LastName { get; set; }public Address Address { get; set; }
}
class Address
{public string City { get; set; }public string Street { get; set; }public string PostalCode { get; set; }
}
class ExampleContext : DbContext
{public DbSet<Person> People { get; set; }protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<Person>().OwnsOne(p => p.Address);}protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.EnableSensitiveDataLogging().LogTo(Console.WriteLine).UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6OwnedDependentHandling");
}

警告日志:

b9370036a01a6bc620b41b72083e4014.png

当你有嵌套自有可选从属关系时,EF Core 将不允许创建模型。

using var context = new ExampleContext();
var person = new Person
{FirstName = "Oleg",LastName = "Kyrylchuk",ContactInfo = new ContactInfo()
};
context.People.Add(person);
await context.SaveChangesAsync();class Person
{public int Id { get; set; }public string FirstName { get; set; }public string LastName { get; set; }public ContactInfo ContactInfo { get; set; }
}
class ContactInfo
{public string Phone { get; set; }public Address Address { get; set; }
}
class Address
{public string City { get; set; }public string Street { get; set; }public string PostalCode { get; set; }
}
class ExampleContext : DbContext
{public DbSet<Person> People { get; set; }protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<Person>().OwnsOne(p => p.ContactInfo).OwnsOne(p => p.Address);}protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6OwnedDependentHandling");
}

创建模型后将会抛出异常。

这些变化迫使你避免这种情况。你可以通过以下方式解决这些问题。

  • 使从属关系成为必需的。

  • 在从属关系中至少有一个必需属性。

  • 为可选的从属关系创建自己的表,而不是与主体共享它们。

12结尾

本文所有代码示例都可以在我的 GitHub 中找到:

https://github.com/okyrylchuk/dotnet6_features/tree/main/EF%20Core%206#linq-query-enhancements

原文:bit.ly/32DqXnu
作者:Oleg Kyrylchuk
翻译:精致码农

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

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

相关文章

linux之mutex(互斥锁)

在Posix Thread中定义有一套专门用于线程同步的mutex函数 1. 创建和销毁 有两种方法创建互斥锁,静态方式和动态方式。POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁,方法如下: pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; 在LinuxThreads实现中,…

SQL相关路径查询脚本

--1.查询机器名 SELECT servername AS 机器名称 --查询已安装的SQL实例名 SELECT * FROM Sys.Servers--2.查询SQL安装路径 DECLARE installPath VARCHAR(200) EXEC MASTER.dbo.xp_regread HKEY_LOCAL_MACHINE,SOFTWARE\Microsoft\MSSQLSERVER\setup,SQLPath,installPath OUT…

SpringMvc项目中使用GoogleKaptcha 生成验证码

前言&#xff1a;google captcha 是google生成验证码的一个工具类&#xff0c;其原理是将随机生成字符串保存到session中&#xff0c;同时以图片的形式返回给页面&#xff0c;之后前台页面提交到后台进行对比。 1、jar包准备 官方提供的pom应该是 <dependency> <grou…

wpsppt流程图联系效果_风险隐患排查的手段—HAZOP 与检查表的区别及应用效果

HAZOP 与检查表的区别HAZOP 分析可以在工厂运行周期内的任何时间段进行&#xff0c;既适用于设计阶段&#xff0c;也适用于在役的工艺装置。在化工项目的设计阶段采用HAZOP 方法进行分析&#xff0c;能识别设计、设备及操作程序中的潜在危险&#xff0c;比如装置设备是否装有安…

软件测试实验报告下载 实验一到实验五

实验一&#xff1a; 传送门在此&#xff1a;https://download.csdn.net/download/qq_44872173/15559951 目录如下&#xff1a;

linux网络编程之并发服务器的三种实现模型 (超级经典)

转载 &#xff1a; http://blog.csdn.net/tennysonsky/article/details/45671215 服务器设计技术有很多&#xff0c;按使用的协议来分有 TCP 服务器和 UDP 服务器&#xff0c;按处理方式来分有循环服务器和并发服务器。 循环服务器与并发服务器模型 在网络程序里面&#xff0c…

poj 1060 Modular multiplication of polynomials

方法&#xff08;无证明&#xff0c;lz弱渣请谅解&#xff09;&#xff1a; 以样例来讲&#xff1a;(x^6 x^4 x^2 x 1) (x^7 x 1) modulo (x^8 x^4 x^3 x 1) x^7 x^6 1 。 (x^6 x^4 x^2 x 1) (x^7 x 1) x^13 x^11 x^9 x^8 x^6 x^5 x^4 x^3 1 。 令a…

IT人的自我导向型学习:学习的4个层次

[原文链接] 谈起软件开发一定会想到用什么技术、采用什么框架&#xff0c;然而在盛行的敏捷之下&#xff0c;人的问题逐渐凸显出来。不少企业请人来培训敏捷开发技术&#xff0c;却发现并不能真正运用起来&#xff0c;其中一个主要原因就是大家还没有很好的学习能力。没有学习&…

.NET Core分析程序集最优美的方法,不用Assembly.LoadFile(),超越ReflectionOnlyLoad

在编写.NET程序的时候&#xff0c;如果需要对一个程序集文件进行分析&#xff0c;我们可以使用Assembly.LoadFile()来加载这个程序集&#xff0c;然后对LoadFile()方法返回的Assembly对象进行进一步的分析。但是Assembly.LoadFile()方法会以执行为目的把程序集加载到程序中&…

C#学习笔记——通用对话框

Visual Studio提供的通用对话框控件有&#xff1a;ColorDialog、FolderBrowserDialog、FontDialog、OpenFileDialog、SaveFileDialog、PageSetupDialog、PrintDialog和PrintPreviewDialog。 在使用这些中的某个“通用对话框”控件时&#xff0c;可以向窗体添加该控件&#xff0…

动态ram依靠什么存储信息_ROM、RAM、DRAM、SRAM和FLASH傻傻分不清

ROM、RAM、DRAM、SRAM和FLASH各类储存器在电脑、手机、电子设备、嵌入式设备及相应的开发中普遍应用的&#xff0c;但是很多还是傻傻分不清楚。下面就简单介绍下这几个吧&#xff01;ROM和RAMROM&#xff1a;只读存储器或者固化存储器&#xff1b;RAM&#xff1a;随机存取存储器…

软件项目管理课后题下载【共5个章(1、3、4、5、6)】

都整理好了&#xff0c;链接在此&#xff1a;https://download.csdn.net/download/qq_44872173/15560093 目录如下&#xff1a;

linux c之snprintf()和sprintf()区别

1、snprintf函数 int snprintf(char *str, size_t size, const char *format, ...); 将可变个参数(...)按照format格式化成字符串,然后将其复制到str中 (1) 如果格式化后的字符串长度 < size,则将此字符串全部复制到str中,并给其后添加一个字符串结束符(/0); (2) 如果…

Chrome中输入框默认样式移除

Chrome中输入框默认样式移除 在chrome浏览器中会默认给页面上的输入框如input、textarea等渲染浏览器自带的边框效果 IE8中效果如下&#xff1a; Chrome中效果如下&#xff1a; 这在我们未给输入框设置获取焦点时改变边框颜色时&#xff0c;chrome浏览器解析页面中默认将输入框…

MBR解析

先推广一下QQ群&#xff1a;61618925。欢迎各位爱好编程的朋友加入。 一、程序界面 二、关键部分代码&#xff1a; 1.数据结构定义 #define MBRSIZE 512 #define BOOTRECORDSIZE 440 #define DISKSIGNEDSIZE 4 #define RESERVESIZE 2 #define DPTNUMBER 4 #define DPTSIZE 16 #…

css sprite讲解与使用实例

转自&#xff1a;http://www.manongjc.com/article/886.html 一、什么是css sprites css sprites直译过来就是CSS精灵。通常被解释为“CSS图像拼合”或“CSS贴图定位”。其实就是通过将多个图片融合到一张图里面&#xff0c;然后通过CSS background背景定位技术技巧布局网页背景…

如何通过 HttpWebRequest 上传文件?

咨询区 dr. evil我不希望通过 WebDAV 文件夹的方式上传文件&#xff0c;我想通过相关的 HttpWebRequest 类&#xff0c;类库或者代码片段来帮我模拟浏览器行为来上传文件&#xff0c;请问是否有好的解决方案&#xff1f;回答区 Joshcodes如果你用的是基于 .NET 4.5 以上的版本&…

实验 2 关键字驱动测试(2 学时)实验报告--软件功能测试与性能测试实验

以下是实验要求部分&#xff1a;&#xff08;小伙伴们根据自己需求决定是否下载哈&#xff09; 下载位置链接&#xff1a;https://download.csdn.net/download/qq_44872173/20031354

小手工纸盒机器人_亲子手工 | DIY弹珠迷宫小黑手自制玩具系列

上周用鞋盒做的迷你桌球受到很多男孩子的喜欢今天小黑手又做了一个瓦楞纸手工「弹珠迷宫」也是喜欢的爱不释手呢暑假小黑手系列&#xff0c;希望也能攒出个自己的小游乐场自己动手做自己的玩具&#xff0c;买玩具的钱可以省了快速手工教程Let’s do it我们一起做起来吧&#xf…

linux网络编程之用select方法实现io复用(基于udp)

1、基本概念 IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合:   (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。   (2)当一个客户同时处理多个套接口时,而这种情况是可能…