ASP.NET Core OData 实践——Lesson8增删改查集合Property(C#)

article/2025/6/8 0:43:25

大纲

  • 支持的接口
  • 主要模型设计
  • 控制器设计
    • 数据源
    • 查询(GET)
      • 查询集合属性的值
        • 查询基类类型Entity的基础类型集合属性值
        • 查询派生类型Entity的基础类型集合属性值
      • 查询集合属性数量
        • 查询基类类型Entity的基础类型集合属性值的个数
        • 查询派生类型Entity的基础类型集合属性值的个数
    • 创建(POST)
      • 新增基类类型Entity的基础类型集合属性值
      • 新增派生类型Entity的基础类型集合属性值
    • 完整更新(PUT)
      • 完整更新基类类型Entity的属性值
      • 完整更新派生类型Entity的属性值
    • 局部更新(PATCH)
    • 删除(DELETE)
      • 删除基类类型Entity的非空属性
        • 清空集合
        • 删除一组集合值
      • 删除集合中一个值
      • 删除派生类型Entity的非空属性
        • 清空集合
        • 删除一组集合值
      • 删除集合中一个值
  • 主程序
    • 服务文档
    • 模型元文档
  • 代码地址
  • 参考资料

在 OData API 设计中,集合属性(Collection-Valued Property)是指一个实体拥有的属性类型为集合(如 List<string>、List<Address>)。

支持的接口

Request MethodRoute Template说明
GET~/{entityset}/{key}/{property}查询基类类型Entity的属性值
GET~/{entityset}/{key}/{cast}/{property}查询派生类型Entity的属性值
GET~/{singleton}/{property}查询基类类型单例的属性值
GET~/{singleton}/{cast}/{property}查询派生类型单例的属性值
GET~/{entityset}/{key}/{collectionvaluedproperty}/$count查询基类类型Entity的基础类型集合属性值的个数
GET~/{entityset}/{key}/{cast}/{collectionvaluedproperty}/$count查询派生类型Entity的基础类型集合属性值的个数
GET~/{singleton}/{collectionvaluedproperty}/$count查询基类类型单例的基础类型集合属性值的个数
GET~/{singleton}/{cast}/{collectionvaluedproperty}/$count查询派生类型单例的基础类型集合属性值的个数
POST~/{entityset}/{key}/{collectionvaluedproperty}新增基类类型Entity的基础类型集合属性值
POST~/{entityset}/{key}/{cast}/{collectionvaluedproperty}新增派生类型Entity的基础类型集合属性值
POST~/{singleton}/{collectionvaluedproperty}新增基类类型单例的基础类型集合属性值
POST~/{singleton}/{cast}/{collectionvaluedproperty}新增派生类型单例的基础类型集合属性值
PUT~/{entityset}/{key}/{property}完整更新基类类型Entity的属性值
PUT~/{entityset}/{key}/{cast}/{property}完整更新派生类型Entity的属性值
PUT~/{singleton}/{property}完整更新基类类型单例的属性值
PUT~/{singleton}/{cast}/{property}完整更新派生类型单例的属性值
DELETE~/{entityset}/{key}/{nullableproperty}删除基类类型Entity的非空属性
DELETE~/{entityset}/{key}/{cast}/{nullableproperty}删除派生类型Entity的非空属性
DELETE~/{singleton}/{nullableproperty}删除基类类型单例的非空属性
DELETE~/{singleton}/{cast}/{nullableproperty}删除派生类型单例的非空属性

主要模型设计

在项目下新增Models文件夹,并添加Address、PostalAddress 、Customer和EnterpriseCustomer类。

namespace Lesson8.Models
{public class Address{public required string Street { get; set; }}
}
namespace Lesson8.Models
{public class PostalAddress : Address{public required string PostalCode { get; set; }}
}
using System.Net;namespace Lesson8.Models
{using System.Collections.Generic;public class Customer{public int Id { get; set; }public string? Name { get; set; }public Address? BillingAddress { get; set; }public List<string> ContactPhones { get; set; } = [];}
}
using System.Net;namespace Lesson8.Models
{using System.Collections.Generic;public class EnterpriseCustomer : Customer{public decimal? CreditLimit { get; set; }public Address? RegisteredAddress { get; set; }public List<Address> ShippingAddresses { get; set; } = new List<Address>();}
}

在这里插入图片描述

控制器设计

在项目中新增Controller文件夹,然后添加CompanyController类。该类注册于ODataController,以便拥有如下能力:

  1. OData 路由支持
    继承 ODataController 后,控制器自动支持 OData 路由(如 /odata/Shapes(1)),可以直接响应 OData 标准的 URL 路径和操作。
  2. OData 查询参数支持
    可以使用 [EnableQuery] 特性,自动支持 $filter、$select、$orderby、$expand 等 OData 查询参数,无需手动解析。
  3. OData 响应格式
    返回的数据会自动序列化为 OData 标准格式(如 JSON OData),方便前端或其他系统消费。
  4. OData Delta 支持
    支持 Delta<T>、DeltaSet<T> 等类型,便于实现 PATCH、批量 PATCH 等 OData 特有的部分更新操作。
  5. 更丰富的 OData 语义
    继承后可方便实现实体集、实体、导航属性、复杂类型等 OData 语义,提升 API 的表达能力。
using Lesson8.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Deltas;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.AspNetCore.OData.Routing.Controllers;namespace Lesson8.Controllers
{public class CustomersController: ODataController{}
}

下面我们在该类中填充逻辑。

数据源

        private static List<Customer> customers = new List<Customer>{new Customer{Id = 1,Name = "Customer 1",ContactPhones = new List<string> { "761-116-1865" },BillingAddress = new Address { Street = "Street 1A" }},new Customer{Id = 2,Name = "Customer 2",ContactPhones = new List<string> { "835-791-8257" },BillingAddress = new PostalAddress { Street = "2A", PostalCode = "14030" }},new EnterpriseCustomer{Id = 3,Name = "Customer 3",ContactPhones = new List<string> { "157-575-6005" },BillingAddress = new Address { Street = "Street 3A" },CreditLimit = 4200,RegisteredAddress = new Address { Street = "Street 3B" },ShippingAddresses = new List<Address>{new Address { Street = "Street 3C" }}},new EnterpriseCustomer{Id = 4,Name = "Customer 4",ContactPhones = new List<string> { "724-096-6719" },BillingAddress = new Address { Street = "Street 4A" },CreditLimit = 3700,RegisteredAddress = new PostalAddress { Street = "Street 4B", PostalCode = "22109" },ShippingAddresses = new List<Address>{new Address { Street = "Street 4C" }}}};

查询(GET)

Request MethodRoute Template说明
GET~/{entityset}/{key}/{property}查询基类类型Entity的属性值
GET~/{entityset}/{key}/{cast}/{property}查询派生类型Entity的属性值
GET~/{singleton}/{property}查询基类类型单例的属性值
GET~/{singleton}/{cast}/{property}查询派生类型单例的属性值
GET~/{entityset}/{key}/{collectionvaluedproperty}/$count查询基类类型Entity的基础类型集合属性值的个数
GET~/{entityset}/{key}/{cast}/{collectionvaluedproperty}/$count查询派生类型Entity的基础类型集合属性值的个数
GET~/{singleton}/{collectionvaluedproperty}/$count查询基类类型单例的基础类型集合属性值的个数
GET~/{singleton}/{cast}/{collectionvaluedproperty}/$count查询派生类型单例的基础类型集合属性值的个数

对于基类类型Entity的属性,我们选用Customer.BillingAddress。

        [EnableQuery]public ActionResult<IEnumerable<string>> GetContactPhones([FromRoute] int key){var customer = customers.SingleOrDefault(d => d.Id.Equals(key));if (customer == null){return NotFound();}return customer.ContactPhones;}

对于派生类型Entity的属性,我们选用EnterpriseCustomer.ShippingAddresses。

        [EnableQuery]public ActionResult<IEnumerable<Address>> GetShippingAddressesFromEnterpriseCustomer([FromRoute] int key){var enterpriseCustomer = customers.OfType<EnterpriseCustomer>().SingleOrDefault(d => d.Id.Equals(key));if (enterpriseCustomer == null){return NotFound();}return enterpriseCustomer.ShippingAddresses;}

查询集合属性的值

Request MethodRoute Template说明
GET~/{entityset}/{key}/{property}查询基类类型Entity的属性值
GET~/{entityset}/{key}/{cast}/{property}查询派生类型Entity的属性值
GET~/{singleton}/{property}查询基类类型单例的属性值
GET~/{singleton}/{cast}/{property}查询派生类型单例的属性值
查询基类类型Entity的基础类型集合属性值
Request MethodRoute Template说明
GET~/{entityset}/{key}/{property}查询基类类型Entity的属性值
GET~/{singleton}/{cast}/{property}查询派生类型单例的属性值
  • Request
curl --location 'http://localhost:5119/odata/Customers(1)/ContactPhones'
  • Response
{"@odata.context": "http://localhost:5119/odata/$metadata#Collection(Edm.String)","value": ["761-116-1865"]
}
查询派生类型Entity的基础类型集合属性值
Request MethodRoute Template说明
GET~/{singleton}/{property}查询基类类型单例的属性值
GET~/{singleton}/{cast}/{property}查询派生类型单例的属性值
  • Request
curl --location 'http://localhost:5119/odata/Customers(3)/Lesson8.Models.EnterpriseCustomer/ShippingAddresses'
  • Response
{"@odata.context": "http://localhost:5119/odata/$metadata#Customers(3)/Lesson8.Models.EnterpriseCustomer/ShippingAddresses","value": [{"Street": "Street 3C"}]
}

查询集合属性数量

Request MethodRoute Template说明
GET~/{entityset}/{key}/{collectionvaluedproperty}/$count查询基类类型Entity的基础类型集合属性值的个数
GET~/{entityset}/{key}/{cast}/{collectionvaluedproperty}/$count查询派生类型Entity的基础类型集合属性值的个数
GET~/{singleton}/{collectionvaluedproperty}/$count查询基类类型单例的基础类型集合属性值的个数
GET~/{singleton}/{cast}/{collectionvaluedproperty}/$count查询派生类型单例的基础类型集合属性值的个数
查询基类类型Entity的基础类型集合属性值的个数
Request MethodRoute Template说明
GET~/{entityset}/{key}/{collectionvaluedproperty}/$count查询基类类型Entity的基础类型集合属性值的个数
GET~/{singleton}/{collectionvaluedproperty}/$count查询基类类型单例的基础类型集合属性值的个数
  • Request
curl --location 'http://localhost:5119/odata/Customers(1)/ContactPhones/$count'
  • Response
1
查询派生类型Entity的基础类型集合属性值的个数
Request MethodRoute Template说明
GET~/{entityset}/{key}/{cast}/{collectionvaluedproperty}/$count查询派生类型Entity的基础类型集合属性值的个数
GET~/{singleton}/{cast}/{collectionvaluedproperty}/$count查询派生类型单例的基础类型集合属性值的个数
  • Request
curl --location 'http://localhost:5119/odata/Customers(3)/Lesson8.Models.EnterpriseCustomer/ShippingAddresses/$count'
  • Response
1

创建(POST)

Request MethodRoute Template说明
POST~/{entityset}/{key}/{collectionvaluedproperty}新增基类类型Entity的基础类型集合属性值
POST~/{entityset}/{key}/{cast}/{collectionvaluedproperty}新增派生类型Entity的基础类型集合属性值
POST~/{singleton}/{collectionvaluedproperty}新增基类类型单例的基础类型集合属性值
POST~/{singleton}/{cast}/{collectionvaluedproperty}新增派生类型单例的基础类型集合属性值

新增基类类型Entity的基础类型集合属性值

        public ActionResult PostToContactPhones([FromRoute] int key, [FromBody] string contactPhone){var customer = customers.SingleOrDefault(d => d.Id.Equals(key));if (customer == null){return NotFound();}customer.ContactPhones.Add(contactPhone);return Accepted();}
  • Request
curl --location 'http://localhost:5119/odata/Customers(1)/ContactPhones' \
--header 'Content-Type: application/json' \
--data '{"value": "798-507-2014"
}'

