Using the newest Entity Framework I have a class with a one-to-many wit only one navigation property on the many side.
As stated in MSDN: Entity Framework Fluent API - Relationships:
A one-directional (also called unidirectional) relationship is when a
navigation property is defined on only one of the relationship ends
and not on both.
Simplified: a School has many Students; there is a one-to-many relation between School and Student, but the School doesn't have a property containing the collection of Students
class Student
{
public int Id {get; set;}
// a Student attends one School; foreign key SchoolId
public int SchoolId {get; set;}
public School School {get; set;}
}
class School
{
public int Id {get; set;}
// missing: public virtual ICollection<Studen> Students {get; set;}
}
In a two-directional relationship, you could write the following fluent API in OnModelCreating:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.HasRequired(student => student.School)
.WithMany(school => school.Students)
.HasForeignKey(student => student.SchoolId);
}
Because of the lack of School.Students, I need to do something extra. According to the link at the beginning it seems that I'd have to do something with WithRequiredDependant.
// Summary:
// Configures the relationship to be required without a navigation property
// on the other side of the relationship. The entity type being configured will
// be the dependent and contain a foreign key to the principal. The entity type
// that the relationship targets will be the principal in the relationship.
//
public ForeignKeyNavigationPropertyConfiguration WithRequiredDependent();
modelBuilder.Entity<Student>()
.HasRequired(student => student.School)
.WithRequiredDependent();
Alas, this doesn't work. SchoolId is not modeled as the foreign key.
What fluent API do I need?
I hope I have the right version/edition in mind:
modelBuilder.Entity<Student>()
.HasRequired(student => student.School)
//.WithMany(school => school.Students)
.WithMany()
.HasForeignKey(student => student.SchoolId);
Related
I have two model classes (Tickets and Activities), where Activities is more like a look-up table, and is not suppose to hold any navigational properties or FK's of other entities.
A record in Tickets is supposed to have a single Activity, but in the whole table of Tickets, there will be many of the same Activities. Activities needs to be a table, and not (for example) an enum, because of the possibility of future updates and amendments.
Although this seems trivial enough, I keep encountering errors like Identity is Set to off.
My models:
public class Tickets
{
public int ID {get; set;}
// fk
public int ActivityID {get; set;
// nav property
public Activity Activity {get; set;}
// other properties.
}
public class Activity
{
public int ID {get; set;}
public int RankOrder {get; set;}
//other properties
}
I have specified a domainmapping for the Tickets model:
builder.HasOne(t => t.Activity)
.WithMany()
.HasForeignKey(t => t.ActivityID);
based on this SO-post and blogpost: here and here but I don't get it to work, my most recent error message is:
SqlException: Cannot insert explicit value for identity column in table 'Activity' when IDENTITY_INSERT is set to OFF.
Also, with this mapping it seems that EF created a Ticket column in the Activity table, something that I don't want.
Try this
builder.Entity<Ticket>()
.HasOne(t => t.Activity)
.WithMany(a => a.Ticket)
.HasForeignKey(t => t.ActivityID);
I have a problem with the Entity Framework that I can't figure out.
I have a Module class that links to another Module (a one-to-one relationship) in two ways.
Code:
public class Module {
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id {get;set;} /* primary key */
public Guid? OtherModule1 {get;set;}
[ForeignKey("OtherModule1")]
public Module OtherModule {get;set;}
public Guid? OtherModule2 {get;set;}
[ForeignKey("OtherModule2")]
public Module OtherModule2 {get;set;}
}
This gives the error that the principal end of the association cannot be determined.
Unable to determine the principal end of an association between the types 'Module' and 'Module'
I understand what the error means, but here's the thing. The relationship with OtherModule1 has always existed without a problem. This code works:
public class Module {
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id {get;set;} /* primary key */
public Guid? OtherModule1 {get;set;}
[ForeignKey("OtherModule1")]
public Module OtherModule {get;set;}
}
There is no Fluent configuration present on this table
Now, if I add a new column, OtherModule2 and link it in the exact same way, this error pops up.
Does anyone have an idea of how to handle this?
TL/DR: one table has two foreign keys to the same table. One foreign key is handled correctly while the other is not.
The working model by convention defines one-to-many unidirectional (with only navigation property at the many side) relationship. It's equivalent of the following fluent configuration:
modelBuilder.Entity<Module>()
.HasOptional(e => e.OtherModule)
.WithMany()
.HasForeignKey(e => e.OtherModule1);
When you add a second FK / navigation property pair (I've renamed the FK property because you can't have 2 properties with the same name in the class):
public class Module
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; } /* primary key */
public Guid? OtherModule1 { get; set; }
[ForeignKey("OtherModule1")]
public Module OtherModule { get; set; }
[Column("OtherModule2")]
public Guid? OtherModule2_Id { get; set; }
[ForeignKey("OtherModule2_Id")]
public Module OtherModule2 { get; set; }
}
EF cannot automatically determine the relationships - it could be 2 unidirectional one-to-many or 1 bidirectional one-to-one, hence the error.
There is no way to specify that with data annotations in this case, so you need to use fluent configuration to either fully configure the relationships, or when combined with data annotations, to simply specify the cardinality and the navigation properties involved.
The following fluent configuration is sufficient to resolve the issue for the above data annotated model:
modelBuilder.Entity<Module>()
.HasOptional(e => e.OtherModule)
.WithMany();
modelBuilder.Entity<Module>()
.HasOptional(e => e.OtherModule2)
.WithMany();
I want to create 3 tables based on 3 entities using code-first and fluent API. I am using Entity Framework version 6. The join table needs a 3-column primary key and additional columns.
My question: how can I use code-first with C# Fluent API to create/map the 3-column primary key for the PatientTreatment table? Thank you.
Details of the 3-column primary key for the join table { PatentId, TreatmentId , TreatmentDate }. The values of PatentId and TreatmentId are fetched from the other 2 entities (tables) while the value of TreatmentDate is entered manually (e.g. C# code or T-SQL script like calling getdate() function).
Details of the 3 entities:
public class Patient {
public long PatentId {get; set;} // database created using Identity
...
}
public class Treatment {
public long TreatmentId {get; set;} // database created using Identity
...
}
And the join table (entity)
public class PatientTreatment
{
public long PatentId {get; set;} // part of the primary key from the Patient entity
public long TreatmentId {get; set;} // part of the primary key from the Treatment entity
public DateTime TreatmentDate {get; set;} // part of the primary key but its value is from C# code or from T-SQL script, not from other entity (table)
// other fields ...
}
You can't model this as a many-to-many association in which the PatientTreatment class is hidden, which is what is usually referred to as many-to-many in Entity Framework mapping.
But you didn't intend to do that, as is apparent from the explicit PatientTreatment class you show. So it's just a matter of modeling it correctly.
In the OnModelCreating override of your DbContext subclass, setup the mapping like so:
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Entity<PatientTreatment>()
.HasKey(x => new { x.PatientId, x.TreatmentId, x.TreatmentDate });
mb.Entity<Patient>().HasMany(p => p.PatientTreatments)
.WithRequired().HasForeignKey(x => x.PatientId);
mb.Entity<Treatment>().HasMany(t => t.PatientTreatments)
.WithRequired().HasForeignKey(x => x.TreatmentId);
base.OnModelCreating(mb);
}
I think this line HasKey(x => new { x.PatientId, x.TreatmentId, x.TreatmentDate }) is what you were looking for mainly.
I Just Serch it in stackoverflow
It's not possible to create a many-to-many relationship with a
customized join table. In a many-to-many relationship EF manages the
join table internally and hidden. It's a table without an Entity class
in your model. To work with such a join table with additional
properties you will have to create actually two one-to-many
relationships
check this many to many with extra column
In previous versions of EF I can use following code to implement an identifying relationship:
public class Child
{
[Key, Column(Order = 1)]
public virtual int Id { get; set; }
[Key, Column(Order = 2)]
public virtual int ParentId { get; set; }
public virtual Parent Parent { get; set; }
}
It's needed to easily remove a child from collection like this:
var parent = _context.Parents.First();
var child = parent.Children.First();
parent.Children.Remove(child);
_context.SaveChanges();
This approach is described in http://www.kianryan.co.uk/2013/03/orphaned-child/ (the method #2).
But in EF7 this code throws exception when migration is creating:
An exception was thrown while executing a resolve operation. See the
InnerException for details. ---> Entity type 'Child' has composite
primary key defined with data annotations. To set composite primary
key, use fluent API.
I also tried to use FluentAPI as described in How to define nested Identifying Relationships Entity Framework code first in following code:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Parent>()
.HasMany(p => p.Children)
.WithOne(c => c.Parent);
modelBuilder.Entity<Child>()
.HasKey(c => new {c.Id, c.ParentId});
base.OnModelCreating(modelBuilder);
}
This approach allow generate a migration successfully, but when I tried to remove a child from Children collection I got following exception:
System.InvalidOperationException: The association between entity types
'Parent' and 'Child' has been severed but the foreign key for this
relationship cannot be set to null. If the dependent entity should be
deleted, then setup the relationship to use cascade deletes.
But I wouldn't like to use cascade deletes, I would like to use identifying relationship!
Please, help me understand what I do incorrect. Thank you!
Use cascade on delete instead as this is what it's used for:
modelBuilder.Entity<Parent>()
.HasMany(p => p.Children)
.WithOne(c => c.Parent);
.WillCascadeOnDelete(true);
https://msdn.microsoft.com/en-gb/data/jj591620.aspx
Just in case someone sees this error, let me tell you how I resolved mine:
When you do an update, on EF you need to first query the database and get the data model, then map the Domain layer model with your changes onto it (basically copying fields onto the data), and finally call the DBContext update method, then save changes.
My problem was that my model (not the data model, the domain model) also had the sub objects on it.
So here's the data layer model (for example):
public class Parent
{
public int ChildId {get; set; }
[ForeignKey("ChildId")]
public virtual Child Child { get; set; }
}
And here's how the domain layer model should be:
public class Parent
{
public int ChildId { get; set; }
//public Child Child { get; set; } // this caused the error, keep reading if you want to know more.
}
When I was seeing the error, I had been using Autofac's runtime mapper to map the domain layer model's properties onto the data layer model. However, the child in the domain layer model was null, so it would nullify the data layer, causing the error:
"The association between entity types 'Parent' and 'Child' has been severed but the foreign key for this relationship cannot be set to null. If the dependent entity should be deleted, then setup the relationship to use cascade deletes."
By the way, in the db context class, I have the following relationship defined:
modelBuilder.Entity<Parent>()
.HasOne(a => a.Child)
.WithMany()
.HasForeignKey(p => p.ChildId)
.OnDelete(DeleteBehavior.Restrict);
It's working.
I am using entity framework code first for creating database in my project. I have defined many to many relationship between following two table.:
Student
Course
Fluent Api
modelBuilder.Entity<Student>().HasMany(e => e.Courses)
.WithMany(e => e.Students).Map(m =>
{
m.MapLeftKey("StudentId");
m.MapRightKey("CourseId");
m.ToTable("StudentCourse");
});
This will define a many to many relationship between Student and Course and will create a new table StudentCourse in the database.
Now i want to define a new relationship (that may be 1 to 1 OR 1 to many) between
StudentCource
Any other table
How can i do this with entity framework code first ??
What do you want is no possible without creating a own class (poco) for the StudentCourse
public class StudentCourse
{
public int Id {get;set;}
public Student Student {get; set;}
public Course Course {get; set;}
}
And then use fluent api to make the relationship between this three variables
modelBuilder.Entity<StudentCourse>()
.HasRequired(i => i.Student)
.WithMany(u => u.StudentCourses)
.HasForeignKey(i => i.StudentId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<StudentCourse>()
.HasRequired(i =>i.Course)
.WithMany(d =>d.StudentCourses)
.HasForeignKey(i => i.CourseId)
.WillCascadeOnDelete(false);
Where StudentCourses are the navigation properties in the student class and Course class
You can use the Id defined as primary key or use the foreign key of both tables as primary:
modelBuilder.Entity<StudentCourse>()
.HasKey(i => new {i.StudentId,i.CourseId });
In my opinion use the Id as primary key make you more simple the things for making relationships between StudentCourse and another table.