How do i create One-to-One mapping in EF 6 using Data Annotation approach - entity-framework

I am using EF 6.1.1.
I am unable to figure out how to create One-to-One relationship between two classes/tables with both entities have their owns PKs. I originally posted question link but could not get much help on it OR i am not able to get it. So, here i am putting my question in simple way.
Appreciate if someone can share thoughts on it.
My Requirement:
I would like create One-To-One relationship between Principle and Dependant with 'Id' from Principle class acts as Foreign Key in dependant class.
Principle Class
public class Student
{
public string FullName {get; set;}
}
Dependant Class
public class StudentReport
{
public string RollNumber { get; set; }
public string StudentType { get; set; }
}

Add PKs – EF requires this:
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
}
Note that EF 5 and later supports naming conventions: Id indicates a primary key. Alternately, it also supports the name of the class followed by "Id", so the above keys could have been StudentId for Student and StudentReportId for StudentReport, if you wished.
Add the foreign relation as a navigation property to at least one of the tables – in this case, you stated that StudentReport is the dependent, so let's add it to that one:
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}
Again – by naming convention – EF determines that a single Student property on StudentReport indicates that this is a navigational property associated with a foreign key. (By defining only the Student property, but no foreign key property, you are indicating that you don't care what EF names the associated FK ... basically, you're indicating you'll always access the related Student via the property.)
If you did care about the name of the FK property, you could add it:
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public int StudentId { get; set; }
public Student Student { get; set; }
}
Again – by naming convention – EF determines that StudentId is the FK associated with the Student property because it has the class name, "Student", followed by "Id".
All of this, so far, has been using conventions as defined in Entity Framework Code First Conventions, but Data Annotations are also an option, if you wish:
public class Student
{
[Key]
public int Id { get; set; }
public string FullName { get; set; }
}
public class StudentReport
{
[Key]
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
[ForeignKey("Student")]
public int StudentId { get; set; }
public Student Student { get; set; }
}
Doing this is actually a good idea, because it makes clearer your intent to other programmers that might not be aware of EF Conventions – but can easily infer them from simply looking at EF Data Annotations – and is still less cumbersome than Fluent API.
UPDATE
I just realized, I left this as a one-to-many, with enforcement of the one-to-one relationship being left to do in the code using this model. To enforce the one-to-one in the model, you could add a navigation property to the Student class going the other way:
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
public StudentReport StudentReport { get; set; }
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}
However, that's going to break, because EF doesn't know which entity to insert first on an add. To indicate which is dependent, you have to specific that the dependent class' PK is the FK to the principal class (this enforces one-to-one because – in order for a Student/StudentReport pair to be associated – their Id properties must be the exact same value):
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
public StudentReport StudentReport { get; set; }
}
public class StudentReport
{
[ForeignKey("Student")]
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}
or, using the full set of Data Annotations from earlier:
public class Student
{
[Key]
public int Id { get; set; }
public string FullName { get; set; }
public StudentReport StudentReport { get; set; }
}
public class StudentReport
{
[Key, ForeignKey("Student")]
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}

Related

The entity type 'Program' requires a primary key to be defined

I am trying to make a simple website that tracks students, programs, and classes. I've created the entities and I'm getting an error when trying to add the migration.
"The entity type 'Program' requires a primary key to be defined."
I have tried using the [Key] attribute and there is an Id field. The other table was created just fine. What else should I try?
Here is the problem class:
public class Program
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool UseRanks { get; set; }
}
Here is another table that I had no problems creating a migration for:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string CellPhone { get; set; }
public string HomePhone { get; set; }
public string WorkPhone { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public DateTime BirthDate { get; set; }
}
Here is what is in my ApplicationDbContext class:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
//public DbSet<Attendance> Attendances { get; set; }
public DbSet<Person> People { get; set; }
public DbSet<Bill> Bills { get; set; }
//public DbSet<Session> Sessions { get; set; }
public DbSet<Program> Programs { get; set; }
}
I've commented out the other entities because I was trying to add them one at a time. Trying to add a migration with all the entities resulted in the same error with the same specific class.
Complete shot in the dark, but based on the name of this class, I'm guessing you're referencing the wrong Program. Make sure that your DbSet<Program> is actually using your Program entity and not something like the Program class used at the console app level. You'll likely need to explicitly use the namespace, i.e. DbSet<MyApp.Models.Program>.
You might also consider changing the name of the class to remove any chance of ambiguity. There's some class names that are just going to wreck havoc trying to use them because they'll conflict with framework stuff constantly. It's usually more hassle than it's worth just to have that particular name. Program is one of those.
You can try to use this way:
public class Program
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool UseRanks { get; set; }
}
Adding [Key] attribute to the Id property.
In the file ApplicationDbContext.cs, you can override OnModelCreating method:
public DbSet<Program> Programs { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Program>().ToTable("Programs").HasKey(x => x.Id);
}