新增派生类型Entity的基础类型集合属性值

        public ActionResult PostToShippingAddressesFromEnterpriseCustomer([FromRoute] int key, [FromBody] Address address){var enterpriseCustomer = customers.OfType<EnterpriseCustomer>().SingleOrDefault(d => d.Id.Equals(key));if (enterpriseCustomer == null){return NotFound();}enterpriseCustomer.ShippingAddresses.Add(address);return Accepted();}
  • Request
curl --location 'http://localhost:5119/odata/Customers(3)/Lesson8.Models.EnterpriseCustomer/ShippingAddresses' \
--header 'Content-Type: application/json' \
--data '{"Street": "One Microsoft Way"
}'

完整更新(PUT)

Request MethodRoute Template说明
PUT~/{entityset}/{key}/{property}完整更新基类类型Entity的属性值
PUT~/{entityset}/{key}/{cast}/{property}完整更新派生类型Entity的属性值
PUT~/{singleton}/{property}完整更新基类类型单例的属性值
PUT~/{singleton}/{cast}/{property}完整更新派生类型单例的属性值

完整更新基类类型Entity的属性值

Request MethodRoute Template说明
PUT~/{entityset}/{key}/{property}完整更新基类类型Entity的属性值
PUT~/{singleton}/{property}完整更新基类类型单例的属性值
        public ActionResult PutToContactPhones([FromRoute] int key, [FromBody] IEnumerable<string> contactPhones){var customer = customers.SingleOrDefault(d => d.Id.Equals(key));if (customer == null){return NotFound();}customer.ContactPhones = contactPhones?.ToList() ?? [];return Ok();}
  • Request
curl --location --request PUT 'http://localhost:5119/odata/Customers(1)/ContactPhones' \
--header 'Content-Type: application/json' \
--data '{"value": ["804-855-4049", "491-9198-476"]
}'

完整更新派生类型Entity的属性值

Request MethodRoute Template说明
PUT~/{entityset}/{key}/{cast}/{property}完整更新派生类型Entity的属性值
PUT~/{singleton}/{cast}/{property}完整更新派生类型单例的属性值
        public ActionResult PutToShippingAddressesFromEnterpriseCustomer([FromRoute] int key, [FromBody] IEnumerable<Address> shippingAddresses){var enterpriseCustomer = customers.OfType<EnterpriseCustomer>().SingleOrDefault(d => d.Id.Equals(key));if (enterpriseCustomer == null){return NotFound();}enterpriseCustomer.ShippingAddresses = shippingAddresses?.ToList() ?? [];return Ok();}
  • Request
curl --location --request PUT 'http://localhost:5119/odata/Customers(3)/Lesson8.Models.EnterpriseCustomer/ShippingAddresses' \
--header 'Content-Type: application/json' \
--data '{"value": [{"Street": "One Microsoft Way"},{"Street": "One Google Way"}]
}'

局部更新(PATCH)

在 OData 标准中,PATCH 方法主要用于部分更新实体的单值属性(如字符串、数字、复杂类型对象),而不直接支持集合属性(collection-valued property)的部分更新。
也就是说,OData PATCH 不能像 PATCH 单个对象那样,直接对集合属性(如 List<Address>、List<string>)进行“增量”或“部分”修改。

