I'm trying to work out how to add a navigation property to the principal entity in this scenario - (maybe it's not possible with the dual primary key):
public class EntityA
{
[Key]
public int EntityAPrimaryKey1 { get; set; }
[Key]
public int EntityAPrimaryKey2 { get; set; }
//What goes here?
public virtual EntityB EntityB { get; set;}
}
public class EntityB
{
[Key]
public int EntityBPrimaryKey { get; set; }
[Column(Order = 1)]
public int EntityAPrimaryKey1 { get; set; }
[Column(Order = 2)]
public int EntityBPrimaryKey2 { get; set; }
[ForeignKey("EntityAPrimaryKey1,EntityAPrimaryKey2")]
public virtual EntityA EntityA { get; set; }
}
Since EF can't tell by the name, you can add this annotation.
[ForeignKey("EntityBPrimaryKey ")]
public virtual EntityB EntityB { get; set;}
You can also set it up with a fluent configuration.
Related
This is done using MVC .net framework and entity framework "database first" approach. There is a many to many relationship between two tables. They are connected through third table that has combined key as id from first table and id from second table.
public class ManyToManyTable
{
[Required]
[Key, Column(Order=0)]
public int firsttableid { get; set; }
[Required]
[Key, Column(Order=1)]
public int secondtableid { get; set; }
public int something { get; set; }
[ForeignKey("firsttableid")]
public virtual FirstTable firstTable { get; set; }
[ForeignKey("secondtableid")]
public virtual SecondTable secondTable { get; set; }
}
First and Second table have some id which is primary key.
I want to create View and Controller method that enables master detail entry form for this ManyToManyTable. that would have FirstTable in Master and SecondTAble in details, and all to be saved in ManyToManyTable when button Save is pressed.
Of course, both First and Second Table have this property:
public virtual ICollection<ManyToManyTable> ManyToManyTables { get; set; }
What is the easiest way to implement cases like this one?
Thank you!
EF has a default conventions for many-to-many relationships. No need to create specific
mapping class. You have to include navigation properties in both "FirstTable" and "SecondTable" Class as shown below.
public class FirstTable
{
public FirstTable()
{
secondTableProperties = new HashSet<SecondTable>();
}
public int Id { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
public virtual ICollection<SecondTable> secondTableProperties { get; set; }
}
public class SecondTable
{
public SecondTable()
{
FirstTableProperties = new HashSet<FirstTable>();
}
public int Id { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
public virtual ICollection<FirstTable> FirstTableProperties { get; set; }
}
Remove mapping class from DBContext , only include above two classes. Build and run the application , EF will automatically create a Mapping table in SQL server. Usually the Mapping table contains only the primary keys of other two tables.
You can use Fluent API to take some control on the created mapping table
modelBuilder.Entity<FirstTable>()
.HasMany<SecondTable>(s => s.FirstTableProperties)
.WithMany(c => c.secondTableProperties)
.Map(cs =>
{
cs.MapLeftKey("FirstTableId");
cs.MapRightKey("SecondTableId");
cs.ToTable("ManyToManyTable");
});
If you want to work with a join table with additional properties, above mentioned many-to-many relationship won't work . In that case you will have to create two one-to-many relationships as shown below.
public class FirstTable
{
public int Id { get; set; }
public int MyProperty2 { get; set; }
public virtual ICollection<ManyToManyTable> manytomany { get; set; }
}
public class SecondTable
{
public int Id { get; set; }
public int MyProperty2 { get; set; }
public virtual ICollection<ManyToManyTable> manytomany { get; set; }
}
public ManyToManyTable
{
[Required]
[Key, Column(Order=0)]
public int firsttableid { get; set; }
[Required]
[Key, Column(Order=1)]
public int secondtableid { get; set; }
public int AdditionalProperty { get; set; }
public virtual FirstTable first { get; set; }
public virtual SecondTable Second { get; set; }
}
I have a simple department model:
public class Department
{
[Key]
[Required]
public int ID { get; set; }
[Required]
public int LeagueID { get; set; }
[Required]
public string Name { get; set; }
public virtual League League { get; set; }
}
which is added in my ApplicationDbContext:
public DbSet<Department> Departments { get; set; }
I've subclassed department for use in a viewmodel, just to add a count of members:
public class DepartmentWithCount : Department
{
public DepartmentWithCount(Department d)
{
this.ID = d.ID;
this.LeagueID = d.LeagueID;
this.Name = d.Name;
}
public int MemberCount { get; set; }
}
Even though I've made no changes to IdentityModels, on update-database it has changed the database and added a MemberCount and Discriminator field. I understand why this would be the case if I'd referenced DepartmentWithCount in IdentityModels, but I don't understand why it would in this situation.
Is there any way for me to subclass Department without these effects?
Use the [NotMapped] attribute before the subclass
I have those 2 Models
public class BranchEmployees
{
public int ID { get; set; }
[Required, Column(Order = 0), Key]
public string ApplicationUserID { get; set; }
[Required, Column(Order = 1), Key]
public int BranchID { get; set; }
public virtual ICollection<ApplicationUser> ApplicationUser { get; set; }
public virtual ICollection<Branch> Branch { get; set; }
}
public class Branch
{
public int ID { get; set; }
public string BranchName { get; set; }
[Required]
public string ApplicationUserID { get; set; }
public ApplicationUser User { get; set; }
public virtual ICollection<BranchEmployees> BranchEmployees { get; set; }
}
public class ApplicationUser
{
//rest of the code
}
UPDATE
I have everything set up but what I want is the query that gets me the Employees whose IDs are in the branch employees table
, I'm using entity framework code first with MVC 5 , how do I do it ?
Assuming that your ApplicationUser class will have a navigational property called BranchEmployees, here is the query that gets me the Employees whose IDs are in the branch employees table
List<ApplicationUsers> employeeNames =
dbContext
.ApplicationUsers
.Where(au => au.BranchEmployees
.Count() > 0).ToList();
Also, can you provide whole model including ApplicationUser? I also wonder why you do not prefer BranchEmployees to inherit from ApplicationUser.
You don't need a class that indicates a many-to-many relation between two tables when you do code-first. The key here is to create virtual properties of those classes. Lets say you have a class Student and class Course. Students can be in many Courses and Courses can have many Students. To generate a database using these models the classes should look like this:
public class Student
{
private ICollection<Course> _courses;
public Student()
{
this._courses = new HashSet<Course>();
}
[Key]
public int Id { get; set; }
public string FullName { get; set; }
public virtual ICollection<Course> Courses
{
get { return this._courses; }
set { this._courses = value; }
}
}
And for Course:
public class Course
{
private ICollection<Student> _students;
public Course()
{
this._students = new HashSet<Student>();
}
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students
{
get { return this._students; }
set { this._students = value; }
}
}
I hope that this can help you solve your issue.
I have a model and i want to put an extra field which can be populated form the same model. IE: Categories and and sub-categories.
In my example, visitor can add an filetype but if file type is under an another file type, he can choose,
But i cant work it out. Below you can see my model.
public class HrFileType
{
[Key]
public int Id { get; set; }
[Display(Name = "Dosya Adı")]
public int Name { get; set; }
public int? HrFileTypeId { get; set; }
public virtual HrFileType HrFileType2 { get; set; }
}
You just need to add a ForeignKeyAttribute like below:
public class HrFileType
{
[Key]
public int Id { get; set; }
[Display(Name = "Dosya Adı")]
public int Name { get; set; }
public int? HrFileTypeId { get; set; }
[ForeignKey("HrFileTypeId")]
public virtual HrFileType HrFileType2 { get; set; }
}
You can also use fluent API to achieve this:
public class HrFileType
{
[Key]
public int Id { get; set; }
[Display(Name = "Dosya Adı")]
public int Name { get; set; }
public int? HrFileTypeId { get; set; }
public virtual HrFileType HrFileType2 { get; set; }
}
public class YourDbContext : DbContext
{
public DbSet<HrFileType> HrFileTypes { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//
modelBuilder.Entity<HrFileType>()
.HasOptional(c => c.HrFileType2)
.WithMany()
.HasForeignKey(c => c.HrFileTypeId);
}
}
Have you tried listing the other file types?
public class HrFileType
{
[Key]
public int Id { get; set; }
[Display(Name = "Dosya Adı")]
public int Name { get; set; }
public List<HrFileType> RelatedTypes { get; set; }
}
then using Entity Frameworks fluent API in the DbContext, try explicitly declaring a many to many map.
modelbuilder.Entity<HrFileType>().HasMany(x => x.RelatedTypes).WithMany();
I'd be very interested to see if this works. It's the only logical solution I can think of without having some kind of parent class.
I am using MVC 4 with EF code first approach. I have two simple objects. These are their POCO classes:
public class Activity
{
//Primitive Properties
[HiddenInput]
public int Id { get; set; }
[Required]
public int LengthInMinutes { get; set; }
public string AdditionalInfo { get; set; }
[Required]
public bool Archive { get; set; }
//Navigation Properties
public virtual User User { get; set; }
public virtual ActivitySet ActivitySet { get; set; }
public virtual ICollection<Company> Companies { get; set; }
public virtual ICollection<Description> Descriptions { get; set; }
}
public class Company
{
//Primitive Properties
[HiddenInput]
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public bool Archive { get; set; }
//Navigation Properties
public virtual ICollection<Activity> Activities { get; set; }
}
So there is a many-to-many relationship between Activity and Company entities. I am creating new Activity in my repository class, but when I assign a Company for the Activity like so:
activity.Companies.Add(company);
I get NullReference exception. I had a look around but according to this link:
BuildStarted.com
my approach seems to be right.
Why doesn't it work???
Before you can use Add() off Companies, it needs to be initialized.
activity.Companies = new List<Company>();
You could also initialize that in the contructor of Activity.
public class Activity
{
public Activity()
{
Companies = new List<Company>();
Descriptions = new List<Description>();
}
//Primitive Properties
[HiddenInput]
public int Id { get; set; }
[Required]
public int LengthInMinutes { get; set; }
public string AdditionalInfo { get; set; }
[Required]
public bool Archive { get; set; }
//Navigation Properties
public virtual User User { get; set; }
public virtual ActivitySet ActivitySet { get; set; }
public virtual ICollection<Company> Companies { get; set; }
public virtual ICollection<Description> Descriptions { get; set; }
}