Timon Post
Timon Post

Reputation: 2879

How to have a one to one, and a many to one, relation ship EF?

Context:

I am working with entity framework core code first approach. The entity framework core is located in .Net core class library.

Situation:

Relations

I have one table named Question and a table named AnswerOption. These tables have relationships like:

A question has multiple answer options and one of them is the right answer.

Code

public class Question
{
     [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
     public int Id { get; set; }

     public virtual AnswerOption RightAnswerId { get; set; }
     public virtual AnswerOption RightAnswer { get; set; }

     public virtual ICollection<AnswerOption> AnswerOptions { get; set; } 
}

public class AnswerOption
{
     [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
     public int Id { get; set; }               

     public int QuestionId { get; set; }

     public virtual Question Question { get; set; }
}

Question

When the database is created it throws the following error:

'Unable to determine the relationship represented by navigation property 'AnswerOption.Question' of type 'Question'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.'

I have try'ed to set the relation ship manually whit entity framework relationship builder in the OnModelCreating() method of DbContext class but don't exactly know how to get this relationship to work.

How can I declare one to one and many to one relationships between those tables?

Upvotes: 1

Views: 3917

Answers (1)

David Browne - Microsoft
David Browne - Microsoft

Reputation: 89386

Here's how to do that in EF Core. AnswerOption should have a compound key for performance, and so you can enforce that the RightAnswer for a question must be one of the AnswerOptions for that question, which requires fluent config in EF Core. Otherwise you just have to annotate the ForeignKey and InverseProperty, and make RightAnswerId nullable, so you can insert a Question without a RightAnswer.

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
//using Microsoft.Samples.EFLogging;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;


namespace EFCore2Test
{
    public class Question
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        public virtual int? RightAnswerId { get; set; }

        [ForeignKey("Id,RightAnswerId")]
        public virtual AnswerOption RightAnswer { get; set; }

        public virtual ICollection<AnswerOption> AnswerOptions { get; set; }
    }

    public class AnswerOption
    {       
        public int QuestionId { get; set; }

        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        [InverseProperty("AnswerOptions")]
        public virtual Question Question { get; set; }
    }
    public class Db : DbContext
    {
        public DbSet<Question> Questions { get; set; }
        public DbSet<AnswerOption> AnswerOptions { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<AnswerOption>().HasKey(e => new { e.QuestionId, e.Id });
            base.OnModelCreating(modelBuilder);
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Server=(local);Database=Test2;Trusted_Connection=True;MultipleActiveResultSets=true");
            base.OnConfiguring(optionsBuilder);
        }
    }




    class Program
    {


        static void Main(string[] args)
        {
             using (var db = new Db())
            {

                db.Database.EnsureDeleted();
               // db.ConfigureLogging(s => Console.WriteLine(s));
                db.Database.EnsureCreated();
                for (int i = 0; i < 100; i++)
                {
                    var q = new Question();
                    db.Questions.Add(q);

                    var a = new AnswerOption();
                    a.Question = q;
                    var b = new AnswerOption();
                    b.Question = q;
                    db.SaveChanges();

                    q.RightAnswer = a;
                    db.SaveChanges();
                }

            }

            Console.WriteLine("Hit any key to exit");
            Console.ReadKey();
        }
    }
}

Upvotes: 2

Related Questions