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.
Related
I have two model classes "customerdetails" and "addresssdetails".my question is "one customer can save with multiple addresss?
namespace customer2.Models
{
public class customerdetails
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { set; get; }
[Key]
public int customerid { set; get; }
public string customername { set; get; }
}
public class addressdetails
{
public int addressno { set; get; }
public string street { set; get; }
public string landmark { set; get; }
public int pincode { set; get; }
}
public class MkContext : DbContext
{
public virtual DbSet<customerdetails> customers { get; set; }
public virtual DbSet<addressdetails> address { get; set; }
}
public class customerviewmodel
{
public customerdetails cd { set; get; }
public List<addressdetails> ad { set; get; }
}
}![enter image description here](https://i.stack.imgur.com/4QCA1.jpg)
Before I answer, just a quick tip:
Make sure to properly case your class names and properties to improve readability.
Here is a link with some guidelines
If you want to store a Customer with multiple AddressDetails, you will need to define a class and add it to the context.
public class Customer {
public int Id { get; set; }
public CustomerDetails CustomerDetails { get; set; }
public IList<AddressDetails> AddressDetails { get; set; }
}
Then add this to the context.
It's really helpful if anyone could explain me how to create a mapping (associated)table for one to many relationship using Fluent API.`
public class Category
{
public int ID { get; set; }
public string Name { get; set; }
public List<Image> Images { get; set; }
}
public class Image
{
public int ID { get; set; }
public string Name { get; set; }
public List<Category> Category{ get; set; }
The mapping table should contain CategoryID and ImageID.
The solution should be something similar to this. (This is for many to many)
modelBuilder.Entity<Category>()
.HasMany(c => c.Images).WithMany(i => i.Categories)
.Map(t => t.MapLeftKey("CategoryID")
.MapRightKey("ImageID")
.ToTable("CategoryImage"));
I want Fluent API to create new mapping table for the below relationship.
public class Category
{
public List<Image> Images{get; set;}
}
public class Image
{
public Category Category{ get; set; }
}
Adding NewTable:
modelBuilder
.Entity<NewTable>()
.HasRequired(_ => _.Category)
.WithMany()
.HasForeignKey(_ => _.CategoryId);
modelBuilder
.Entity<Image>()
.HasRequired(_ => _.NewTable)
.WithMany(_ => _.Images)
.HasForeignKey(_ => _.NewTableId)
public class NewTable
{
public int ID { get; set; }
public int CategoryId { get; set; }
public List<Image> Images { get; set; }
public virtual Category Category { get; set; }
}
public class Image
{
public int ID { get; set; }
public string Name { get; set; }
public List<Category> Categories { get; set; }
public int NewTableId { get; set; }
public virtual NewTable NewTable { get; set; }
}
As far as i know, i have two way to implement many-to-many relation in asp.net mvc using code-first.
1- Fluent Api
public class HrPerson
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<HrPersonTitle> HrPersonTitle { get; set; }
}
public class HrPersonTitle
{
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<HrPerson> HrPerson { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<HrPerson>()
.HasMany(s => s.HrPersonTitle)
.WithMany(c => c.HrPerson)
.Map(t =>
{
t.MapLeftKey("HrPersonId")
.MapRightKey("HrPersonTitleId")
.ToTable("HrMapPersonTitle");
});
}
2-Custom Mapping Table
public class HrPerson
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<HrMapPersonTitle> HrMapPersonTitle { get; set; }
}
public class HrPersonTitle
{
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<HrMapPersonTitle> HrMapPersonTitle { get; set; }
}
public class HrMapPersonTitle
{
public int Id { get; set; }
public int HrPersonId { get; set; }
public int HrPersonTitleId { get; set; }
public virtual HrPerson HrPerson { get; set; }
public virtual HrPersonTitle HrPersonTitle { get; set; }
public string Note { get; set; }
public bool Deleted { get; set; }
}
My questions:
If i choose second way, i am not able to reach HrPersonTitle.Name property from HrPerson model in the view. How can i reach the properties ?
If i choose the first way i can reach the HrPersonTitle.Name but i am not able to add more property in the map file ? How can i add more properties?
Regards.
When you create a M2M without a payload (just the foreign key relationships, no extra data), EF collapses the relationship so that you can query directly without having to explicitly go through the join table. However, if you need a payload, then EF can no longer manage the relationship in this way.
So, if you want to get the title, you have to go through HrMapPersonTitle:
#foreach (var title in Model.HrMapPersonTitle)
{
#title.HrPersonTitle.Name
}
Both these methods seem overkill maybe. I don't know your full intentions however I implement this all the time at work and I use the following:
public class HrPerson
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<HrPersonTitle> HrPersonTitles { get; set; }
}
public class HrPersonTitle
{
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<HrPerson> HrPersons { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<HrPerson>()
.HasMany(s => s.HrPersonTitles)
.WithMany(c => c.HrPersons);
}
If you are using code first and you try and access either mapping within the DbContext it should Lazy Load your information and every property should be accessible.
I do have one question though. Are you sure it should be many to many, do they really have multiple titles?
I am using this tutorial from microsoft to create a one-zero-to-one relationship with EF4.1 Between an Instructor and OfficeAssignment. This is working like a charm.
But now I want to add a Home for each Instructor (1 to zero-or-1) like in this:
I added the Home model exactly the same way as the OfficeAssignment (like in the tutorial above), but when I try to add controllers for these model, I get the error "An item with the same name has already been added".
So my model is set up incorrectly.
What is wrong with the below?
How do I create multiple one-to-zero-to-one relationships in EF4.1?
public class Instructor
{
public Int32 InstructorID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public virtual OfficeAssignment OfficeAssignment { get; set; }
public virtual Home Home { get; set; }
}
public class OfficeAssignment
{
[Key]
public int InstructorID { get; set; }
public string Location { get; set; }
public virtual Instructor Instructor { get; set; }
}
public class Home
{
[Key]
public int InstructorID { get; set; }
public string Location { get; set; }
public virtual Instructor Instructor { get; set; }
}
public class Context : DbContext
{
public DbSet<OfficeAssignment> OfficeAssignments { get; set; }
public DbSet<Instructor> Instructors { get; set; }
public DbSet<Home> Homes { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Instructor>()
.HasOptional(p => p.OfficeAssignment)
.WithRequired(p => p.Instructor);
modelBuilder.Entity<Instructor>()
.HasOptional(p => p.Home).WithRequired(p => p.Instructor);
}
Doesn't look like EF supports real 1 to 0..1 relationship. You need a foreign key. And add the optional (int?) into the main model.
So I did this as follow, and it works like a charm.
public class Instructor
{
public Int InstructorID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public int? OfficeAssignmentID { get; set; }
public virtual OfficeAssignment OfficeAssignment { get; set; }
public int? HomeID { get; set; }
public virtual Home Home { get; set; }
}
public class OfficeAssignment
{
public int OfficeAssignmentID { get; set; }
public string Location { get; set; }
}
public class Home
{
public int HomeID { get; set; }
public string Location { get; set; }
}
public class ParikshaContext :DbContext
{
public ParikshaContext()
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<ParikshaContext>());
}
public DbSet<UserDetail> UserDetails { get; set; }
public DbSet<Standard> Standards { get; set; }
public DbSet<Subject> Subjects { get; set; }
public DbSet<QuestionDescriptor> QuestionDescriptors { get; set; }
public DbSet<QuestionBrief> QuestionBriefs { get; set; }
public DbSet<QuestionCustom> QuestionCustoms { get; set; }
public DbSet<QuestionChoice> QuestionChoices { get; set; }
public DbSet<QuestionMatch> QuestionMatches { get; set; }
public DbSet<Test> Tests { get; set; }
public DbSet<Test_Question> Test_Questions { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<QuestionCustom>().ToTable("Custom");
modelBuilder.Entity<QuestionBrief>().ToTable("Brief");
modelBuilder.Entity<QuestionMatch>().ToTable("Match");
modelBuilder.Entity<QuestionChoice>().ToTable("Choice");
}
}
public class QuestionDescriptor
{
public int QuestionDescriptorId { get; set; }
public int StandardId { get; set; }
[ForeignKey("StandardId")]
public virtual Standard Standard { get; set; }
public int SubjectId { get; set; }
[ForeignKey("SubjectId")]
public virtual Subject Subject { get; set; }
public int Rating { get; set; }
public int Difficulty { get; set; }
public DateTime DateOfCreation{get;set;}
public int UserDetailId { get; set; }
[ForeignKeyAttribute("UserDetailId")]
public virtual UserDetail Creator { get; set; }
}
public class QuestionBrief : QuestionDescriptor
{
public String QuestionText { get; set; }
public String Answer { get; set; }
//true for fill in the blanks and false for a loing answers
public bool Short { get; set; }
}
public class Standard
{
public int StandardId { get; set; }
public String StandardName { get; set; }
}
public class Subject
{
public int SubjectId { get; set; }
public String SubjectName { get; set; }
public String SubjectCategory { get; set; }
// public int StandardId { get; set; }
// [ForeignKey("StandardId")]
// public virtual Standard Standard { get; set; }
}
public class Test
{
public int TestID { get; set; }
public DateTime DateOfCreation { get; set; }
public String StandardName { get; set; }
public String SubjectName { get; set; }
public String SubjectCategory { get; set; }
// public int UserDetailId { get; set; }
// [ForeignKey("UserDetailId")]
// public virtual UserDetail Creator { get; set; }
}
public class Test_Question
{
public int Test_QuestionID { get; set; }
public int TestId { get; set; }
[ForeignKey("TestId")]
public virtual Test Test { get; set; }
public int QuestionDescriptorId { get; set; }
[ForeignKey("QuestionDescriptorId")]
public virtual QuestionDescriptor Question { get; set; }
}
public class UserDetail
{
public int UserDetailId { get; set; }
[Required]
[MaxLength(10, ErrorMessage = "UserName must be 10 characters or less"), MinLength(5)]
public String Name { get; set; }
[Required]
public String Password { get; set; }
public String UserRole { get; set; }
public DateTime DateOfCreation{ get; set;}
}
//Match,Custom,Choice classes have been omitted for lack of space (which sounds stupid when i look at the amount of code i have pasted )
I have two problems:-
I cant get a foreign key relation between standard and subjects,it says the relation will cause several cascade delete paths...
if I make a foreign key rlation between test and usedetail it gives me the above problem for mapping the tst_question table .
Also since I am new to EF code first ,please point out my mistakes.all help and disccussion is welcome.
By default EF will create foreign keys will cascade delete. In your model if you delete a Standard there are multiple paths to delete the QuestionDescriptor.
Standard -> QuestionDescriptor
and
Standard -> Subject -> QuestionDescriptor
That is why SQL server does not allow you to do this. See this answer for more details
What you can do is explicitly tell EF to create foreign keys without cascade delete. But this may create data integrity problems. So make sure you understand the consequences.
What you can do is configure the relationships using fluent API with WillCascadeOnDelete(false).
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//other mappings
modelBuilder.Entity<Subject>()
.HasRequired(subject => subject.Standard).WithMany()
.HasForeignKey(subject => subject.StandardId)
.WillCascadeOnDelete(false);
}