Entity Framework relationship between another fields than id

I have two class (tables)
Person { id(primary key) , code, name, address, ...}
Order {id(primary key) , order_number, customer, create_date, description, ...}
I want to create relationship between Person.code and Order.customer (one two many).
How can I create that relationship in EF code first.
OK it has an easy solution
[Table("Person")]
public partial class Person
{
public long ID { get; set; }
[Key()]
[StringLength(10)]
public string code { get; set; }
[StringLength(100)]
public string name { get; set; }
[Column(TypeName = "text")]
public string address{ get; set; }
public ICollection<Order> Orders { get; set; }
}
and for order
[Table("Order")]
public partial class Order
{
public long ID { get; set; }
public int order_number { get; set; }
[StringLength(10)]
public string customer { get; set; }
[Column(TypeName = "text")]
public string description { get; set; }
//...
[ForeignKey("customer")]
public Library Person { get; set; }
}
I will create a new question about specification various composite keys per each navigation property.

EF Code first : set optional one to one relationship with data annotation

I've the following situation I try to solve : I've 2 tables, a Course table with some fields and a CourseDescription table which is optional (so Course may have a CourseDescription but CourseDescription must have a Course). I'm trying to set this up. So far, here's what I have :
public class Course
{
[Key, Column("Key_Course")]
public int ID { get; set; }
public string Name { get; set; }
public virtual CourseDescription CourseDescription { get; set; }
}
public class CourseDescription
{
[Key, ForeignKey("Course")]
public int ID { get; set; }
public string Description { get; set; }
public string PreRequis { get; set; }
public int CoursesID { get; set; }
[ForeignKey("CoursesID")]
public Course Course { get; set; }
}
This "works" meaning that EF doesn't complains about my model but the relation is not properly done because EF associate the PK of CourseDescription with the PK of Course. In my database, this is not the case (ex : CourseDescription.ID=1 is associated with CourseDescription.CoursesID=3, not 1).
Is there a way to fix that with data annotation ? I know I can use the fluent API but I don't want to override the model building just for that (unless there's no other way).
Thanks
Well, I think you have two choices:
Configure an one to many relationship
If you want to map the FK of the relationship between Course and CourseDescription, and you don't want to declare that FK property as Key of the CourseDescription entity, then, you don't have other choice that configure an one-to-many relationship. In that case your model would be like this:
public class Course
{
[Key, Column("Key_Course")]
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<CourseDescription> CourseDescriptions { get; set;}
}
public class CourseDescription
{
[Key]
public int ID { get; set; }
public string Description { get; set; }
public string PreRequis { get; set; }
[ForeignKey("Course")]
public int CourseID { get; set; }
public Course Course { get; set; }
}
Configure an one-to-one relationship but not map the FK of the
relationship
The only way that EF lets you map the FK in an one-to-one relationship is when the FK is declared as a PK too, so if you want to have diferent Ids in both entities and you want to stablish an one-to-one relationship, then you could do something like this:
public class Course
{
[Key, Column("Key_Course")]
public int ID { get; set; }
public string Name { get; set; }
public CourseDescription CourseDescription { get; set;}
}
public class CourseDescription
{
[Key]
public int ID { get; set; }
public string Description { get; set; }
public string PreRequis { get; set; }
[Required]
public Course Course { get; set; }
}
And work with the navigations properties.
It looks like you should not use ForeignKey attribute for ID property of CourseDescription class as you don't want to have an association between primary keys. Try to remove it.
Edit: It looks like I misunderstood the question previous time.
You can have your CourseDescription this way.
public class CourseDescription
{
[Key, ForeignKey("Course")]
public int ID { get; set; }
public string Description { get; set; }
public string PreRequis { get; set; }
public Course Course { get; set; }
}
In this case you don't need to have CoursesID field. Entities will be connected by primary keys.

Table with several one-to-many relationships

I have an EF code-first model with a table having several one-to-many relationships with other tables:
public class Note
{
[Key]
public Guid Id { get; set; }
public string NoteText { get; set; }
public string Author { get; set; }
public DateTime? CreationDate { get; set; }
}
public class Foo
{
public Foo()
{
Notes = new HashSet<Note>();
}
[Key]
public Guid Id { get; set; }
public virtual ICollection<Note> Notes { get; set; }
// other properties ommited...
}
public class Bar
{
public Bar()
{
Notes = new HashSet<Note>();
}
[Key]
public Guid Id { get; set; }
public virtual ICollection<Note> Notes { get; set; }
// other properties ommited...
}
As you can see, both Foo and Bar have their own list of Notes, but a Note belongs to either a Foo or a Bar.
When scaffolding the migration, EF creates a foreign key for Foo and Bar in the Notes table, which I think is not correct. I would like, instead, that a link table is created between Foo and Notes and another one between Bar and Notes.
Is there a way to automatically do this? Or do I have to manually create these classes in my code-first implementation?
This has already been answered in this other post!
But to save you a little googling, you are getting a one-to-many association, which is correct. you want a many-to-many relationship in your code, so what you will need to do is :
in your Notes class:
public class Note
{
[Key]
public Guid Id { get; set; }
public string NoteText { get; set; }
public string Author { get; set; }
public DateTime? CreationDate { get; set; }
public DateTime? CreationDate { get; set; }
public virtual ICollection<Foo> Foos { get; set; }
public virtual ICollection<Bar> Bars { get; set; }
}
Hope this helps

ef code first map subclasses to single foreign key

I can't find an answer to this anywhere, so here goes.
I have several subclassed "Answer" types. All answers will need a reference back to their question.
By default, when ef creates the "Answers" table, it creates one foreign key reference to the questions table called FullNameQuestion_QuestionId, and one called TextboxQuestion_QuestionId.
What I want is for TextboxQuestion and FullNameQuestion to both use the same QuestionId foreign key. I cannot figure out how to get the mapping to work for this.
public abstract class Question
{
public int QuestionId { get; set; }
private string Text { get; set; }
}
public class TextboxQuestion : Question
{
public string TextboxValue { get; set; }
public virtual List<TextboxAnswer> TextboxAnswers { get; set; }
}
public class FullNameQuestion : Question
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public virtual List<FullNameAnswer> FullNameAnswers { get; set; }
}
public abstract class Answer
{
public int AnswerId { get; set; }
public int UserId { get; set; }
}
public class TextboxAnswer : Answer
{
public string TextboxValue { get; set; }
}
public class FullNameAnswer:Answer
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
I tried adding a question id to the TextboxAnswer and FullNameAnswer classes like this, but it just creates two columns, QuestionId and QuestionId1. Is there any way to get these to share the same column?
public class TextboxAnswer : Answer
{
[ForeignKey("Question")]
public int QuestionId { get; set; }
public virtual Question Question { get; set; }
public string TextboxValue { get; set; }
}
public class FullNameAnswer:Answer
{
[ForeignKey("Question")]
public int QuestionId { get; set; }
public virtual Question Question { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
I played with it now little bit and it only confirmed my expectations. It is probably not possible. Columns mapped in derived entities must be unique among all entities in hierarchy. If I tried to remap relations to the same column I got exception saying that column with the same name was already used. The only shared columns can be defined in parent entity so until you move your navigation property to base Question and reference base Answer you will not achieve that.