简体   繁体   English

EF Core 5.0 - 更新多对多实体 ASP.NET Core Web API

[英]EF Core 5.0 - Updating many-to-many entities in ASP.NET Core Web API

With EF Core 5.0 Many-to-many relations are introduced. EF Core 5.0 引入了多对多关系。 I'm getting stucked on how to update them through my asp .net api.我对如何通过我的 asp .net api 更新它们感到困惑。

For One-to-one and One-to-many relations there is a convention by simply adding the property name followed by ID.对于一对一和一对多关系,有一种约定,只需添加属性名称后跟 ID。

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public BlogImage BlogImage { get; set; }
}

public class BlogImage
{
    public int BlogImageId { get; set; }
    public byte[] Image { get; set; }
    public string Caption { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

So a propper POST Request could look like所以适当的 POST 请求看起来像

{
  "BlogId": 123,
  "Url": "example.com",
  "BlogImageID": 42
}

but I could not find out if there is a convention or how it look like for Many-to-many relations但我无法确定是否存在约定或多对多关系的外观

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public ICollection<Tag> Tags { get; set; }
}

public class Tag
{
    public string TagId { get; set; }

    public ICollection<Post> Posts { get; set; }
}

Is there a convention to map the body of a http request to Many-to-many relations using EF 5.0? map http 对使用 EF 5.0 的多对多关系请求的正文是否存在约定?

Consider the following two entities which are in many-to-many relationship -考虑以下两个处于多对多关系的实体 -

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }

    public ICollection<Tag> Tags { get; set; }
}

public class Tag
{
    public int Id { get; set; }
    public string Name { get; set; }

    public ICollection<Post> Posts { get; set; }
}

When updating the Tags in a Post entity, in the most common scenario, a new list of tag Id s are sent from the client-side, and the request payload will look like -在更新Post实体中的Tags时,在最常见的情况下,从客户端发送一个新的 tag Id列表,请求有效负载将如下所示 -

{
    "id": 123,
    "title": "An Awesome Post",
    "tags": [2, 7, 13]
}

Typically, you'd want to define a DTO to represent this request object, like -通常,您希望定义一个 DTO 来表示此请求 object,例如 -

public class PostUpdateDTO
{
    public int Id { get; set; }
    public string Title { get; set; }

    public List<int> Tags { get; set; }
}

Then, for the update operation itself, you can do something like -然后,对于更新操作本身,您可以执行类似 -

[HttpPut]
public async Task Put([FromBody]PostUpdateDTO dto)
{
    // fetch existing Post including related Tags
    var post = await _DbCtx.Posts
        .Include(p => p.Tags)
        .FirstOrDefaultAsync(p => p.Id == dto.Post.Id);

    // remove all Tags from the existing list
    post.Tags.Clear();
    
    // add new Tags to the list whose Ids are sent by the client
    // but to identify them you need the list of all available tags
    var availableTags = await _DbCtx.Tags.ToListAsync();
    foreach (var id in dto.Tags)
    {
        post.Tags.Add(availableTags.First(p => p.Id == id));
    }
    
    // modify properties of Post if you need, like -
    // post.Title = dto.Title;

    await _DbCtx.SaveChangesAsync();
}

As you can see, this requires a trip to the database to fetch a list of all available Tag .如您所见,这需要访问数据库以获取所有可用Tag的列表。 If you don't like that and want to skip it, you can try the following approach -如果您不喜欢它并想跳过它,您可以尝试以下方法 -

[HttpPut]
public async Task Put([FromBody]PostUpdateDTO dto)
{
    // fetch existing Post including related Tags
    var post = await _DbCtx.Posts
        .Include(p => p.Tags)
        .FirstOrDefaultAsync(p => p.Id == dto.Post.Id);

    // remove Tags which are in the existing Tag list, but not 
    // in the new list sent by the client
    post.Tags.Where(tag => !dto.Tags.Any(id => id == tag.Id))
        .ToList().ForEach(tag => post.Tags.Remove(tag));

    // add Tags which are in the new list sent by the client, but 
    // not in the existing Tag list
    dto.Tags.Where(id => !post.Tags.Any(tag => tag.Id == id))
        .ToList().ForEach(id => post.Tags.Add(new Tag { Id = id }));

    // modify properties of Post if you need, like -
    // post.Title = dto.Title;

    await _DbCtx.SaveChangesAsync();
}

About that - property name followed by ID :关于那个 -属性名称后跟 ID
The kind of Id property you are referring to represents a foreign-key.您所指的那种 Id 属性代表外键。 Neither of these two entities contains a foreign-key property, because neither of them depends on the other.这两个实体都不包含外键属性,因为它们都不依赖于另一个。 A foreign-key implies a parent/child or principal/dependent relationship.外键表示父/子或委托人/依赖关系。 But when two entities are in many-to-many relation, they are independent of each other.但是当两个实体处于多对多关系时,它们是相互独立的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 更新 asp.net 核心 mvc 中的多对多关系 - Updating a many-to-many relationship in asp.net core mvc 使用 EF Core 在 ASP.NET Core 应用程序中使用多对多关系将记录添加到数据库 - Adding records to database with many-to-many relations in ASP.NET Core app with EF Core 带有实体框架的ASP.NET核心多对多不起作用 - ASP.NET core with Entity Framework many-to-many not working EF Core 5.0 从嵌套集合中多对多删除 - EF Core 5.0 Many-To-Many delete from nested collection Entity Framework Core 5.0 如何将 LINQ 转换为多对多连接以使用 ASP.NET 成员资格的交集表 - Entity Framework Core 5.0 How to convert LINQ for many-to-many join to use Intersection table for ASP.NET Membership 在 asp.net core3.1 webapi 中处理我的多对多关系 api 请求 - Handeling my Many-to-Many relation api requests in asp.net core3.1 webapi ASP.NET Core EF多对多引用表 - ASP.NET Core EF Many to Many referencing table 具有许多参数的ASP.Net Core Web API Controller操作 - ASP.Net Core Web API Controller action with many parameters ASP.NET Core 5 Blazor WASM、gRPC、Entity Framework Core 5:多对多导致堆栈溢出 - ASP.NET Core 5 Blazor WASM, gRPC, Entity Framework Core 5: many-to-many results in stack overflow .Net core EF,将记录保存到多对多类型表 - .Net core EF, saving records to many-to-many type table
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM