How to fix this error: 'The instance of entity type cannot be tracked...'

.net-core asp.net-core c# entity-framework entity-framework-core

Question

Here is full error:

System.InvalidOperationException: "The instance of entity type 'Book' cannot be tracked because another instance with the key value '{BookId: 382234c3-721d-4f34-80e5-57657bbbbb32}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached."

It throws when I try to add new entity to my DB from my service in business logic layer. I used EF Core, made repositories and unit of work for interaction with DB in my data access layer.

Here is some code where an error throws, it is in repository:

public void Create(T entity)
{
    this.LibraryContext.Set<T>().Add(entity);
}

It, in turn, is called from here:

public bool TakeBookById(Guid bookId, Guid studentId, DateTime issueDate) // student takes the book from library
        {
            var book = mapper.Map<BookDto>(unit.Books.FindByCondition(x => x.BookId == bookId).FirstOrDefault()); // take that book for later using 

            if (book != null && book.IsAvailable == true) // if this book is available
            {
                var student = mapper.Map <StudentDto>(unit.Students.FindByCondition(x => x.StudentId == studentId).FirstOrDefault()); // look for that student
                if (student != null && student.LibraryCard.Fields.Where(x => x.Book.IsAvailable == false).Count() <= 10)
                { // if student exists and his/her limit of non-returned books is not exceeded
                    var libraryCard = mapper.Map<LibraryCardDto>(student.LibraryCard); // take his/her library card
                    unit.LibraryCardFields.Create( // create library card's field with current data
                        mapper.Map<LibraryCardField> ( 
                            new LibraryCardFieldDto()
                            {
                                Id = Guid.NewGuid(), // generate new id
                                Book = book, // student got this book
                                LibraryCard = libraryCard, // field is in this library card
                                IssueDate = issueDate, // note current date
                                ReturnDate = null // student still didn't return it
                            } )
                    ); 

                    unit.Save(); // save changes
                    return true;
                }
                else { return false; }    
            }
            else { return false; }    
        }

Here is the code from where I call the service method, as hard-coded as possible for clarity:

StudentService sts = new StudentService("Server=.\\SQLEXPRESS;Database=StudentsLibrary;Trusted_Connection=True;");

sts.TakeBookById(Guid.Parse("382234C3-721D-4F34-80E5-57657BBBBB32"), Guid.Parse("382C74C3-721D-4F34-80E5-57657B6CBC27"), DateTime.Now);

And I also apply the methods that I use from the repositories:

public IEnumerable<T> FindAll()
{
     return this.LibraryContext.Set<T>();
}
public IEnumerable<T> FindByCondition(Expression<Func<T, bool>> expression)
{
     return this.LibraryContext.Set<T>().Where(expression);
}

I didn't use AsNoTracking() in repository because I want Lazy Loading to work (I don't want to write all that Inlude&ThenInclude stuff for each my model).

And I thought, if specifically this book is being tracked, then I can make context stop tracking it. I wrote something like this:

public void Reset()
{
     var entries = libraryContext.ChangeTracker.Entries().ToArray();
     foreach (var entry in entries)
     {
         entry.State = EntityState.Detached;
     }
}

And tried this one:

public void Reset()
{
     libraryContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
}

And do you know what? There is still that error. I don't know maybe it all because of mappers?

UPDATE: It IS because of mappers. But how can I fix this situation? It works if in Create method I create object of my DAL model. I cannot create object of my BLL model and then map it. EF can't stand this stuff.

Help me, please. I'm new to EF.

1
1
12/9/2019 8:14:45 PM

Popular Answer

Drop the Auto Mapper. It takes seconds to type your own extension methods and you easily have full control over it.

Your main issue is that your creating a DTO then converting it to an entity and you haven't configured that correctly. Skip that part entirely and just create the entity. It doesn't make sense to use a DTO like this. Look at your code below.

 unit.LibraryCardFields.Create( // create library card's field with current data
                        mapper.Map<LibraryCardField> ( 
                            new LibraryCardFieldDto()
                            {
                                Id = Guid.NewGuid(), // generate new id
                                Book = book, // student got this book
                                LibraryCard = libraryCard, // field is in this library card
                                IssueDate = issueDate, // note current date
                                ReturnDate = null // student still didn't return it
                            } )
                    ); 

Change this to create your own extension methods and convert it yourself.

Take this for example.

Supposed you passed in a DTO instead of creating it.

var LibraryCardField = LibraryCardFeildDto.ToEntity();//ToEntity is your extension method
 unit.LibraryCardFields.Create(LibraryCardField);

Create a new class for the extension methods.

public static class ExampleMapperClass //or w/e you want to call it{

  public static LibaryCardField ToEntity(this LibraryCardFieldDto lbf){
      return new LibraryCardField{
        Id = lbf.Id,
        Book = lbf.book.ToEntity(),//create another extension method for this one
        LibraryCard  = LibraryCardDto.ToEntity(),//same here
        IssueDate = lbf.issueDate,
        ReturnDate = lbf.returnDate
      };
  }  
}
0
12/9/2019 10:28:28 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow