locked
Foreignkey is not updated with primarykey in entity framework core RRS feed

  • Question

  • User-843276596 posted

    Hi, Im a newbie an I made a simple application (code first) with asp.net core (5.0) with entity framework core 5.0. I have two tables that I have created with EF core namely a table Profile and a table Education that are linked to each other in a one-to-one relationship. Here are the classes to create the tables

        public class Profile
        {
            [Key]
            public int ProfileId { get; set; }
            [Required]
            public string Name { get; set; }
            [Required]
            public string MainPositions { get; set; }
            [Required]
            public string KeyCompetences { get; set; }
            [Required]
            public string PersonalDetails { get; set; }
            [Required]
            public string Languages { get; set; }
    
            public virtual Education Education { get; set; }
        }
        public class Education
        {
            [Key]
            public int EducationId { get; set; }
            public string EducationTitle { get; set; }
            public string University { get; set; }
            public string Thesis { get; set; }
    
            public int ProfileId { get; set; }
            public virtual Profile Profile { get; set; }
        }

    This is my fluent api:

            protected override void OnModelCreating(ModelBuilder modelbuilder)
            {
                base.OnModelCreating(modelbuilder);
    
                modelbuilder.Entity<Profile>()
                        .HasOne(x => x.Education)
                       .WithOne();
            }

    So I want to enter data via a view into table Profile and that goes wel and when I want to enter data into table Education via a view I get an 'unhandled exception'. (InvalidOperationException: Both relationships between 'Education' and 'Profile.Education' and between 
    'Education.Profile' and 'Profile' could use {'ProfileId'} as the foreign key. To resolve this, configure 
    the foreign key properties explicitly in 'OnModelCreating' on at least one of the relationships.

    What I want is that the primary key of Profile table (ProfileId) is inserted into the Education table as a foreignkey when I enter data via a view of Education. What am I doing wrong here?

    Sunday, December 6, 2020 2:19 PM

Answers

  • User-843276596 posted

    Hi Jerry, I solved it! The problem was in the view create of the Education controller.

    It should have been asp-for="ProfileId":

                <div class="form-group">
                    <label asp-for="ProfileId" class="control-label"></label>
                    <select asp-for="ProfileId" class="form-control" asp-items="ViewBag.ProfileId"></select>
                </div>

    Instead of

                <div class="form-group">
                    <label asp-for="Profile" class="control-label"></label>
                    <select asp-for="Profile" class="form-control" asp-items="ViewBag.ProfileId"></select>
                </div>

    plus I have added a ViewData like this and now it works

            // GET: Educations/Create
            public IActionResult Create()
            {
                ViewData["ProfileId"] = new SelectList(_context.Profile, "ProfileId", "ProfileId");
                return View();
            }
    
            // POST: Educations/Create
            // To protect from overposting attacks, enable the specific properties you want to bind to.
            // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
            [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> Create([Bind("EducationId,EducationTitle,University,Thesis,ProfileId")] Education education)
            {
                if (ModelState.IsValid)
                {
                    _context.Add(education);
                    await _context.SaveChangesAsync();
                    return RedirectToAction(nameof(Index));
                }
                ViewData["ProfileId"] = new SelectList(_context.Profile, "ProfileId", "ProfileId", education.ProfileId);
                return View(education);
                }

    Thanks for your input.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, December 8, 2020 6:53 PM

All replies

  • User-843276596 posted

    I did use this code in the last link, but was not able to migrate to db because it said that I had to use virtual keyword when linking to tables. So I left it at that.

            protected override void OnModelCreating(ModelBuilder modelbuilder)
            {
                base.OnModelCreating(modelbuilder);
    
                modelbuilder.Entity<Profile>()
                        .HasOne(x => x.Education)
                       .WithOne(i => i.Profile).HasForeignKey<Education>(x => x.ProfileId);
            }
        public class Profile
        {
            [Key]
            public int ProfileId { get; set; }
            [Required]
            public string Name { get; set; }
            [Required]
            public string MainPositions { get; set; }
            [Required]
            public string KeyCompetences { get; set; }
            [Required]
            public string PersonalDetails { get; set; }
            [Required]
            public string Languages { get; set; }
    
            public virtual Education Education { get; set; }
        }
        public class Education
        {
            [Key]
            public int EducationId { get; set; }
            public string EducationTitle { get; set; }
            public string University { get; set; }
            public string Thesis { get; set; }
    
            public int ProfileId { get; set; }
            public virtual Profile Profile { get; set; }
    
        }

    But even after altering my OnModelCreating method it gave me this:

    SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Educations_Profiles_ProfileId". The conflict occurred in database "aspnet-CV_App_Core_V2", table "dbo.Profiles", column 'ProfileId'.
    The statement has been terminated.

    Sunday, December 6, 2020 4:19 PM
  • User475983607 posted

    For the second time, your class looks like a one-to-one but I think you want a one-to-many?  You are the only one that knows...  Frankly, the design is a bit confusing.  How does a profile relate to education in your application?

    public class Profile
    {
        [Key]
        public int ProfileId { get; set; }
        [Required]
        public string Name { get; set; }
        [Required]
        public string MainPositions { get; set; }
        [Required]
        public string KeyCompetences { get; set; }
        [Required]
        public string PersonalDetails { get; set; }
        [Required]
        public string Languages { get; set; }
    
        public ICollection<Education> Educations { get; set; }
    }

    Sunday, December 6, 2020 4:38 PM
  • User1312693872 posted

    Hi, Dennis_73

    When you enter data, If you also insert a profileId to a Education entity, you should check whether the 'ProfileId' already exists in Profile

    entity. Because ProfileId in Education is a foreignkey, you can't make it point to a non-existent value. For example, If you insert profileId=3 to

    Education,but profileId in Profile has just 1 and 2, then this error will occur. This could be one of the reasons.

    You can check the above first, and if error still exists, you should better tell us more details about what you want to do, so we can make a

    similiar demo for you to refer.

    Best Regards,

    Jerry Cai

    Monday, December 7, 2020 2:41 AM
  • User-843276596 posted

    Hi Jerry, I updated the code a bit. I got it working but now, but it still does not work as expected. namely the Foreignkey 'ProfileId'is now 'NULL'.

        public class Profile
        {
            [Key]
            public int ProfileId { get; set; }
            [Required]
            public string Name { get; set; }
            [Required]
            public string MainPosition { get; set; }
            [Required]
            public string KeyCompetence { get; set; }
            [Required]
            public string PersonalDetail { get; set; }
            [Required]
            public string Language { get; set; }
    
            public virtual Education Education { get; set; }
        }
        public class Education
        {
            [Key]
            public int EducationId { get; set; }
            public string EducationTitle { get; set; }
            public string University { get; set; }
            public string Thesis { get; set; }
    
            [ForeignKey("ProfileId")]
            public virtual Profile Profile { get; set; }
    
        }
    }
            protected override void OnModelCreating(ModelBuilder modelbuilder)
            {
                base.OnModelCreating(modelbuilder);
    
                modelbuilder.Entity<Profile>()
                        .HasOne(x => x.Education)
                       .WithOne(i => i.Profile);

    Monday, December 7, 2020 5:52 PM
  • User1312693872 posted

    Hi,Dennis_73

    That's not the point, we want to know how you insert it, you sent us the model, we can't reproduce your problem. Do you just want to insert

    Education or along with the Profile? 

    Your model design would generate the foreign key by default in database. But if you want to insert data into Education table with foreign keys,

    you need to add the key to your model.

    This is a demo to insert Education:

    public class Education
        {
            [Key]
            public int EducationId { get; set; }
            public string EducationTitle { get; set; }
            public string University { get; set; }
            public string Thesis { get; set; }
    
            public int ProfileId { get; set; } //foreign key
            public virtual Profile Profile { get; set; }
    
        }

    Controller:

     [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> Create(Education edu)
            {
                if (ModelState.IsValid)
                {
                    Education edu1 = _context.Educations.Find(edu.ProfileId); //search id in Education
                    Profile p1 = _context.Profiles.Find(edu.ProfileId);  //search id in Profile
                    if (edu1 != null || p1==null)   //If Education already has id or Profile doesn't have that id, error
                    {
                        return View("error page");
                    }
                    else
                    {
                        _context.Add(edu);
                        await _context.SaveChangesAsync();   // create done.
                        return RedirectToAction(nameof(Index));
                    }               
                }
                return View("error page");
            }

    Results:

    And about CRUD in .net core mvc, view this tutorial

    Best Regards,

    Jerry Cai

    Tuesday, December 8, 2020 2:58 AM
  • User-843276596 posted

    Hi Jerry, I solved it! The problem was in the view create of the Education controller.

    It should have been asp-for="ProfileId":

                <div class="form-group">
                    <label asp-for="ProfileId" class="control-label"></label>
                    <select asp-for="ProfileId" class="form-control" asp-items="ViewBag.ProfileId"></select>
                </div>

    Instead of

                <div class="form-group">
                    <label asp-for="Profile" class="control-label"></label>
                    <select asp-for="Profile" class="form-control" asp-items="ViewBag.ProfileId"></select>
                </div>

    plus I have added a ViewData like this and now it works

            // GET: Educations/Create
            public IActionResult Create()
            {
                ViewData["ProfileId"] = new SelectList(_context.Profile, "ProfileId", "ProfileId");
                return View();
            }
    
            // POST: Educations/Create
            // To protect from overposting attacks, enable the specific properties you want to bind to.
            // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
            [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> Create([Bind("EducationId,EducationTitle,University,Thesis,ProfileId")] Education education)
            {
                if (ModelState.IsValid)
                {
                    _context.Add(education);
                    await _context.SaveChangesAsync();
                    return RedirectToAction(nameof(Index));
                }
                ViewData["ProfileId"] = new SelectList(_context.Profile, "ProfileId", "ProfileId", education.ProfileId);
                return View(education);
                }

    Thanks for your input.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, December 8, 2020 6:53 PM
  • User1312693872 posted

    Hi,Dennis_73

    I'm glad that you have solved it, then you can mark the useful answers, so other users can easily located the helpful answers.

    Best Regards,

    Jerry Cai

    Wednesday, December 9, 2020 1:47 AM