(source: mcainsh.info)
The tables are just for an example, what I am trying to do is map a virtual Manufacturer in the Book entity. I've tried using data annotation similar to below:
[ForeignKey("PublisherId")]
public virtual Publisher { get; set; }
[ForeignKey("Publisher.ManufacturerCompanyId")]
[InverseProperty("ManufacturerId")]
public virtual Manufacturer { get; set; }
Is this something that can be done?
You're configuring incorrectly the foreign keys. To do what you want, your model should be like this:
public class Book
{
public int Id { get; set; }
public string Title{ get; set; }
public int PublisherId { get; set; }
[ForeignKey("PublisherId")]
public virtual Publisher Publisher{ get; set; }
public int ManufacturerId { get; set; }
[ForeignKey("ManufacturerId")]
public virtual Manufacturer Manufacturer { get; set; }
}
public class Manufacturer
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Publisher
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
In this model you have two one-to-many relationships, the first between Book and Publisher and the second one between Book and Manufacturer. As you can see in the Book class, if you want to use a FK property you must declare a property of the same type of the PK of the related entity (see PublisherId and ManufacturerId).Now, you can apply the ForeignKey annotation to the navigation property and tell it which property is the foreign key for the relationship, as I show above. Alternatively, you can addForeignKey attribute to the ManufacturerId, along with information telling it which navigation property represents the relationship it is a foreign key for:
[ForeignKey("Manufacturer")]
public int ManufacturerId { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
If you want, you don't need to create the FKs properties, EF will do the job for you begin the escene. It will create a FK row in your Books table for each relationship (check the DB after execute your code):
public class Book
{
public int Id { get; set; }
public string Title{ get; set; }
//public int PublisherId { get; set; }
//[ForeignKey("PublisherId")]
public virtual Publisher Publisher{ get; set; }
//public int ManufacturerId { get; set; }
//[ForeignKey("ManufacturerId")]
public virtual Manufacturer Manufacturer { get; set; }
}
Related
I have these 2 Entities. each book can have one or zero BookDetail (1 to 1 Relationship)
public class Book
{
public int BookId{ get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string ISBN { get; set; }
public string Price { get; set; }
public int BookDetailId { get; set; } /* FK for BookDetail */
public BookDetail BookDetail{ get; set; }
}
public class BookDetail
{
public int BookDetailId{ get; set; }
public string Weight { get; set; }
public string NumberOfPages { get; set; }
public DateTime PublicationDate { get; set; }
public int BooklId { get; set; } /* FK for Book */
public Book Book{ get; set; }
}
I want to have 2 sides foreign key, I just find solutions for just one side foreign key but I want to store FK Id of BookDetail on Book and vice versa in EF Core 5.
I know how to configure this relationship with one side FK.
To Model the Fact that a Book can have 0 or 1 BookDetail you have to make the FK on Book, pointing to BookDetail, nullable, check this:
Fluent API Key Relation
and this
public class Book
{
public int BookId{ get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string ISBN { get; set; }
public string Price { get; set; }
public int? BookDetailId { get; set; } /* nullable FK to BookDetail */
public BookDetail BookDetail{ get; set; }
}
Is it coherent with reality that a BookDetail cannot exist without the book itself, so in this case the FK from BookDetail to Book must not be nullable.
I would not "warp" the name of the FK so I can leverage EFCore conventions:
public class BookDetail
{
public int BookDetailId{ get; set; }
public string Weight { get; set; }
public string NumberOfPages { get; set; }
public DateTime PublicationDate { get; set; }
public int BookId { get; set; } /* FK to Book by conventions*/
public Book Book{ get; set; }
}
This would be enough for EFCore conventions to figure out that you have a one to one relation and that Book is the Independent memeber of the relation and BookDetail is the dependent one: The Independent is always required.
A little extra info: you might want to check owned entites, your BookDetail entity can be seen as a "complex property" of Book, this would mean though that BookDetail could not have an Id by itself.
Owned Entity Types
Model:
public class Address
{
[Key]
public long AddressId { get; set; }
public string Street { get; set; }
public string Town { get; set; }
public string State { get; set; }
public string Country { get; set; }
}
public class User
{
[Key]
public long UserId { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public virtual List<Address> Addresses { get; set; }
}
DBContext:
public class DataModelContext : DbContext
{
public DbSet<Address> Addresses { get; set; }
public DbSet<User> Users{ get; set; }
}
Using above code its creating this schema for DB.
Addresses Users
----------- -------
AddressId(PK) UserId(PK)
Street UserName
Town Password
State
Country
User_UserId(FK)
Now i want to access User_UserId from Addresses table, but it not showing any property there. Its giving error "Address does not contain a definition for User_UserId.....
using (var db = new DataModelContext())
{
db.Addresses.Select(x=>x.User_UserId).ToList();
}
Use Foreign-Key Association instead of independant association while creating models. It means that, you must include a foreign key property in your model alongside with a corresponding Navigational Property. For example:
public class Address
{
...
public int UserId {get; set;} //Foreign-Key property
[ForeignKey("UserId")]
public virtual User User { get; set; } // Navigational Property
...
}
Read this article for more information.
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; }
}
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.
Person and EHR(electronic health record) are one to one related.
Person has EHRId nullable and EHR has PersonId not nullable.
At the same time EHR and Person must be many to many related.
Because a person can have many medics (represented by person entity) and a medic can have many EHRs.
I would like to have extra attributes on the join table.
I dont know how to define this in EF.
Please help.
Here are my classes.
public class Person
{
public int ID { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
public ICollection<UserSpecialist> patients { get; set; }
public int ehrID { get; set; }
public virtual EHR ehr { get; set; }
}
public class EHR
{
public int ID { get; set; }
public bool asthmatic{ get; set; }
public ICollection<UserSpecialist> specialists { get; set; }
public int PersonID { get; set; }
public virtual Person Person { get; set; }
}
public class UserSpecialist
{
public int ID { get; set; }
public DateTime creationDate { get; set; }
public int PersonID { get; set; }
public int EHRID { get; set; }
public virtual Person Person { get; set; }
public virtual EHR EHR { get; set; }
}
When EF tries to create the database throws this error
Unable to determine the principal end
of an association between the types
'Project.Person' and 'Project.EHR'.
The principal end of this association
must be explicitly configured using
either the relationship fluent API or
data annotations.
Please help
Person and EHR are not one-to-one related and they cannot be in EF. What you have defined is bidirectional one-to-many. You have also declared both relations as required because FK's are not nullable.
Real one-to-one can be defined in EF only if EHR's PK (Id) is also FK to Person. Once you define this the part with many-to-many becomes really strange because Person will be related with EHRs of other persons. You domain description is most probably not correct.