EF Code First giving problems in foreign keys - entity-framework-4

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);
}

Related

how to create foreign key use migration code first (one to many relationship)

I have 2 classes:
public class Retete
{
public Retete() { }
public int ID { get; set; }
public string Nume { get; set; }
public string Categorie { get; set; }
public string Grupa { get; set; }
public string Descriere { get; set; }
public string Ingrediente { get; set; }
public string Preparare { get; set; }
//Configure 1 to many relationship
//Foreign Key
[ForeignKey("GrupaIndivizi")]
public int GrupaID { get; set; }
[ForeignKey("GrupaID")]
public virtual GrupaIndivizi GrupaIndivizi { get; set; }
}
and
public class GrupaIndivizi
{
public GrupaIndivizi(){}
[Key]
public int GrupaID { get; set; }
public string NumeGrupa { get; set; }
public virtual ICollection<Retete> Retetes { get; set; }
}
and the table that are created
My question is how to make GrupaID from Retetes table to be a foreign Key?
One way to make a foreign key in entity framework is: beside the Id of the key you need to have an object of that type. Check if this works.
[Table("Retete")]
public class Retete
{
public Retete() { }
public int ID { get; set; }
public string Nume { get; set; }
public string Categorie { get; set; }
public string Grupa { get; set; }
public string Descriere { get; set; }
public string Ingrediente { get; set; }
public string Preparare { get; set; }
//Configure 1 to many relationship
//Foreign Key
[ForeignKey("GrupaIndivizis")]
public int GrupaIndiviziID { get; set; }
public GrupaIndivizi GrupaIndivizi { get; set; }
}
I would also recommed to get the tables some more suitable names and don't let EF generate the names. This can be done by the Table attribute.
Your FK didn't generate corectly because he was trying to bind to a GrupaIndivizi table but you have GrupaIndivizis.

MVC Many to many search

i have three tables in my model class
public class Objekat
{
[Key]
public int ObjekatID { get; set; }
[Display(Name="Naziv Objekta")]
public String Naziv { get; set; }
public int? KategorijaID { get; set; }
public int[] idZanrova { get; set; }
public virtual ICollection<Zanr> Zanr { get; set; }
public virtual Kategorija Kategorija { get; set; }
}
public class Zanr
{
public int ZanrID { get; set; }
[Display(Name="Naziv Zanra")]
public string Naziv { get; set; }
public virtual ICollection<Objekat> Objekat { get; set; }
}
public class Kategorija
{
public int KategorijaID { get; set; }
public string Naziv { get; set; }
public ICollection<Objekat> Objekat { get; set; }
}
public class KatalogContext : DbContext
{
public DbSet<Objekat> Objekti { get; set; }
public DbSet<Zanr> Zanrovi { get; set; }
public DbSet<Kategorija> Kategorije { get; set; }
public KatalogContext() : base("MojaBaza") { }
}
Is it possible to make a filter for showing only data from table "Objekat" witch contains specific "Zanrs"?
I suppose the relation between tables "Objekat" and "Zanr" are ok ?

Code First Many to Many Mess what is going on here?

Here is a sniplet of my model:
public class ContractParent
{
public int ContractParentID { get; set; }
public string Name { get; set; }
public string Verbiage { get; set; }
public int Position { get; set; }
public bool IncludedByDefault { get; set; }
public virtual IEnumerable<ContractChild> ContractChilds { get; set; }
public virtual bool HasOnlyOneChild { get; set; }
}
public class ContractParentItem
{
public int ContractParentItemID { get; set; }
public virtual int ContractParentID { get; set; }
public virtual ContractParent ContractParent { get; set; }
public int ChargeID { get; set; }
public virtual Charge Charge { get; set; }
}
public class Charge
{
public int ChargeID { get; set; }
public virtual ChargeType ChargeType { get; set; }
public int ChargeTypeID { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<ChargeContract> ChargeContracts { get; set; }
public virtual Company Company { get; set; }
public virtual int? CompanyID { get; set; }
public virtual IEnumerable<ContractParentItem> ContractParentItems { get; set; }
public virtual IEnumerable<ContractChildItem> ContractChildItems { get; set; }
}
When i try to access a Charge with ChargeID = 687:
Charge.ContractParentItem is null.
But its not!
Looking at my table ContractParentItem in SQL
There is an entity:
ContractParentItemID=1
ContractParentID=8
ChargeID=687
I know i am missing something here.
public class Proposals : DbContext
{
public DbSet<Charge> Charges { get; set; }
public DbSet<ContractParent> ContractParents { get; set; }
public DbSet<ContractParentItem> ContractParentItems { get; set; }
}
Instead of
public virtual IEnumerable<ContractParentItem> ContractParentItems { get; set; }
you should have
public virtual ICollection<ContractParentItem> ContractParentItems { get; set; }

multiple "1 to 0..1" relationship models

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; }
}

MVC - Entity framework - Metadata relation

Today I've been working with MVC for the first time. Also normally I use the EF with model first, but I wanted to try POCO.
So I've made my 3 entities and when I try to make a controller I get an error:
Unable to retrieve metadata for "BookExchange.Models.Exchange". Unable to determine the principal end of an association between the types "BookExchange.Models.Exchange" and "BookExchange.Models.Book". The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
My 3 classes:
public class Book
{
public int BookID { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public string ISBN10 { get; set; }
public int PersonID { get; set; }
public virtual Person Person { get; set; }
public virtual Exchange Exchange { get; set; }
}
public class Person
{
public int PersonID { get; set; }
public string Name { get; set; }
public virtual ICollection<Book> Books { get; set; }
public virtual ICollection<Exchange> Exchanges { get; set; }
}
public class Exchange
{
[Key]
public int BookID { get; set; }
public int PersonID { get; set; }
public DateTime ReturnDate { get; set; }
public virtual Person Person { get; set; }
public virtual Book Book { get; set; }
}
Does anyone know what I'm doing wrong? I don't want to lose the association properties.
Thanks in advance!
Try adding foreign key properties for your references. E.g.
public class Book
{
public int BookID { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public string ISBN10 { get; set; }
public virtual Person Person { get; set; }
public int PersonID { get; set; }
public virtual Exchange Exchange { get; set; }
public int ExchangeID { get; set; }
}
public class Person
{
public int PersonID { get; set; }
public string Name { get; set; }
public virtual ICollection<Book> Books { get; set; }
public virtual ICollection<Exchange> Exchanges { get; set; }
}
public class Exchange
{
public int ExchangeID { get; set; }
public int BookID { get; set; }
public virtual Book Book { get; set; }
public int PersonID { get; set; }
public virtual Person Person { get; set; }
public DateTime ReturnDate { get; set; }
}
Also, take a look at ScottGu's post on code first and this EF post on conventions.
Try this: (Remove database, so EF will create new)
public class Book
{
public int Id { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public string ISBN { get; set; }
public virtual Person Person { get; set; }
public virtual Exchange Exchange { get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Book> Books { get; set; }
public virtual ICollection<Exchange> Exchanges { get; set; }
}
public class Exchange
{
public int Id { get; set; }
public DateTime ReturnDate { get; set; }
public virtual Person Person { get; set; }
public virtual Book Book { get; set; }
}
It's your one on one associations.
Remove one reference between exchange or book, so Code-first can decide which one is more important in your one on one relation (Book <--> Exchange)
If you want to know why, you should read this:

Resources