删除(DELETE)

Request MethodRoute Template说明
DELETE~/{entityset}/{key}/{nullableproperty}删除基类类型Entity的非空属性
DELETE~/{entityset}/{key}/{cast}/{nullableproperty}删除派生类型Entity的非空属性
DELETE~/{singleton}/{nullableproperty}删除基类类型单例的非空属性
DELETE~/{singleton}/{cast}/{nullableproperty}删除派生类型单例的非空属性

删除操作只能支持非空的原始(primitive) 或者复杂(complex)property。本例中删除的Customer.ContactPhones以及EnterpriseCustomer.ShippingAddresses都是List类型,其值可以是null。

不管是“删除基类类型Entity的非空属性”,还是“删除派生类型Entity的非空属性“,下面三种删除方法不可以同时存在,否则请求可以被路由到错误的地址。
只有集合属性(如 ContactPhones)才支持带 Body 的 DELETE(用于删除集合中的某项),其他类型(原始(primitive)或者单值)的删除操作不能带Body。

删除基类类型Entity的非空属性

Request MethodRoute Template说明
DELETE~/{entityset}/{key}/{nullableproperty}删除基类类型Entity的非空属性
DELETE~/{singleton}/{nullableproperty}删除基类类型单例的非空属性
清空集合
        public ActionResult DeleteToContactPhones([FromRoute] int key){var customer = customers.SingleOrDefault(d => d.Id.Equals(key));if (customer == null){return NotFound();}customer.ContactPhones.Clear();return NoContent();}
  • Request
