EF Adding an additional FK? - entity-framework

I have the following 2 entities:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Fixture> Fixtures { get; set; }
}
public class Fixture
{
public int Id { get; set; }
public Result Result { get; set; }
public int HomeTeamId { get; set; }
public int AwayTeamId { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team AwayTeam { get; set; }
}
I have then mapped it like so:
public class FixtureMap : EntityTypeConfiguration<Fixture>
{
public FixtureMap()
{
HasRequired(x => x.AwayTeam).WithMany().HasForeignKey(x => x.AwayTeamId);
HasRequired(x => x.HomeTeam).WithMany().HasForeignKey(x => x.HomeTeamId);
}
}
But when I add a migration, EF is creating an additional FK and column to my Fixture table and I've no idea why? How can I tell it not too?
As you can see its added a column called Team_Id and created an FK from it even tho I have specified the relationship in the mapping?

use this code:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
[InverseProperty("HomeTeam")]
public virtual ICollection<Fixture> HomeFixtures { get; set; }
[InverseProperty("AwayTeam")]
public virtual ICollection<Fixture> AwayFixtures { get; set; }
}
public class Fixture
{
public int Id { get; set; }
public Result Result { get; set; }
public int HomeTeamId { get; set; }
public int AwayTeamId { get; set; }
[InverseProperty("HomeFixtures")]
[ForeignKey("HomeTeamId ")]
public virtual Team HomeTeam { get; set; }
[InverseProperty("AwayFixtures")]
[ForeignKey("AwayTeamId")]
public virtual Team AwayTeam { get; set; }
}
And :
public class FixtureMap : EntityTypeConfiguration<Fixture>
{
public FixtureMap()
{
HasRequired(x => x.AwayTeam).WithMany().HasForeignKey(x => x.AwayTeamId).willCascadeOnDelete(false);
HasRequired(x => x.HomeTeam).WithMany().HasForeignKey(x => x.HomeTeamId);
}
}

Related

Entity Framework Core - 3 tier relationship

I have to apply a set of relationships with a system that incorporates a messaging system.
I have the two of my domain object with one mapping object (for the many-to-many relationship):
public class User
{
public User()
{
UserMails = new List<UserMail>();
}
public int Id { get; set; }
public ICollection<UserMail> UserMails { get; set; }
}
public class Mail
{
public Mail()
{
UserMails = new List<UserMail>();
}
public int Id { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public ICollection<UserMail> UserMails { get; set; }
}
public class UserMail
{
public int Id { get; set; }
public int FromUserId { get; set; }
public User FromUser { get; set; }
public int ToUserId { get; set; }
public User ToUser { get; set; }
public int MailId { get; set; }
public Mail Mail { get; set; }
}
How would I configure this relationship using Fluent API such that there's a many to many relationship between User and Mail and Mail can have 2 foreign keys back to the UserFrom and UserTo?
Any help on this would be greatly appreciated.
If you are trying to model the relationship between a mail and its sender/recipient, then you don't need a many-to-many relation, or 2 foreign keys in your joining entity. Instead, you need 2 one-to-many relations like below -
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Mail> ReceivedMails { get; set; }
public ICollection<Mail> SentMails { get; set; }
}
public class Mail
{
public int Id { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public int SenderId { get; set; }
public User Sender { get; set; }
public int RecipientId { get; set; }
public User Recipient { get; set; }
}
and you can configure them as -
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Mail>()
.HasOne(p => p.Sender)
.WithMany(p => p.SentMails)
.HasForeignKey(p => p.SenderId)
.OnDelete(DeleteBehavior.NoAction);
builder.Entity<Mail>()
.HasOne(p => p.Recipient)
.WithMany(p => p.ReceivedMails)
.HasForeignKey(p => p.RecipientId)
.OnDelete(DeleteBehavior.NoAction);
}

Defining the one to many relationship in OnModelCreating using Entity Framework Core 3.1

I am new to Entity Framework Core 3.1 and trying to define the one-to-many relationship between two tables. I am currently struggling and getting compilation errors. Could somebody tell me what the problem could be.
The error is:
PersonNote does not contain the definition for PersonNote
I am currently getting is at line
entity.HasOne(d => d.PersonNote)
How else could I define one-to-many relationship?
The two tables are Person and PersonNote. One Person can have many PersonNotes. I have defined the models for them
public class Person
{
public int Id { get; set; }
public int? TitleId { get; set; }
public string FirstName { get; set; }
public string FirstNamePref { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public DateTime? DateOfBirth { get; set; }
public string Gender { get; set; }
public int AddressId { get; set; }
public string TelephoneNumber { get; set; }
public string MobileNumber { get; set; }
public string Email { get; set; }
public int? PartnerId { get; set; }
public bool Enabled { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
public string ModifiedBy { get; set; }
public DateTime Modified { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordStartDateTime { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordEndDateTime { get; set; }
public Address Address { get; set; }
public Title Title { get; set; }
public Client Client { get; set; }
internal static IEnumerable<object> Include(Func<object, object> p)
{
throw new NotImplementedException();
}
public PersonNote PersonNote { get; set; }
}
public class PersonNote
{
public int Id { get; set; }
public int PersonId { get; set; }
public string Note { get; set; }
public int AuthorId { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordStartDateTime { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordEndDateTime { get; set; }
}
public IEnumerable<PersonNote> GetPersonNotes(int personId)
{
var PersonNotes = PersonNote
.Include(x => x.)
.Where(x => x.Id == personId)
.ToList();
return PersonNotes;
}
I have tried the following in OnModelCreating:
modelBuilder.Entity<PersonNote>(entity =>
{
entity.ToTable("PersonNote", "common");
entity.HasOne(d => d.PersonNote)
.WithMany(p => p.Person)
.HasForeignKey(d => d.PersonId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_commonPersonNote_commonPerson");
});
You should have have something like this (other properties are omitted):
class Person
{
[Key]
public int Id { get; set; }
public List<PersonNote> PersonNotes { get; set; }
}
class PersonNote
{
[Key]
public int Id { get; set; }
public int PersonId { get; set; }
}
class StackOverflow : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<PersonNote> PersonNotes { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasMany(p => p.PersonNotes)
.WithOne()
.HasForeignKey(p => p.PersonId);
}
}

many to many entity framework + Compose Primary Key

Hi friends I am having problems with a relationship Much to Much with Compose Primary Key.
I have the following:
public class Empleado
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key, Column(Order = 0)]
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Nombre { get; set; }
[Key, Column(Order = 1)]
public int? IdentificacionId { get; set; }
public Identificacion Identificacion { get; set; }
[Required]
[StringLength(11)]
[Key, Column(Order = 2)]
public string NoIdentificacion { get; set; }
}
// Entidad relación
public class EmpleadoNomina
{
public int EmpleadoId { get; set; }
public int NominaId { get; set; }
public decimal Salario { get; set; }
public int DescuentoLey { get; set; }
public decimal? SalarioIngresoEgreso { get; set; }
public Nomina Nomina { get; set; }
public Empleado Empleado { get; set; }
}
// FluentApi
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Constraint combinado TipoId + NoID
modelBuilder.Entity<Empleado>().HasKey(x => new { x.IdentificacionId, x.NoIdentificacion });
// Relación
modelBuilder.Entity<EmpleadoNomina>().HasKey(k => new { k.NominaId, k.EmpleadoId });
}
The problem arises when the relationship table is created. To this is added the columns Employee_IdentificationId, Employee_NoIdentification. And the EmployeeId column without foreignkey.
The other problem is: I can't use .Find(id); example: db.Empleados.Find(15); This gives an error because it requires me to pass the three keys.
I just want to remove the extra columns Employee_IdentificationId, Employee_NoIdentification and only use EmpleadoId.
Don't use a composite key on Empleado - just use ID as its key. Same for Nomina. The composite key is used on the bridge table. Also, since you are already using fluent code you don't need the annotations. Behavior can be odd when you mix.
public class Empleado
{
// This will be identity key by convention
public int Id { get; set; }
// These could be set in fluent code
[Required]
[StringLength(100)]
public string Nombre { get; set; }
public string NoIdentificacion { get; set; }
// This will be an optional FK by convention
public int? IdentificacionId { get; set; }
public Identificacion Identificacion { get; set; }
public virtual ICollection<Nomina> Nominas { get; set; }
}
public class Nomina
{
// This will be identity key by convention
public int Id { get; set; }
public string XXXXXX { get; set; }
... etc
public virtual ICollection<Empleado> Empleados { get; set; }
}
public class EmpleadoNomina
{
public int EmpleadoId { get; set; }
public int NominaId { get; set; }
public decimal Salario { get; set; }
public int DescuentoLey { get; set; }
public decimal? SalarioIngresoEgreso { get; set; }
public Nomina Nomina { get; set; }
public Empleado Empleado { get; set; }
}
// FluentApi
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Empleado>()
.HasMany<Nomina>(e => e.Nominas)
.WithMany(c => c.Empleado)
.Map(cs =>
{
cs.MapLeftKey("Id");
cs.MapRightKey("Id");
cs.ToTable("EmpleadoNomina");
});
}
See here
EDIT: OK, If you need to keep the composite key on Empleado, then you will need to reference it with a composite FK. So you need to add the other 2 FK fields:
// Entidad relación
public class EmpleadoNomina
{
public int EmpleadoId { get; set; }
public int IdentificacionId { get; set; }
public string NoIdentificacion { get; set; }
public int NominaId { get; set; }
public decimal Salario { get; set; }
public int DescuentoLey { get; set; }
public decimal? SalarioIngresoEgreso { get; set; }
public Nomina Nomina { get; set; }
public Empleado Empleado { get; set; }
}
Then the fluent code:
modelBuilder.Entity<EmpleadoNomina>()
.HasRequired(en => en.Empleado)
.WithMany()
.HasForeignKey(en => new {en.EmpleadoId, en.IdentificacionId , en.NoIdentificacion });
Also, I am not sure IdentificacionId can be nullable. See here.
I solved it with Index Dataanotations to create the Unique Composited Index instead of a Composited primary key (this was responsible of my problem).
I removed the composite keys from the main class and added a list of EmployeeNomine to the two classes of entities.
I changed everything as shown below and now it is working very well. This what I wanted to do from the beginning.
// Class 2
public class Empleado
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Nombre { get; set; }
[Index("IX_Identificacion", 1, IsUnique = true)]
public int? IdentificacionId { get; set; }
public Identificacion Identificacion { get; set; }
[Required]
[StringLength(11)]
[Index("IX_Identificacion", 2, IsUnique = true)]
public string NoIdentificacion { get; set; }
public List<EmpleadoNomina> EmpleadoNominas { get; set; }
}
// Class 1
public class Nomina
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(200)]
public string Descripcion { get; set; }
public int Frecuencia { get; set; }
public int Dia { get; set; }
public List<EmpleadoNomina> EmpleadoNominas { get; set; }
}
// Relation Entity (Table)
public class EmpleadoNomina
{
public int EmpleadoId { get; set; }
public int NominaId { get; set; }
public decimal Salario { get; set; }
public int DescuentoLey { get; set; }
public decimal? SalarioIngresoEgreso { get; set; }
public Nomina Nomina { get; set; }
public Empleado Empleado { get; set; }
}
// FluentApi
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Nominas -> Empleados
modelBuilder.Entity<EmpleadoNomina>().HasKey(k => new { k.NominaId, k.EmpleadoId });
modelBuilder.Entity<EmpleadoNomina>().HasRequired(e => e.Empleado).WithMany(n => n.EmpleadoNominas).HasForeignKey(r => r.EmpleadoId);
modelBuilder.Entity<EmpleadoNomina>().HasRequired(n => n.Nomina).WithMany(n => n.EmpleadoNominas).HasForeignKey(n => n.NominaId);
}
It's I always wanted to do. thanks for everything

EF Core More Navigation properties from two tables

I am trying to create navigation properties for two table.
Here is the code.
public class CourseMaster
{
public int Id { get; set; }
public string Name { get; set; }
public int? TeamLeaderId { get; set; }
[ForeignKey("TeamLeaderId")]
public StudentMaster TeamLeader { get; set; }
public int? GroupLeaderId { get; set; }
[ForeignKey("GroupLeaderId")]
public StudentMaster GroupLeader { get; set; }
public virtual ICollection<StudentMaster> Students { get; set; }
}
public class StudentMaster
{
public int id { get; set; }
public string Name { get; set; }
public int FirstSemCourseId { get; set; }
[ForeignKey("FirstSemCourseId")]
public CourseMaster FirstSemCourse { get; set; }
public int SecondSemCourseId { get; set; }
[ForeignKey("SecondSemCourseId")]
public CourseMaster SecondSemCourse { get; set; }
public int ThirdSemCourseId { get; set; }
[ForeignKey("ThirdSemCourseId")]
public CourseMaster ThirdSemCourse { get; set; }
public int CourseMasterId { get; set; }
public CourseMaster Course { get; set; }
}
// Fluent API
modelBuilder.Entity<StudentMaster>()
.HasOne(p => p.Course)
.WithMany(b => b.Students)
.HasForeignKey(p => p.CourseMasterId);
But when i am creating migrations i am getting following error.
Unable to determine the relationship represented by navigation property 'CourseMaster.TeamLeader' of the type 'StudentMaster'. Either manually configure the relationship, or ignore this property from model.
Whether the procedure i am following is right or should i create intermediate class.
or how should i create class.
Any help are appreciated.
Thanks

Code first fluent api - table relationship

I have following tables and need to set relationship between them.
Model classes for the tables are as given
public class UserAction
{
public int ActionID { get; set; }
public string ActionName { get; set; }
public virtual ICollection<RoleScreenActionPermission> RoleScreenActionPermissions { get; set; }
}
public class Screen
{
public int ScreenID { get; set; }
public string ScreenName { get; set; }
public virtual ICollection<RoleScreenActionPermission> RoleScreenActionPermissions { get; set; }
}
public class ScreenAction
{
public int ScreenActionID { get; set; }
public int ScreenID { get; set; }
public int ActionID { get; set; }
public virtual Screen Screen { get; set; }
public virtual UserAction UserAction { get; set; }
}
public class RoleScreenActionPermission
{
public int RoleScreenActionPermissionID { get; set; }
public int ScreenActionID { get; set; }
public int RoleID { get; set; }
public virtual ScreenAction ScreenAction { get; set; }
public virtual Role Role { get; set; }
}
The talbe structure created is as:
Please help with setting the relationship correctly.
Try to remove all your own foreign keys from your classes. EF must make it.
upd:
public class Screen
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Action
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ScreenAction
{
public int Id { get; set; }
public virtual Screen Screen { get; set; }
public virtual Action Action { get; set; }
}
public class RoleScreenActionPermission
{
public int Id { get; set; }
public virtual ScreenAction ScreenAction { get; set; }
public virtual Role Role { get; set; }
}