I have the following design.
As we can see from this image, an Episode will have multiple EpisodePatients, and each of these EpisodePatients, will point to one Episode.
Here are my two models corresponding to the tables.
public class EpisodeModel
{
public int ID { get; set; }
public virtual EpisodePatientModel EpisodePatient { get; set; }
}
public class EpisodePatientModel
{
public int EpisodePatientID { get; set; }
public virtual EpisodeModel Episode { get; set; }
}
How do I setup the One to Many relationship between EpisodeModel and EpisodePatientModel?
Since EpisodeModel does not contain a foreign key to EpisodePatient, I cannot do the following.
modelBuilder.Entity<EpisodeModel>().HasRequired(r => r.EpisodePatient).WithMany().HasForeignKey() //No foreign key
I have tried this.
modelBuilder.Entity<EpisodeModel>().HasRequired(r => r.EpisodePatient);
But with this approach, the EpisodeModel is not Lazy loaded when loading all EpisodePatientModels form the DB
First of all your model does not reflect what you say. If there is one-to-many relationship between EpisodeModel and EpisodePatientModel you must have collection of EpisodePatientModel. And you are missing foreign key property at EpisodePatientModel:
public class EpisodeModel
{
public int ID { get; set; }
public virtual ICollection<EpisodePatientModel> EpisodePatients { get; set; } // Must be collection
}
public class EpisodePatientModel
{
public int EpisodePatientID { get; set; }
public int EpisodeID { get; set; } // Foreign key to Episode
public virtual EpisodeModel Episode { get; set; }
}
Then after your models are correct, mappings with Fluent API is easy to understand, map them as you say: one EpisodeModel can have many EpisodePatientModel:
modelBuilder.Entity<EpisodeModel>()
.HasMany(r => r.EpisodePatients)
.WithRequired(m => m.Episode)
.HasForeignKey(m => m.EpisodeID);
Or you can map reverse of this. Adding one of these two is enough:
modelBuilder.Entity<EpisodePatientModel>()
.HasRequired(r => r.Episode)
.WithMany(m => m.Episode)
.HasForeignKey(m => m.EpisodeID);
I understood that you need to have a foreign key in the EpisodePatient table that refers to the Episode table Id, so I think you can solve it like this:
public class EpisodeModel
{
public int ID { get; set; }
public virtual IEnumerable<EpisodePatientModel> EpisodePatients { get; set; }
}
public class EpisodePatientModel
{
public int EpisodePatientID { get; set; }
public int EpisodeID { get; set; }
public virtual EpisodeModel Episode { get; set; }
}
And then, your configuration should go like this:
modelBuilder.Entity<EpisodePatientModel>().HasRequired(r => r.Episode).WithMany(e => e.EpisodePatients).HasForeignKey(r => r.EpisodeID);
Related
I'm having a problem with many-to-many relationships in a pizzeria system I'm developing.
I have an entity called "Payament" that has a list of Pizzas and a list of Drinks.
ex:
public class Payament
{
public string? PayamentId { get; set; }
public virtual List<Pizza> Pizzas { get; set; }
public virtual List<Drink> Drinks { get; set; }
public string? CPFId { get; set; }
[JsonIgnore]
public virtual Client? Client { get; set; }
public double? TotalPay { get; set; }
public DateTime DateTransaction { get; set; }
public virtual StatusOrder StatusOrder { get; set; }
public Payament()
{
Pizzas = new List<Pizza>();
Drinks = new List<Drink>();
DateTransaction = DateTime.Now;
StatusOrder = StatusOrder.CARRINHO;
}
}
Also, I have two entities Pizza and Drink.
ex:
public class Pizza : IItem
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int Quantity { get; set; }
public double Value { get; set; }
[JsonIgnore]
public virtual List<Payament> Payament { get; set; }
public Pizza()
{
Payament = new List<Payament>();
}
}
public class Drink : IItem
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int Quantity { get; set; }
public double Value { get; set; }
[JsonIgnore]
public virtual List<Payament> Payament { get; set; }
public Drink()
{
Payament = new List<Payament>();
}
}
These classes are configured as many-to-many in OnModelCreating()...
Drink:
builder.HasMany(h => h.Payament)
.WithMany(d => d.Drinks);
Pizza:
builder.HasMany(h => h.Payament)
.WithMany(p => p.Pizzas);
Payament:
builder.HasMany(p => p.Pizzas)
.WithMany(p => p.Payament);
builder.HasMany(d => d.Drinks)
.WithMany(d => d.Payament);
Migrations were generated, all right. But when I go to send a payment, I get this error:
MySqlException: Cannot add or update a child row: a foreign key constraint fails (pizzaroller.drinkpayament, CONSTRAINT FK_DrinkPayament_Payament_PayamentId FOREIGN KEY (PayamentId) REFERENCES payament (PayamentId) ON DELETE CASCADE)
What I believe it could be:
If I'm not mistaken, a drinkpayament table and a pizzapayament table are created where the primary keys between the relations are joined.
And in this case, "Payament" has a primary key of type string, while items "Pizza" and "Drink" have a primary key of type int.
The conflict is likely to be found in this divergence. I could be wrong, of course.
So I would like to know how I can solve this problem. And also, if possible, tips on how I can work with existing items for sale and relate them to a payment.
Project is on github if you want to take a look:
https://github.com/newhobbye/pizza-roller-api
This project is for the exercise of knowledge and some patterns that I will implement to practice. I accept any kind of criticism! A big hug and many thanks!
I managed to solve.
I was resending the client entity in update. And I hadn't turned off the AsNoTracking() option;
In addition to this problem, I was also resending the items instead of associating the existing ones by id.
Thank you all for your help!
I have a problem similar to Entity Framework Code First : Setting up One-To-One foreign key association using Annotations
However, I have many "optional" references on the same parent table to same child table.
If I call classes CE and CA, to simplify, CE has a number of CA fields. CA id's, then, cannot have as key only the same id as CE.
What I want is EF to recognize CA/id as primary key and ConfiguracionEmpresaId as the foreign key relationship. Simply adding it to the keys didn't work.
I tried many things and I think is time to ask for help.
Simplified code:
public class ConfiguracionEmpresa
{
[Key]
[ForeignKey("Empresa")]
public long Id { get; set; }
public virtual Empresa Empresa { get; set; }
[StringLength(200)]
public string DirectorioTrabajo { get; set; }
public virtual ConfiguracionArchivo Cfg_LibroMayor { get; set; }
public virtual ConfiguracionArchivo Cfg_LibroDiario { get; set; }
public virtual ConfiguracionArchivo Cfg_Balance { get; set; }
public virtual ConfiguracionArchivo Cfg_DiccionarioCuentas { get; set; }
}
public class ConfiguracionArchivo
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public long ConfiguracionEmpresaId { get; set; }
[Required, ForeignKey("ConfiguracionEmpresaId")]
public virtual ConfiguracionEmpresa ConfiguracionEmpresa { get; set; }
public int LineasCabecera { get; set; }
}
The problem is I cannot have the same parent ID on child table, it will have duplicated primary keys.
On ModelBuilder:
modelBuilder.Entity<ConfiguracionArchivo>().HasKey(e => e.Id).HasRequired(e => e.ConfiguracionEmpresa);
modelBuilder.Entity<ConfiguracionEmpresa>()
.HasOptional(d => d.Cfg_Balance).WithRequired(q => q.ConfiguracionEmpresa);
modelBuilder.Entity<ConfiguracionEmpresa>()
.HasOptional(d => d.Cfg_DiccionarioCuentas).WithRequired(q => q.ConfiguracionEmpresa);
modelBuilder.Entity<ConfiguracionEmpresa>()
.HasOptional(d => d.Cfg_LibroDiario).WithRequired(q => q.ConfiguracionEmpresa);
modelBuilder.Entity<ConfiguracionEmpresa>()
.HasOptional(d => d.Cfg_LibroMayor).WithRequired(q => q.ConfiguracionEmpresa);
Say you have a table of road mile-marker points (mile-markers are signs placed every mile on US highways). Then you have a second table of spans between these mile markers. The Span table has two int columns StartMileMarkerId and EndMileMarkerId which are foreign keys referencing MileMarker Id column; These are the tables;
tblMileMarkers
[Table("tblMileMarkers")]
public class MileMarker
{
public MileMarker()
{
Spans = new HashSet<Span>();
}
[Key]
public int Id { get; set; }
public string Name { get; set; }
public DbGeography Location { get; set; }
public virtual ICollection<Span> Spans { get; set; }
}
tblSpans
[Table("tblSpans")]
public class Span
{
[Key]
public int Id { get; set; }
[Required, StringLength(100)]
public string Name { get; set; }
public int StartMileMarkerId { get; set; }
public int EndMileMarkerId { get; set; }
public virtual MileMarker MileMarker { get; set; }
}
If it was only one foreign key (StartMileMarkerId), I could configure the one-many relationship in the DbContext with Fluent Api as below
modelBuilder.Entity<Span>().HasRequired(s => s.MileMarker)
.WithMany(m => m.Spans)
.HasForeignKey(s => s.StartMileMarkerId);
How can I map these 2 columns (StartMileMarkerId and EndMileMarkerId) to the same primary key?
Since you have 2 foreign keys, you need 2 collection navigation properties in MileMarker and 2 reference navigation properties in Span. Something like this:
MileMarker class:
public virtual ICollection<Span> StartSpans { get; set; }
public virtual ICollection<Span> EndSpans { get; set; }
Span class:
public virtual MileMarker StartMileMarker { get; set; }
public virtual MileMarker EndMileMarker { get; set; }
Configuration:
modelBuilder.Entity<Span>()
.HasRequired(s => s.StartMileMarker)
.WithMany(m => m.StartSpans)
.HasForeignKey(s => s.StartMileMarkerId);
modelBuilder.Entity<Span>()
.HasRequired(s => s.EndMileMarker)
.WithMany(m => m.EndSpans)
.HasForeignKey(s => s.EndMileMarkerId);
P.S. If your idea is to have ModelMarker.Spans collection mapped to spans with either start or end marker being this marker, it's just not possible.
I am using EF6. I have two models PowerLine and PowerSource. PowerSource has a foreign key column that points to PowerLine. The problem is that the PowerLine object is populating with List of PowerSource but the SourcePowerLine navigation property of PowerSource is always NULL. My models are as follows :
public class PowerLine
{
[Key]
public int ID { get; set; }
public virtual ICollection<PowerSource> PowerSources { get; set; }
}
public class PowerSource
{
[Key]
public int ID { get; set; }
public int SourcePowerLineID {get;set;}
[ForeignKey("SourcePowerLineID")]
public virtual PowerLine SourcePowerLine { get; set; }
}
I tried Column(Order) attribute as well to set the correct order also I tried to use Fluent API like as follows :
modelBuilder.Entity<PowerSource>()
.HasRequired(c => c.SourcePowerLine )
.WithMany(b => b.PowerSources)
.HasForeignKey(c => c.SourcePowerLineID);
Your [ForeingKey()] attribute is not really pointing to anywhere, try:
[ForeignKey("PowerLine")]
public int SourcePowerLineID { get; set; }
I am struggling to get some related navigation properties loading up using EF code first.
I have a User table which is my primary table, which every time you update it, it generates a UserLight object containing only the basics. This is linked via a one-to-one mapping with User, so the User object generates the identity key and then when it saves, a UserLlight object is created using that UserId as it's key.
I now have a conversation object between two users which I want to load in only the UserLight objects for the sender and receiver, for performance reasons. I have tried mapping using Fluent and CF but when I load the objects from my repository, only the UserStartedId and UserRecipientId integer fields are populated, the actual UserLight objects UserStarted and UserRecipient are null.
My conversation class is as follows
public class DbConversation
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long ConversationId { get; set; }
public virtual DbUserLight UserStarted { get; set; }
public int UserStartedId { get; set; }
public virtual DbUserLight UserRecipient { get; set; }
public int UserRecipientId { get; set; }
public virtual IList<DbStoryMessage> Messages { get; set; }
}
My Userlight class is as follows (abbreviated)
public class DbUserLight
{
public int UserId { get; set; }
[Required]
[MaxLength(50)]
public string FirstName { get; set; }
[Required]
public DateTime DateOfBirth { get; set; }
}
My DbContext OnModelCreating has the following
modelBuilder.Entity<DbUserLight>()
.HasKey(a => a.UserId);
modelBuilder.Entity<DbUserLight>()
.Property(a => a.UserId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
modelBuilder.Entity<DbStoryConversation>()
.HasKey(c => c.ConversationId);
modelBuilder.Entity<DbStoryConversation>()
.Property(c => c.ConversationId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<DbStoryConversation>()
.HasMany<DbStoryMessage>(c => c.Messages)
.WithRequired(m => m.Conversation)
.WillCascadeOnDelete(true);
And my repository call is as follows
public IQueryable<DbStoryInboxMessage> GetInboxMessages()
{
return Work.Context.StoryInboxMessages
.Include(i => i.Conversation.UserStarted)
.Include(i => i.Conversation.UserRecipient)
.Include(i => i.Conversation.Messages);
}
Can anyone shed any light on why this is not working?
Did you try adding the foreign key annotations?
public class DbConversation
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long ConversationId { get; set; }
[ForeignKey("UserStartedId")]
public virtual DbUserLight UserStarted { get; set; }
public int UserStartedId { get; set; }
[ForeignKey("UserRecipientId")]
public virtual DbUserLight UserRecipient { get; set; }
public int UserRecipientId { get; set; }
public virtual IList<DbStoryMessage> Messages { get; set; }
}