简体   繁体   中英

EF Core One to Many adding new object

I have tried many ways but I am still hitting different kinds of errors for each solution. I have tried to stop tracking, tried adding challenge itself, updating competition but all of them doesn't seem to work.

I basically have 1 competition to many challenges, and in this scenario, 1 competition and 1 challenge is already present, and I am adding another challenge which has a Foreign Key linking with the competition . I understand that I have asked a similar question before, but that was for bulk creation of 1 competition to many categories. I am thinking this is more like an update operation, which doesn't seem to be working. Appreciate your help a lot! :)

InvalidOperationException: The instance of entity type 'Challenge' cannot be tracked because another instance with the same key value for {'ID'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.

Competition Model Class:

public class Competition
{
    [Key]
    public int ID { get; set; }

    public ICollection<CompetitionCategory> CompetitionCategories { get; set; }
    public ICollection<Challenge> Challenges { get; set; }
}

Challenge Model Class:

public class Challenge
{
    [Key]
    public int ID { get; set; }

    [ForeignKey("CompetitionID")]
    public int CompetitionID { get; set; }
    [Display(Name = "Competition Category")]
    [ForeignKey("CompetitionCategoryID")]
    public int CompetitionCategoryID { get; set; }
}

Controller:

public async Task<IActionResult> Create([Bind("ID,XXX,CompetitionID,CompetitionCategoryID")] Challenge challenge)
{
    var competition = await _context.Competitions
    .Include(c => c.CompetitionCategories)
    .Include(c1 => c1.Challenges)
    .AsNoTracking()
    .FirstOrDefaultAsync(m => m.ID == challenge.CompetitionID);

    if (ModelState.IsValid)
    {
        //_context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
        competition.Challenges.Add(challenge);

        _context.Update(competition);
        _context.Entry(competition).State = EntityState.Detached;
        _context.Entry(competition.Challenges).State = EntityState.Detached;
        await _context.SaveChangesAsync();
        //_context.Add(challenge);
        //await _context.SaveChangesAsync();
        //return RedirectToAction(nameof(Index));
        return RedirectToAction("Index", "Challenges", new { id = challenge.CompetitionID });
    }

     return View();
 }

Update: I have actually tried to just add challenge itself but it also throws up another error. Really quite at a lost of what to do.

SqlException: Cannot insert explicit value for identity column in table 'Challenges' when IDENTITY_INSERT is set to OFF. System.Data.SqlClient.SqlCommand+<>c.b__122_0(Task result)

DbUpdateException: An error occurred while updating the entries. See the inner exception for details. Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)

Update 2: Removing the ID from the binding works as there was some unknown ID value being passed in and being tracked. Ivan's answer on adding a new object with Foreign Key is correct.

public async Task<IActionResult> Create([Bind("XXX,CompetitionID,CompetitionCategoryID")] Challenge challenge)
{
    //Codes here
    _context.Add(challenge);
    await _context.SaveChangesAsync();
}

Working with disconnected entities is not easy and requires different techniques depending of the presense/absense of navigation / innverse navigation and FK properties in the entity model.

Your Challenge class has explicit FK properties and no navigation properties. Adding new object like this is the simplest operation - just call DbContext.Add or DbSet.Add :

_context.Add(challenge);
await _context.SaveChangesAsync();

However, the exception you are getting makes me think that the Challenge object received by the Create method has the PK property Id populated with a value of an existing Challenge . If you really want to add new Challenge and Id is auto-generated, exclude Id from the binding or make sure it is set to 0 (zero) before calling Add .

For more info, see Disconnected Entities and related links in the EF Core documentation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM