与EF 6 CRUD的多对多关系



我是EntityFrame工作的新手,我只是想通过项目获得经验,我在网上搜索了很多,但不幸的是,EF6没有太多关于这方面的例子。我有两个表MovieActor,多对多关系如下:

参与者模型:

public class Actor
{
public int Id { get; set; }
[StringLength(50)]
public string Name { get; set; }
[StringLength(50)]
public string Nationality { get; set; }
public DateTime BOD { get; set; }
// RelationShip
public virtual ICollection<Movie> Movies { get; set; }
}

电影型号:

public class Movie
{
public int Id { get; set; }
[StringLength(50)]
public string Title { get; set; }
[StringLength(250)]
public string Description { get; set; }
public GenresEnum Genre { get; set; }
public int ReleasedYear { get; set; }
public string PosterUrl { get; set; }
// RelationShip
public virtual ICollection<Actor> Actors { get; set; }
}

我正在尝试向Movie添加数据,我需要添加电影数据和多个演员(每个电影都有多个演员(,所以我创建了一个名为MovieRequestDto的DTO

public class MovieRequestDto
{
public string Title { get; set; }
public string Description { get; set; }
public GenresEnum Genre { get; set; }
public int ReleasedYear { get; set; }
public string PosterUrl { get; set; }
//// RelationShip
public List<int> ActorsId { get; set; }
}

我想的是将数据插入Movie,然后从dto获得ActorId列表,并将数据插入到联接表MovieActor。我尝试通过创建Movie_Actor Model并将其添加到AppDBContext来实现这一点,同时使用fluent API将其映射为Bellow:

AppDbContext:

using Microsoft.EntityFrameworkCore;
using MovieApp.Core.Models;
namespace MovieApp.EF.Data
{
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Movie_Actor>()
.HasOne(m => m.Movie)
.WithMany(ma => ma.Movie_Actors)
.HasForeignKey(m => m.MovieId);
modelBuilder.Entity<Movie_Actor>()
.HasOne(a => a.Actor)
.WithMany(am => am.Movie_Actors)
.HasForeignKey(a => a.ActorId);
}
public DbSet<Movie> Movies { get; set; }
public DbSet<Actor> Actors { get; set; }
public DbSet<Movie_Actor>  movie_Actors { get; set; }
}
}

Movie_Actor型号:

public class Movie_Actor
{
public int Id { get; set; }
public int MovieId { get; set; }
public Movie Movie { get; set; }
public int ActorId { get; set; }
public Actor Actor { get; set; }
}

这是POST:

[HttpPost]
public async Task<IActionResult> Post(MovieRequestDto dto)
{
var movie = new Movie();
movie.Title = dto.Title;
movie.Description = dto.Description;
movie.Genre = dto.Genre;
movie.ReleasedYear = dto.ReleasedYear;
movie.PosterUrl = dto.PosterUrl;
movie.ProducerId = dto.ProducerId;
await _context.Movies.AddAsync(movie);
await _context.SaveChangesAsync();
foreach (var ActorId in dto.ActorsId)
{
var movie_actor = new Movie_Actor();
movie_actor.MovieId = movie.Id;
movie_actor.ActorId = ActorId;
await _context.movie_Actors.AddAsync(movie_actor);
}
await _context.SaveChangesAsync();
return Ok();
}

这种方式不起作用,我认为我不需要使用这种方式,因为EF6可以自己处理映射,而无需手动操作。那么,对于最新的EF6,对一对多关系进行CRUD的最佳方式是什么。

我得到这个错误:

Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
---> Microsoft.Data.SqlClient.SqlException (0x80131904): Invalid object name 'movie_Actors'.
at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__188_0(Task`1 result)
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
ClientConnectionId:c6f722d2-d86e-453b-8855-da3c87fe20ed
Error Number:208,State:1,Class:16
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at MovieApp.API.Controllers.MoviesController.Post(MovieRequestDto dto) in C:UsersAppiaTech-RQabsourcereposMovieAppMovieApp.APIControllersMoviesController.cs:line 90
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Host: localhost:7050
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36
:method: POST
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Content-Type: application/json
Origin: https://localhost:7050
Referer: https://localhost:7050/swagger/index.html
Content-Length: 158
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
sec-fetch-site: same-origin
sec-fetch-mode: cors
sec-fetch-dest: empty

最好在一个事务中完成所有操作,否则数据完整性可能会受损。试试这个

var movie = new Movie();
movie.Title = dto.Title;
movie.Description = dto.Description;
movie.Genre = dto.Genre;
movie.ReleasedYear = dto.ReleasedYear;
movie.PosterUrl = dto.PosterUrl;
movie.ProducerId = dto.ProducerId;

foreach (var ActorId in dto.ActorsId)
{
var movie_actor = new Movie_Actor();
movie_actor.Movie = movie;
movie_actor.ActorId = ActorId;
_context.movie_Actors.Add(movie_actor);
}
await _context.SaveChangesAsync();

更新

根据您的错误消息,您还必须将movie_Actors类映射到db表,因为它们显然有不同的名称。

最新更新