I have the following entities:
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();
}
I try to add an Author
and set the BookId
to an existing value.
var newAuthor = new Author();
newAuthor.BookId = 1;
_dbContext.Authors.Add(author);
When I inspect the ChangeTracker
to see what DbContext is going to do:
var longView = _dbContext.ChangeTracker.DebugView.LongView;
It indicates that Author
, Book
, and User
will all be added.
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>
How can I do it so that only the new Author
gets added when the BookId
foreign key is set? Should I be setting objects instead of Ids?
newAuthor.Book = _dbContext.Book.Find(1);
CodePudding user response:
newAuthor.Book
is not null and is not tracked by EF so it will consider it as a new book. There are multiple options:
- "Clear" the book object:
var newAuthor = new Author();
newAuthor.BookId = 1;
newAuthor.Book = null;
- Attach the book:
var newAuthor = new Author();
newAuthor.Book.Id = 1;
_dbContext.Books.Attach(newAuthor.Book);
_dbContext.Authors.Add(author);
- Fetch the book from database (as you have suggested yourself)
CodePudding user response:
Yes, don't modify the foreign keys directly, instead let ef core do its job by setting the object itself. Also don't new()
reference navigation properties:
public Book Book { get; set; } = new Book();
doing it for collection navigation properties is good because it avoids null exceptions when trying to add to the collection, for example.