curl --location --request DELETE 'http://localhost:5119/odata/Customers(1)/ContactPhones'
删除一组集合值
        public ActionResult DeleteToContactPhones([FromRoute] int key, [FromBody] IEnumerable<string> contactPhones){var customer = customers.SingleOrDefault(d => d.Id.Equals(key));if (customer == null){return NotFound();}foreach (var contactPhone in contactPhones){customer.ContactPhones.Remove(contactPhone);}return NoContent();}
  • Request
curl --location --request DELETE 'http://localhost:5119/odata/Customers(1)/ContactPhones' \
--header 'Content-Type: application/json' \
--data '{"value": ["804-855-4049", "491-9198-476"]
}'

删除集合中一个值

        public ActionResult DeleteToContactPhones([FromRoute] int key, [FromBody] string contactPhone){var customer = customers.SingleOrDefault(d => d.Id.Equals(key));if (customer == null){return NotFound();}if (!customer.ContactPhones.Remove(contactPhone)){return NotFound();}return NoContent();}
  • Request
curl --location --request DELETE 'http://localhost:5119/odata/Customers(1)/ContactPhones' \
--header 'Content-Type: application/json' \
--data '{"value": "798-507-2014"
}'

删除派生类型Entity的非空属性

Request MethodRoute Template说明
DELETE~/{entityset}/{key}/{cast}/{nullableproperty}删除派生类型Entity的非空属性
DELETE~/{singleton}/{cast}/{nullableproperty}删除派生类型单例的非空属性
清空集合
        public ActionResult DeleteToShippingAddressesFromEnterpriseCustomer([FromRoute] int key){var enterpriseCustomer = customers.OfType<EnterpriseCustomer>().SingleOrDefault(d => d.Id.Equals(key));if (enterpriseCustomer == null){return NotFound();}enterpriseCustomer.ShippingAddresses.Clear();return NoContent();}
  • Request
curl --location --request DELETE 'http://localhost:5119/odata/Customers(3)/Lesson8.Models.EnterpriseCustomer/ShippingAddresses'
删除一组集合值
        public ActionResult DeleteToShippingAddressesFromEnterpriseCustomer([FromRoute] int key, [FromBody] IEnumerable<Address> shippingAddresses){var enterpriseCustomer = customers.OfType<EnterpriseCustomer>().SingleOrDefault(d => d.Id.Equals(key));if (enterpriseCustomer == null){return NotFound();}foreach (var address in shippingAddresses){enterpriseCustomer.ShippingAddresses.Remove(address);}return NoContent();}
  • Request
curl --location --request DELETE 'http://localhost:5119/odata/Customers(3)/Lesson8.Models.EnterpriseCustomer/ShippingAddresses' \
--header 'Content-Type: application/json' \
--data '{"value": [{"Street": "One Microsoft Way"},{"Street": "One Google Way"}]
}'

