Davood Kazemi
Davood Kazemi

Reputation: 105

Can't update value: 'Primary Key' has a temporary value while attempting to change the entity's state to 'Modified'

This is my first ASP .Net Core project. It will hold directors. Each director has a page that shows a list of his/her movies.

I have two classes. Movie:

public class Movie
    {
        public int MovieId { get; private set; }
        public int DirectorId { get; set; }
        [Required]
        public string Title { get; set; }
        public string Year { get; set; }
        public string Description { get; set; }
    }

And Director:

public class Director
    {
        public Director()
        {
            Movies = new List<Movie>();
        }
        public int DirectorId { get; private set; }
        [Required]
        public string Name { get; set; }
        public string Country { get; set; }
        public string Bio { get; set; }
        public List<Movie> Movies { get; set; }
    }

But I have a problem with editing Directors. As I want to save changes I get this error:

InvalidOperationException: The property 'DirectorId' on entity type 'Director' has a temporary value while attempting to change the entity's state to 'Modified'. Either set a permanent value explicitly or ensure that the database is configured to generate values for this property.

I use this line of code in Index page to navigate to Edit page:

<a asp-page="./../Movies/Create" asp-route-DirectorId="@item.DirectorId">Add Movie</a>

Photo of Index page: Please click to see the photo


The code in Edit.cshtml.cs:

public class EditModel : PageModel
{
    private readonly MastersOfCinema.Data.Context _context;

    public EditModel(MastersOfCinema.Data.Context context)
    {
        _context = context;
    }

    [BindProperty]
    public Director Director { get; set; }

    public async Task<IActionResult> OnGetAsync(int? directorId)
    {
        if (directorId == null)
        {
            return NotFound();
        }

        Director = await _context.Director.FirstOrDefaultAsync(m => m.DirectorId == directorId);

        if (Director == null)
        {
            return NotFound();
        }
        return Page();
    }

    // To protect from overposting attacks, enable the specific properties you want to bind to, for
    // more details, see https://aka.ms/RazorPagesCRUD.
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _context.Attach(Director).State = EntityState.Modified;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!DirectorExists(Director.DirectorId))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return RedirectToPage("./Index");
    }

    private bool DirectorExists(int id)
    {
        return _context.Director.Any(e => e.DirectorId == id);
    }
}

Apparently, Something upsets this very line:

_context.Attach(Director).State = EntityState.Modified;

Perhaps it is about the primary key (DirectorId), As the error suggests.

Edit page screenshot: Please Click to see Edit page


Edit.cshtml :

@page
@model MastersOfCinema.Pages.Directors.EditModel

@{
    ViewData["Title"] = "Edit";
}

<h1>Edit</h1>

<h4>Director</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>

            <div class="form-group">
            <label asp-for="Director.DirectorId" class="control-label"></label>
            <input asp-for="Director.DirectorId" class="form-control" />

            </div>

            <div class="form-group">
                <label asp-for="Director.Name" class="control-label"></label>
                <input asp-for="Director.Name" class="form-control" />
                <span asp-validation-for="Director.Name" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Director.Country" class="control-label"></label>
                <input asp-for="Director.Country" class="form-control" />
                <span asp-validation-for="Director.Country" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Director.Bio" class="control-label"></label>
                <input asp-for="Director.Bio" class="form-control" />
                <span asp-validation-for="Director.Bio" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="./Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Additional information:

Context.cs (Uses EF Core) :

public class Context : DbContext
    {
        public Context (DbContextOptions<Context> options)
            : base(options)
        {
        }

        public DbSet<MastersOfCinema.Models.Director> Director { get; set; }
        public DbSet<MastersOfCinema.Models.Movie> Movie { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(
                "Data Source = (localdb)\\MSSQLLocalDB; Initial Catalog = MastersOfCinama");
        }


    }

Thanks for reading and for any help.

Upvotes: 1

Views: 723

Answers (1)

Jakub Kozera
Jakub Kozera

Reputation: 3473

Try removing the private setter from:

public int DirectorId { get; private set; }

Instead it should look like this:

public int DirectorId { get; set; }

Upvotes: 2

Related Questions