У меня есть следующие сущности:
public class Book {
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public int? AddedByUserId { get; set; }
public virtual ICollection<Author> Authors { get; set; } = new HashSet<Author>();
}
public class Author {
public int Id { get; set; }
public int BookId { get; set; }
public string Name { get; set; } = string.Empty;
public int? AddedByUserId { get; set; }
public Book Book { get; set; } = new Book();
}
Я пытаюсь добавить Author
и установить существующее значение BookId
.
var newAuthor = new Author();
newAuthor.BookId = 1;
_dbContext.Authors.Add(author);
Когда я проверяю ChangeTracker
, чтобы увидеть, что собирается делать DbContext:
var longView = _dbContext.ChangeTracker.DebugView.LongView;
Это означает, что будут добавлены Author
, Book
и User
.
Author {Id: -2147482646} **Added**
Id: -2147482646 PK Temporary
AddedByUserId: 1
DateAdded: '11/25/2022 8:22:11 PM'
Name: 'My Author Name'
BookId: -2147482643 FK Temporary
Book: {Id: -2147482643}
Book {Id: -2147482643} **Added**
Id: -2147482643 PK Temporary
AddedByUserId: -2147482645 FK Temporary
DateAdded: '1/1/0001 12:00:00 AM'
Name: ''
AddedByUserId: {Id: -2147482645}
User {Id: -2147482645} **Added**
Id: -2147482645 PK Temporary
DateAdded: '1/1/0001 12:00:00 AM'
Name: <null>
RowVersion: <null>
Как я могу сделать так, чтобы при установке внешнего ключа Author
добавлялся только новый BookId
? Должен ли я устанавливать объекты вместо идентификаторов?
newAuthor.Book = _dbContext.Book.Find(1);
newAuthor.Book
не является нулевым и не отслеживается EF, поэтому он будет рассматривать его как новую книгу. Есть несколько вариантов:
var newAuthor = new Author();
newAuthor.BookId = 1;
newAuthor.Book = null;
var newAuthor = new Author();
newAuthor.Book.Id = 1;
_dbContext.Books.Attach(newAuthor.Book);
_dbContext.Authors.Add(author);
Вы правы, я инициализирую Book
в классе Author
. Я выберу модифицированную версию 1, которая просто позволит Book
быть обнуляемой и не инициализировать ее в Author
. Вариант 3 — очень хороший подход, но я действительно не хочу выполнять поиск в базе данных, когда я уже знаю идентификатор.
Да, не изменяйте внешние ключи напрямую, вместо этого позвольте ef core выполнить свою работу, установив сам объект. Также не new()
ссылайтесь на свойства навигации:
public Book Book { get; set; } = new Book();
делать это для свойств навигации коллекции хорошо, потому что это позволяет избежать нулевых исключений, например, при попытке добавить в коллекцию.
Возможно, вы захотите изменить отношение
Book
иAuthor
на N:M, поскольку авторы могут писать несколько книг, а книги могут быть написаны несколькими авторами.