删除集合中一个值

        public ActionResult DeleteToShippingAddressesFromEnterpriseCustomer([FromRoute] int key, [FromBody] Address address){var enterpriseCustomer = customers.OfType<EnterpriseCustomer>().SingleOrDefault(d => d.Id.Equals(key));if (enterpriseCustomer == null){return NotFound();}if (!enterpriseCustomer.ShippingAddresses.Remove(address)){return NotFound();}return NoContent();}
  • Request
curl --location --request DELETE 'http://localhost:5119/odata/Customers(3)/Lesson8.Models.EnterpriseCustomer/ShippingAddresses' \
--header 'Content-Type: application/json' \
--data '{"Street": "One Microsoft Way"
}'

主程序

using Lesson8.Models;
using Microsoft.AspNetCore.OData;
using Microsoft.OData.ModelBuilder;
using Microsoft.OData.Edm;var builder = WebApplication.CreateBuilder(args);static IEdmModel GetEdmModel()
{var modelBuilder = new ODataConventionModelBuilder();modelBuilder.EntitySet<Customer>("Customers");return modelBuilder.GetEdmModel();
}builder.Services.AddControllers().AddOData(options =>options.Select().Filter().OrderBy().Expand().Count().SetMaxTop(null).AddRouteComponents("odata", GetEdmModel())
);var app = builder.Build();app.UseRouting();app.MapControllers();app.Run();

服务文档

  • Request
curl --location 'http://localhost:5119/odata'
  • Response
{"@odata.context": "http://localhost:5119/odata/$metadata","value": [{"name": "Customers","kind": "EntitySet","url": "Customers"}]
}

模型元文档

  • Request
curl --location 'http://localhost:5119/odata/$metadata'
  • Response
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="Lesson8.Models" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="Customer"><Key><PropertyRef Name="Id" /></Key><Property Name="Id" Type="Edm.Int32" Nullable="false" /><Property Name="Name" Type="Edm.String" Nullable="false" /><Property Name="BillingAddress" Type="Lesson8.Models.Address" Nullable="false" /><Property Name="ContactPhones" Type="Collection(Edm.String)" /></EntityType><ComplexType Name="Address"><Property Name="Street" Type="Edm.String" Nullable="false" /></ComplexType><ComplexType Name="PostalAddress" BaseType="Lesson8.Models.Address"><Property Name="PostalCode" Type="Edm.String" Nullable="false" /></ComplexType><EntityType Name="EnterpriseCustomer" BaseType="Lesson8.Models.Customer"><Property Name="CreditLimit" Type="Edm.Decimal" Nullable="false" Scale="variable" /><Property Name="RegisteredAddress" Type="Lesson8.Models.Address" Nullable="false" /><Property Name="ShippingAddresses" Type="Collection(Lesson8.Models.Address)" /></EntityType></Schema><Schema Namespace="Default" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityContainer Name="Container"><EntitySet Name="Customers" EntityType="Lesson8.Models.Customer" /></EntityContainer></Schema></edmx:DataServices>
</edmx:Edmx>

代码地址

https://github.com/f304646673/odata/tree/main/csharp/Lesson/Lesson8

参考资料

  • https://learn.microsoft.com/en-us/odata/webapi-8/fundamentals/property-routing?tabs=net60%2Cvisual-studio

http://www.hkcw.cn/article/UjxCnSKPuv.shtml

相关文章

C++旅行预算规划 全国信息素养大赛复赛决赛 C++小学/初中组 算法创意实践挑战赛 内部集训模拟题详细解析

C++旅行预算规划 全国信息素养大赛 C++复赛/决赛模拟训练题 博主推荐 所有考级比赛学习相关资料合集【推荐收藏】1、C++专栏 电子学会C++一级历年真题解析电子学会C

赴山海预约破400万 创新武侠点燃荧屏

武侠剧迷久等了!《赴山海》这部融合穿书、权谋、热血成长的创新武侠巨制,将点燃今夏荧屏。该剧终于官宣定档,将于6月15日在藤子视频和271双平台同步上线。自开拍以来备受关注,目前两大平台预约人数已突破500万大关,创下武侠剧未播预约新纪录。《赴山海》改编自武侠大师温瑞…

