Итак, у меня есть сущность Customer и сущность Movie, и я правильно настроил отношения многие-ко-многим, и EF создал третью таблицу CustomerMovie с двумя FK, являющимися CustomerId и MovieId, которые являются первичным ключом. Итак, теперь, когда я начал создавать конечные точки, и все было нормально, пока я не добрался до конечной точки AddMovie, которая добавляет новый фильм в базу данных, это работает, но таблица CustomerMovie пуста, хотя в ней должен быть CustomerId клиента, который добавил фильм. и MovieId добавленного фильма, поэтому не уверен, что реализация конечной точки неверна для достижения этой цели или неверна конфигурация.
Это моя реализация конечной точки
[HttpPost("AddMovie"), Authorize]
public ActionResult<Movie> AddMovie([FromBody] MovieDto movie)
{
if (movie == null || !ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (_movieRepository.CheckMovieByTitle(movie.Title))
{
ModelState.AddModelError("", "Movie Already exists, if both share the same name add the release year with the name");
return StatusCode(422, ModelState);
}
var userEmail = User.FindFirstValue(ClaimTypes.Email);
Customer customerAdded = _customerRepository.GetCustomerByEmail(userEmail);
Movie addedMovie = _movieRepository.AddMovie(movie, userEmail, customerAdded);
return Ok(addedMovie);
}
и это то, что находится в классе репозитория (я использую шаблон репозитория)
public Movie AddMovie(MovieDto movie, string email, Customer customerAdded)
{
Movie newMovie = new Movie
{
Title = movie.Title,
Description = movie.Description,
Duration = movie.Duration,
ReleaseDate = movie.ReleaseDate,
Rating = 0,
AddedByUser = email
};
_context.Movie.Add(newMovie);
Save();
return newMovie;
}
что касается конфигурации отношений, это контекст:
public class ClassContextDb : DbContext
{
public ClassContextDb(DbContextOptions<ClassContextDb> options) : base(options)
{
}
public DbSet<Customer> Customer { get; set; }
public DbSet<Movie> Movie { get; set; }
public DbSet<Genre> Genre { get; set; }
public DbSet<MembershipType> MembershipType { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Customer>()
.HasMany(c => c.Movie)
.WithMany(m => m.Customer)
.UsingEntity(j => j.ToTable("CustomerMovie"));
}
}
а это свойства в самих моделях:
public virtual ICollection<Movie> Movie { get; set; } = new List<Movie>(); //in Customer class
public virtual ICollection<Customer> Customer { get; set; } = new List<Customer>(); // in Movie class
и это класс Movie для большего контекста
public class Movie
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int MovieId { get; set; }
[Required]
[MaxLength(30)]
public string Title { get; set; }
[Required]
public DateTime ReleaseDate { get; set; }
[Required]
[Range(0, 10)]
public float Rating { get; set; }
[Required]
[MaxLength(200)]
[MinLength(15)]
public string Description { get; set; }
[Required]
public int Duration { get; set; }
public string AddedByUser { get; set; }
public virtual ICollection<Customer> Customer { get; set; } = new List<Customer>();
public virtual ICollection<Genre> Genre { get; set; }
}
Пожалуйста, добавьте в вопрос объект фильма. Судя по добавленному вами коду, я не понимаю, где вы когда-либо устанавливали свойство Customer в фильме. AddMovie() принимает клиента, но ничего с ним не делает.
@Fran Спасибо, я добавил то, что вы упомянули, в свой ввод, что касается объекта клиента, который я передал через AddMovie(), это одно из решений, которые я пытался сделать, но, к сожалению, не смог в этом разобраться.
@Jay Привет, я использовал JWT для аутентификации и авторизации, а утверждения являются частью токена, в котором содержатся нужные вам данные, поэтому у меня есть адрес электронной почты в качестве утверждения в токенах, поэтому я могу получить к нему доступ через этот встроенный класс User и это работает, поскольку AddMovie() авторизован.
Вас не хватает newMovie.Customer.Add(customerAdded)
перед звонком _context.Movie.Add(newMovie);
Ниже приведен упрощенный пример:
Сущности
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public ICollection<Tag> Tags { get; } = [];
}
public class Tag
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Post> Posts { get; } = [];
}
Контекст БД
public class DataContext(DbContextOptions<DataContext> options) : IdentityDbContext(options)
{
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Post>()
.HasMany(e => e.Tags)
.WithMany(e => e.Posts)
.UsingEntity(
"PostTag",
l => l.HasOne(typeof(Tag)).WithMany().HasForeignKey("TagsId").HasPrincipalKey(nameof(Tag.Id)),
r => r.HasOne(typeof(Post)).WithMany().HasForeignKey("PostsId").HasPrincipalKey(nameof(Post.Id)),
j => j.HasKey("PostsId", "TagsId"));
}
}
Сохранить объекты
var tag = new Tag { Id = 1, Name = "EF Core Tutorial" };
context.Tags.Add(tag);
await context.SaveChangesAsync();
var post = new Post { Id = 1, Title = "How to do Many-To-Many relationship" };
post.Tags.Add(tag);
context.Posts.Add(post);
await context.SaveChangesAsync();
var posts = context.Posts.First();
var tags = context.Tags.First();
Большое спасибо Waqaz за этот ответ. Я новичок в этом стеке технологий, и синтаксис все еще кажется мне ошеломляющим, искренне благодарю вас за эту помощь.
не волнуйтесь, помогло ли это решить вашу проблему (если да, отметьте ответ)? рад объяснить приведенный выше код, если это необходимо.
Да, я проверил таблицу, и теперь она работает так, как задумано, хотя я получаю ошибку цикла самореференции с ответом 500, но я думаю, что это не будет слишком сложно исправить, но я рад, что конечная точка работает и база данных работает как Я хотел и еще раз очень благодарен за ваш ответ.
var userEmail = User.FindFirstValue(ClaimTypes.Email);
мне это кажется странным