How can I implement a child that has multiple parents in Entity Framework?
The resulting tables must be as follows:
1.Courses:
CourseID int identity
CourseTitle nvarchar
.
.
.
OtherColumns as neede
2.CoursePreRequisites:
CourseID (FK to Course.CourseID)
PreRequisiteCourseID (FK to Course.CourseID)
or is there any better way to achieve multiple parent for a child record?
You just need two navigation properties in the child class refering to the same parent class and - optionally - two corresponding foreign key properties:
public class Course
{
public int CourseID { get; set; } // PK property
public string CourseTitle { get; set; }
}
public class CoursePreRequisite
{
public int CoursePreRequisiteID { get; set; } // PK property
public int CourseID { get; set; } // FK property 1
public Course Course { get; set; } // Navigation property 1
public int PreRequisiteCourseID { get; set; } // FK property 2
public Course PreRequisiteCourse { get; set; } // Navigation property 2
}
If one or both of the two relationships are optional, use int? instead of int for the foreign key properties.
If you use the property names as indicated in the example above you don't need to configure anything. EF will recognize the two one-to-many relationships by naming conventions.
You can also use collections as inverse properties in the Course entity if you need or want them:
public class Course
{
public int CourseID { get; set; } // PK property
public string CourseTitle { get; set; }
public ICollection<CoursePreRequisite> PreRequisites1 { get; set; }
public ICollection<CoursePreRequisite> PreRequisites2 { get; set; }
}
However, in that case you must specify which navigation property pairs belong together in a relationship. You can do this with data annotations for example:
[InverseProperty("Course")]
public ICollection<CoursePreRequisite> PreRequisites1 { get; set; }
[InverseProperty("PreRequisiteCourse")]
public ICollection<CoursePreRequisite> PreRequisites2 { get; set; }
Or with Fluent API:
modelBuilder.Entity<Course>()
.HasMany(c => c.PreRequisites1)
.WithRequired(p => p.Course) // Or WithOptional
.HasForeignKey(p => p.CourseID);
modelBuilder.Entity<Course>()
.HasMany(c => c.PreRequisites2)
.WithRequired(p => p.PreRequisiteCourse) // Or WithOptional
.HasForeignKey(p => p.PreRequisiteCourseID);
Related
I am trying to map a composite object using FluentAPI on entity framework 5.0 for the following model:
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public virtual ICollection<Category> Children { get; set; }
}
So far tried many ways that didn't work well, such as the following:
HasKey(t => t.CateroryId);
HasOptional(c => c.Children)
.WithMany()
.HasForeignKey(c => c.CateroryId);
Any idea how I might do that?
If I've understood what you're going for - a Category is able to have many categories as children.
I've done this in the past using a similar foreign key mapping and some additional properties, although there may be a way to do it using independent association.
Adding additional properties to your Category so we can keep track of the parent/child relationship:
public class Page
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public int? ParentID { get; set; } // Nullable (Parent is optional).
// Navigation properties
public virtual Category Parent { get; set; } // Optional Parent
public virtual ICollection<Category> Children { get; set; }
}
You should then be able to configure like so (depending on where your mappings are set):
this.HasMany(c => c.Children) // Many Children
.WithOptional(c => c.Parent) // Optional Parent
.HasForeignKey(x => x.ParentID);
I have model Page:
public int Id{ get; set; }
public string Name { get; set; }
I want to have children pages there:
public int Id{ get; set; }
public string Name { get; set; }
public List<Page> Childrens { get; set; }
What the best way to setup non required children items of same model?
The way I went about it requires a few additional properties in your model (I'm using the virtual` keyword for my navigation properties because I required lazy loading):
public class Page
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentID { get; set; } // Nullable int because your Parent is optional.
// Navigation properties
public virtual Page Parent { get; set; } // Optional Parent
public virtual List<Page> Children { get; set; }
}
Then, using a foreign key association, you can configure the relationship like so (this is my Page mapping):
// You may be configuring elsewhere, so might want to use `modelBuilder.Entity<Page>()` instead of `this`
this.HasMany(t => t.Children)
.WithOptional(t => t.Parent)
.HasForeignKey(x => x.ParentID);
Essentially, every child is aware of its parent, and as a result of the navigation properties, you can explore the relationship from both sides.
I'm new to MVC and EF code first. I'm in struggle to model a real-estate company DB model using EF code-first approach and I did some exercises as well as reading some online tutorials.
First thing I have a customers table that would be in relation with one or more properties he/she has registered as it's owner to sell or to rent, I was wondering if it is possible to have some sub classes inside a model class for registered properties as below:
public Property
{
public int PropertyID { get; set; }
public bool IsforSale { get; set; }
public bool IsforRent { get; set; }
public class Apartment{
public int ApartmentID { get; set; }
public int AptSqureMeter { get; set; }
. . .
. . .
}
public class Villa{
public int VillaID { get; set; }
public int VillaSqureMeter { get; set; }
. . .
. . .
}
and also other sub-classes for other types of properties
}
If the answer is Yes, then how should I declare the relations using data annotation or Fluent API, and then please help me how to update both Customers table and Property table with the customer information and property info at the same time?
thanks for your answer in advance.
As #Esteban already provided you with a pretty detailed answer on how to design your POCOs and manage the relationship between them, I will only focus on that part of your question:
how should I declare the relations using data annotation or Fluent API
First of all, you should know that certain model configurations can only be done using the fluent API, here's a non exhaustive list:
The precision of a DateTime property
The precision and scale of numeric properties
A String or Binary property as fixed-length
A String property as non-unicode
The on-delete behavior of relationships
Advanced mapping strategies
That said, I'm not telling you to use Fluent API instead of Data Annotation :-)
As you seem to work on an MVC application, you should keep in mind that Data Annotation attributes will be understood and processed by both by Entity Framework and by MVC for validation purposes. But MVC won't understand the Fluent API configuration!
Both your Villa and Apartment classes have similar properties, if they are the same but as it's type, you could create an enum for that.
public enum PropertyType {
Apartment = 1,
Villa
}
public class Property {
public int PropertyID { get; set; }
public bool IsforSale { get; set; }
public bool IsforRent { get; set; }
public PropertyType PropertyType { get; set; }
public int SquareMeter { get; set; }
}
This way of modelating objects is refered as plain old clr object or POCO for short.
Assume this model:
public class User {
public int UserId { get; set; }
public string Username { get; set; }
public virtual List<Role> Roles { get; set; }
}
public class Role {
public int RoleId { get; set; }
public string Name { get; set; }
public virtual List<User> Users { get; set; }
}
Creating relations with fluent api:
Mapping many to many
On your OnModelCreating method (you'll get this virtual method when deriving from DbContext):
protected override void OnModelCreating(DbModelBuilder builder) {
// Map models/table
builder.Entity<User>().ToTable("Users");
builder.Entity<Role>().ToTable("Roles");
// Map properties/columns
builder.Entity<User>().Property(q => q.UserId).HasColumnName("UserId");
builder.Entity<User>().Property(q => q.Username).HasColumnName("Username");
builder.Entity<Role>().Property(q => q.RoleId).HasColumnName("RoleId");
builder.Entity<Role>().Property(q => q.Name).HasColumnName("Name");
// Map primary keys
builder.Entity<User>().HasKey(q => q.UserId);
builder.Entity<Role>().HasKey(q => q.RoleId);
// Map foreign keys/navigation properties
// in this case is a many to many relationship
modelBuilder.Entity<User>()
.HasMany(q => q.Roles)
.WithMany(q => q.Users)
.Map(
q => {
q.ToTable("UserRoles");
q.MapLeftKey("UserId");
q.MapRightKey("RoleId");
});
Mapping different types of relationships with fluent api:
One to zero or one:
Given this model:
public class MenuItem {
public int MenuItemId { get; set; }
public string Name { get; set; }
public int? ParentMenuItemId { get; set; }
public MenuItem ParentMenuItem { get; set; }
}
And you want to express this relationship, you could do this inside your OnModelCreating method:
builder.Entity<MenuItem>()
.HasOptional(q => q.ParentMenuItem)
.WithMany()
.HasForeignKey(q => q.ParentMenuItemId);
One to many
Given this model:
public class Country {
public int CountryId { get; set; }
public string Name { get; set; }
public virtual List<Province> Provinces { get; set; }
}
public class Province {
public int ProvinceId { get; set; }
public string Name { get; set; }
public int CountryId { get; set; }
public Country Country { get; set; }
}
You now might want to express this almost obvious relationship. You could to as follows:
builder.Entity<Province>()
.HasRequired(q => q.Country)
.WithMany(q => q.Provinces)
.HasForeignKey(q => q.CountryId);
Here are two useful links from MSDN for further info:
Configuring Relationships with the Fluent API.
Code First Relationships Fluent API.
EDIT:
I forgot to mention how to create a many to many relationship with additional properties, in this case EF will NOT handle the creation of the join table.
Given this model:
public class User {
public int UserId { get; set; }
public string Username { get; set; }
public virtual List<Role> Roles { get; set; }
pubilc virtual List<UserEmail> UserEmails { get; set; }
}
pubilc class Email {
public int EmailId { get; set; }
public string Address { get; set; }
public List<UserEmail> UserEmails { get; set; }
}
public class UserEmail {
public int UserId { get; set; }
public int EmailId { get; set; }
public bool IsPrimary { get; set; }
public User User { get; set; }
public Email Email { get; set; }
}
Now that we've added a new property into our join table ef will not handle this new table.
We can achieve this using the fluent api in this case:
builder.Entity<UserEmail>()
.HasKey( q => new {
q.UserId, q.EmailId
});
builder.Entity<UserEmail>()
.HasRequired(q => q.User)
.WithMany(q => q.UserEmails)
.HasForeignKey(q => q.EmailId);
builder.Entity<UserEmail>()
.HasRequired(q => q.Email)
.WithMany(q => q.UserEmails)
.HasForeignKey(q => q.UserId);
Is it possible to accomplish this using just attributes?
I need the Class2 table to have its own primary key of Id and a column called Class2Id that is the foreign key to Class1.Id.
public class Class1
{
public virtual int Id { get; set; }
public virtual Class2 Class2 { get; set; }
}
public class Class2
{
public virtual int Id { get; set; }
public virtual Class1 Class1 { get; set; }
}
I can get it to work using the fluent mappings using:
modelBuilder.Entity<Class1>()
.HasRequired(x => x.Class2)
.WithRequiredPrincipal(x => x.Class1)
.Map(x => x.MapKey("Class1Id"));
According to "Programming Entity Framework: Code First" book by Julia Lerman, it should be possible. The configuration depends if it is optional 1-1 relationship or required 1-1 relationship.
It is done by using
[Key]
and
[ForeignKey]
data annotations applied on dependent end.
The book contains following example:
public class PersonPhoto
{
[Key]
[ForeignKey("PhotoOf")]
public int PersonId { get; set; }
public byte[] Photo { get; set; }
public string Caption { get; set; }
}
This may be a duplicate qn, but i couldnt get a proper answer to this scenario. I have the following table structure:
public class File
{
public int FileId { get; set; } //PK
public int VersionID { get; set; }
public virtual ICollection<FileLocal> FileLLocalCollection { get; set; }
}
public class FileLocal
{
public int FileId { get; set; } //PK, FK
public int LangID { get; set; } //PK,FK
public string FileName { get; set; }
}
I have not included the third table here(Its basically LangID (PK) & LangCode )
How do i specify this mapping in fluent Api so that i can load "FileLLocalCollection" with every File objects?
The first part of your mapping can be done this way:
modelBuilder.Entity<File>()
.HasMany(f => f.FileLocalCollection)
.WithRequired()
.HasForeignKey(fl => fl.FileId);
modelBuilder.Entity<FileLocal>()
.HasKey(fl => new {fl.FileId, fl.LangId});
And the second part depends on the way how your Lang is defined. For example if you add navigation property from FileLocal to Lang you can map it this way:
modelBuilder.Entity<FileLocal>()
.HasRequired(fl => fl.Lang)
.WithMany()
.HasForeignKey(fl => fl.LangId);