藏海单眼落泪串成线 稚奴心碎哭泣惹人怜

藏海寻求荼荼安慰,是谁还没看到肖战藏海单眼一滴泪啊,这哭到我心碎,“你就让我在这坐会吧”也太可怜了吧,我们的藏海此刻坐做回了稚奴啊,这哭的我好心痛~责任编辑:zx0001

李亚鹏拄拐和妻子看女儿演出 一家三口幸福同框

六一儿童节时,海哈金喜分享了与李亚鹏陪伴女儿过节的照片,一家三口其乐融融,幸福的样子令人羡慕。作为明星,李亚鹏虽然不再拍戏,但影响力犹存。他转行做主播后依然备受关注。这次和妻子一起陪女儿过六一,再次成为焦点。他们前往小女儿的幼儿园观看演出,坐在台下为女儿加…

樊振东加盟德甲联赛意味着什么 乒坛巨星开启欧洲冒险

6月1日,德国乒乓球甲级联赛FC萨尔布吕肯俱乐部宣布奥运冠军樊振东将加盟球队。俱乐部称,前世界排名第一、国际乒坛最耀眼的巨星之一樊振东将在新赛季代表该队出战德国乒乓球甲级联赛(TTBL)。这位28岁的中国名将明确表示将开启“欧洲冒险”,并全力参与球队所有赛事。此次签…

中国单方面免签朋友圈再增5国 拉美国家首享便利

从今天开始,中国对巴西、阿根廷、智利、秘鲁、乌拉圭五国持普通护照人员试行免签政策。2025年6月1日至2026年5月31日,这五个国家的公民来华经商、旅游观光、探亲访友、交流访问或过境不超过30天时,可免办签证入境。这是中方首次将免签政策拓展到拉美和加勒比地区国家,至此,…

法国禁止在儿童公共场所吸烟 新禁令7月生效

法国政府宣布将在所有儿童出入的户外场所,包括海滩、公园、学校外、公交车站和体育场馆禁止吸烟。卫生与家庭事务部长沃特兰于5月29日表示,这项新禁令将于7月1日生效,违反者将面临最高135欧元的罚款。沃特兰强调,在有儿童的地方必须禁止烟草,儿童呼吸清洁空气的权利远大于…

于正说临江仙集均打底6000 争议与期待并存

于正的新剧《临江仙》未播先崩,300万预约暴露了观众的矛盾心理。这部仙侠剧的配音让观众想起喜羊羊,特效被嘲像贪吃蛇开会,制片人却忙着和全网对赌口碑。于正在微博上激情宣言“绝无口碑崩塌可能”,还自夸“内娱独一份”。然而,网友备忘录里记满了账本:白鹿的“幼态配音”…

硬件学习笔记--63 开关电源简单介绍

开关电源&#xff08;Switching Mode Power Supply, SMPS&#xff09;是一种高效的电能转换装置&#xff0c;通过高频开关&#xff08;通常由晶体管或MOSFET控制&#xff09;将输入电压&#xff08;如交流或直流&#xff09;转换为稳定的直流输出电压。相比传统的线性电源&…

数据结构:时间复杂度(Time Complexity)和空间复杂度(Space Complexity)

目录 什么是时间复杂度&#xff1f; 如何表示时间复杂度&#xff1f; 为什么需要时间复杂度&#xff1f; 用几个例子理解 怎么分析代码的时间复杂度&#xff1f; 什么是空间复杂度&#xff1f; 举例理解 什么是时间复杂度&#xff1f; 时间复杂度是用来衡量一个算法“…

华为OD机试真题——文件目录大小(2025 A卷:100分)Java/python/JavaScript/C++/C语言/GO六种语言最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录+全流程解析/备考攻略/经验分享 华为OD机试真题《文件目录大小》: 目录 题…

全球名校疯抢哈佛留学生 各国争抢顶尖人才

最近,教育界掀起了一场激烈的全球“抢人大战”,各国纷纷瞄准哈佛生源。哈佛学生之所以受到追捧,是因为他们在学术研究上屡创佳绩,思维活跃,创新能力一流。这些人才对本国的教育、科研和经济发展有着不可估量的推动作用。美国政府宣布撤销部分中国留学生签证的消息一出,教…

怎样才能看懂赵丽颖新剧《在人间》 剧情烧脑反转不断

赵丽颖和尹昉主演的电视剧《在人间》虽然只有8集,却融合了无限流、悬疑烧脑、奇幻、多重人格、赛博朋克等众多元素,讲述了贾小朵与徐天一起进入“虚拟空间”的故事。故事题材新颖,惊喜不断。剧情以“梦中梦”方式展开,各种意想不到的场景和桥段层出不穷,如虚拟空间、抽象梦…

藏海传热度榜冠军 肖战新剧引爆收视狂潮

肖战主演的《藏海传》开播不到一周便引起了广泛关注。该剧不仅以超过2%的实时收视率成为央八年度冠军,肖战也凭借“藏海”一角在角色热度榜上遥遥领先。网友评价:“上一次这么火的还是《梦华录》,肖战这波赢麻了!”《藏海传》自首播以来,收视率一路飙升。酷云数据显示,该…

美国黄石公园车祸致中国公民5死8伤 皮卡车司机酒驾超限

5月1日晚,美国黄石国家公园附近发生了一起严重的交通事故。一辆皮卡车与一辆载有14人的面包车相撞,导致7人死亡,其中包括5名中国公民,另有8名中国公民受伤。5月30日,当地警方透露,皮卡车司机血液中的酒精含量超过法定准驾限值的两倍。肇事司机是来自得克萨斯州汉布尔的伊…

暴雨横扫南方大部 为何成都不下雨 成都成“少雨孤岛”

随着南海西南季风的爆发,南方多地进入强降雨模式。自5月下旬以来,从广西到湖南、江西、贵州,甚至云南东部和重庆东南部,雨水强度和频率都显著增加。特别是在云南、贵州一带,不仅有稳定的中到大雨,还有局地暴雨乃至大暴雨,累计雨量不断刷新。根据中央气象台发布的中期天气…

特朗普为何向俄罗斯下“最后通牒” 忍耐已达极限

特朗普要求俄罗斯在14天内给出解释,针对近期俄罗斯的行为,这位美国总统的耐心几乎耗尽。最近几天,特朗普在接受采访时对普京发出明确警告,称两周内将知道普京是否在利用美国,并表示如果确实如此,美国将做出不同的回应。这被视为特朗普对莫斯科的“最后通牒”,也是他自年…

陈伟霆曾舜晞陈瑶九门开机同框 原班人马回归期待

《九门》突然宣布开机,引起广泛关注。陈伟霆饰演张启山,曾舜晞扮演吴老狗,陈瑶则出演霍仙姑。尽管目前只公布了三位演员,但他们的角色都是重量级的,尤其是陈伟霆的回归让人充满期待。2016年,《老九门》播出时迅速走红。这部集结了众多当红演员的民国悬疑剧首播当天收视率…

Canvas实例篇:十二星座之天蝎座

Canvas实例篇&#xff1a;十二星座之天蝎座 前言效果预览代码实现代码说明星座特定星 结语 前言 星座总给人浪漫而神秘的感觉&#xff0c;如何用代码还原星空中的浪漫&#xff1f;本文将通过 Canvas 技术&#xff0c;讲述如何实现一个可交互的天蝎座星空图&#xff0c;包含星星…

马斯克回应离任当天眼角淤青:儿子所为 与子嬉戏致伤

美国总统特朗普和企业家马斯克于5月30日在白宫举行新闻发布会。这天也是马斯克在政府效率部任职的最后一天,他的眼角淤青引起了媒体的关注。马斯克解释说,这是他五岁的儿子小X造成的。当时他在和儿子玩耍时开玩笑让儿子打他的脸,结果儿子真的打了,虽然一开始没什么感觉,但…