Entity Framework Core many-to-many relation - getting error "Invalid column name 'id'" - .net-core

I'm doing a triple many-to-many relationship in the same relationship table in Entity Framework Core.
The certificate, language and candidate entities are related to each other from many-to-many in the CandidateLanguageCertificationLanguage relationship table.
The database tables are:
CREATE TABLE candidato.Candidato
(
ID_CANDIDATO int ,
NOMBRE VARCHAR(50) ,
PRIMARY KEY(ID_CANDIDATO)
);
CREATE TABLE candidato.Idiomaa
(
ID_IDIOMA int ,
NOMBRE VARCHAR(50) ,
PRIMARY KEY(ID_IDIOMA)
);
CREATE TABLE candidato.CertificadoIdiomaa
(
ID_CERTIFICADO_IDIOMA int,
NOMBRE VARCHAR(50),
PRIMARY KEY(ID_CERTIFICADO_IDIOMA)
);
CREATE TABLE candidato.CandidatoIdiomaCertificacionIdiomaa
(
ID_CANDIDATO int,
ID_IDIOMA int,
ID_CERTIFICADO_IDIOMA int,
PRIMARY KEY(ID_CANDIDATO, ID_IDIOMA, ID_CERTIFICADO_IDIOMA),
FOREIGN KEY (ID_CANDIDATO) REFERENCES candidato.Candidato (id_candidato),
FOREIGN KEY (ID_IDIOMA) REFERENCES candidato.Idiomaa (ID_IDIOMA),
FOREIGN KEY (ID_CERTIFICADO_IDIOMA) REFERENCES candidato.CertificadoIdiomaa (ID_CERTIFICADO_IDIOMA)
);
The relationships established in the context through Fluent API are:
builder.Entity<CandidatoIdiomaCertificacionIdiomaa>().ToTable("CandidatoIdiomaCertificacionIdiomaa", "candidato");
builder.Entity<CandidatoIdiomaCertificacionIdiomaa>().HasKey(cici => new { cici.IdCandidato, cici.IdIdioma, cici.IdCertificadoIdioma });
builder.Entity<CandidatoIdiomaCertificacionIdiomaa>().Property(cici => cici.IdCandidato).HasColumnName("Id_Candidato");
builder.Entity<CandidatoIdiomaCertificacionIdiomaa>().Property(cici => cici.IdIdioma).HasColumnName("Id_Idioma");
builder.Entity<CandidatoIdiomaCertificacionIdiomaa>().Property(cici => cici.IdCertificadoIdioma).HasColumnName("Id_Certificado_Idioma");
builder.Entity<CertificadoIdiomaa>().ToTable("CertificadoIdiomaa", "candidato");
builder.Entity<CertificadoIdiomaa>().HasKey(ci => ci.Id);
builder.Entity<CertificadoIdiomaa>().Property(ci => ci.Id).HasColumnName("Id_Certificado_Idioma").ValueGeneratedOnAdd();
builder.Entity<CertificadoIdiomaa>().Property(ci => ci.Nombre).HasColumnName("Nombre");
builder.Entity<Idiomaa>().ToTable("Idiomaa", "candidato");
builder.Entity<Idiomaa>().HasKey(i => i.Id);
builder.Entity<Idiomaa>().Property(i => i.Id).HasColumnName("Id_Candidato").ValueGeneratedOnAdd();
builder.Entity<Idiomaa>().Property(i => i.Nombre).HasColumnName("Nombre");
builder.Entity<Candidato>().ToTable("Candidato", "candidato");
builder.Entity<Candidato>().HasKey(i => i.Id);
builder.Entity<Candidato>().Property(i => i.Id).HasColumnName("Id_Candidato").ValueGeneratedOnAdd();
builder.Entity<Candidato>().Property(i => i.Nombre).HasColumnName("Nombre");
builder.Entity<CandidatoIdiomaCertificacionIdiomaa>()
.HasOne(cici => cici.CertificadoIdioma)
.WithMany(cei => cei.CandidatosIdiomasCertificacionesIdiomaas)
.HasForeignKey(cf => cf.IdCertificadoIdioma);
builder.Entity<CandidatoIdiomaCertificacionIdiomaa>()
.HasOne(cici => cici.Candidato)
.WithMany(c => c.CandidatosIdiomasCertificacionesIdiomaas)
.HasForeignKey(cici => cici.IdCandidato);
builder.Entity<CandidatoIdiomaCertificacionIdiomaa>()
.HasOne(cici => cici.Idioma)
.WithMany(cei => cei.CandidatosIdiomasCertificacionesIdiomaas)
.HasForeignKey(cf => cf.IdIdioma);
The models are:
public class Idiomaa
{
#region propiedades
public int Id { get; internal set; }
public string Nombre { get; internal set; }
//public ICollection<CandidatoIdiomaa> CandidatosIdiomas { get; internal set; }
public ICollection<CandidatoIdiomaCertificacionIdiomaa> CandidatosIdiomasCertificacionesIdiomaas { get; internal set; }
#endregion
}
public class CertificadoIdiomaa
{
public int Id{ get; internal set; }
public string Nombre { get; internal set; }
public ICollection<CandidatoIdiomaCertificacionIdiomaa> CandidatosIdiomasCertificacionesIdiomaas { get; internal set; }
}
public class CandidatoIdiomaCertificacionIdiomaa
{
#region propiedades
public int IdCandidato { get; internal set; }
public int IdIdioma { get; internal set; }
public int IdCertificadoIdioma { get; internal set; }
public CertificadoIdiomaa CertificadoIdioma { get; internal set; }
public Candidato Candidato { get; internal set; }
public Idiomaa Idioma { get; internal set; }
#endregion
}
public class Candidato
{
#region propiedades
public int Id { get; internal set; }
public string CorreoElectronico { get; internal set; }
#endregion
}
The query I wrote is:
contexto.Where(certificadoIdioma => certificadoIdioma.Nombre.Contains(filtro))
.Include(ci => ci.CandidatosIdiomasCertificacionesIdiomaas)
.ThenInclude(cici => cici.Idioma).ToList();
The error I get:
Invalid column name 'Id_Candidato'
Invalid column name 'Id_Candidato'
The funny thing is that if I change the include of the query to candidate it works perfect:
contexto.Where(certificadoIdioma => certificadoIdioma.Nombre.Contains(filtro))
.Include(ci => ci.CandidatosIdiomasCertificacionesIdiomaas)
.ThenInclude(cici => cici.candidato).ToList();
The tables have been made by a DBA, I am a programmer and I cannot modify the database, I know that you could make the relations in several tables instead of one, your reasons will be, that's another story. I am sure that in Entity Framework Core this can be done but I do not know how, I suspect that I have made a mistake when setting up the relationships in Fluent API, but I have been reviewing it for hours and nothing ...
Could someone take a look at it?
Thank you so much guys.
regards

You are missing int keyword:
public class Idiomaa
{
#region propiedades
public Id { get; internal set; } here int keyword is missing
public string Nombre { get; internal set; }
//public ICollection<CandidatoIdiomaa> CandidatosIdiomas { get; internal set; }
public ICollection<CandidatoIdiomaCertificacionIdiomaa> CandidatosIdiomasCertificacionesIdiomaas { get; internal set; }
#endregion
}
public Id { get; internal set; } here int keyword is missing

Related

Establishing one to one relations with Entity Framework 7

Having the following parent class:
[Table("smart_recharge_registro")]
public class SmartRechargeRegistro
{
[Key]
public int id { get; set; }
public SmartRechargeRequest request { get; set; }
public SmartRechargeProceso proceso { get; set; }
public SmartRechargeResponse response { get; set; }
}
Which in turn references the following child classes:
[Table("smart_recharge_request")]
public class SmartRechargeRequest
{
public String nombreDeUsuario { get; set; }
public String passwordDeUsuario { get; set; }
public String msisdnSuscriptor { get; set; }
}
and:
[Table("smart_recharge_proceso")]
public class SmartRechargeProceso
{
[Key]
public int id { get; set; }
public String carrierId { get; set; }
public String cliente { get; set; }
public String network { get; set; }
}
and lastly:
[Table("smart_recharge_response")]
public class SmartRechargeResponse
{
public Boolean responseSuccess { get; set; }
public int responseCode { get; set; }
public String? responseDetails { get; set; }
}
The Add-Migration and Update-Database command execute without problems. However, when I try to save
await _repository.RegistroColeccion.AddAsync(registro);
await _repositorio.SaveChangesAsync();
I get the following error:
Microsoft.EntityFrameworkCore.DbUpdateException: Could not save changes. Please configure your entity type accordingly.
---> MySql.Data.MySqlClient.MySqlException (0x80004005): Cannot add
or update a child row: a foreign key constraint fails
(beservicebroker_dev.registro_eventos_srdotnet, CONSTRAINT
FK_registro_eventos_srdotnet_SmartRechargeProceso_procesoid FOREIGN
KEY (procesoid) REFERENCES smartrechargeproceso (id) O)
To solve the problem, I tried to create one-to-one relationships following this tutorial
modelBuilder.Entity<SmartRechargeRegistro>()
.HasOne(s => s.request)
.WithOne(r => r.SmartRechargeRegistro)
.HasForeignKey<SmartRechargeRequest>(r => r.id);
modelBuilder.Entity<SmartRechargeRegistro>()
.HasOne(s => s.proceso)
.WithOne(p => p.SmartRechargeRegistro)
.HasForeignKey<SmartRechargeProceso>(p => p.id);
modelBuilder.Entity<SmartRechargeRegistro>()
.HasOne(s => s.response)
.WithOne(r => r.SmartRechargeRegistro)
.HasForeignKey<SmartRechargeResponse>(r => r.id);
Inside SmartRechargeRequest, SmartRechargeProceso and SmartRechargeResponse, added the following:
[JsonIgnore]
public SmartRechargeRegistro SmartRechargeRegistro { get; set; }
Also added inside SmartRechargeRequest and SmartRechargeResponse an id
[Key]
public int id { get; set; }
I'm still unable to test the endpoint because the SmartRechargeRequest and SmartRechargeResponse are completely disfigured in the swagger (even if the [JsonIgnore] or [IgnoreDataMember] annotations are set) due to the presence of that SmartRechargeRegistro object.
I'm pretty sure my solution is misguided and I'm getting the process completely wrong.
What would be the proper way to map one-to-one relationships for this case? Any help will be appreciated.
Please note that in reality, these classes are huge (dozens of properties), so it's not possible to merge all of them on a single table.

The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Posts_Authors_AuthorId"

I successfully built migrations, and I am now trying to update the database with my models in Asp.net core but it keeps giving me this error
"The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Posts_Authors_AuthorId". The conflict occurred in database "MediumDb", table "dbo.Authors", column 'AuthorId'.
The statement has been terminated."
This is what the code in my Post class looks like
namespace Medium.Api.Entities
{
public class Post
{
public Guid Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int NoOfClaps { get; set; }
public DateTime CreatedDate { get; set; }
public IQueryable<Tag> Tags { get; set; }
public IQueryable<PostTag> PostTags { get; set; }
public string Image { get; set; }
// public string Video { get; set; }
public Author Author { get; set; }
public int AuthorId { get; set; }
while the code in my Author class says this
namespace Medium.Api.Entities
{
public class Author
{
public int AuthorId { get; set; }
public string Name { get; set; }
public IQueryable<Post> Posts { get; set; }
}
}
This is my DbContext configuration
{
public class MediumApiContext : DbContext
{
public MediumApiContext(DbContextOptions options)
: base(options)
{
// Database.EnsureCreated();
}
public DbSet<Post> Posts { get; set; }
public DbSet<Author> Authors { get; set; }
public DbSet<Tag> Tags { get; set; }
public DbSet<PostTag> PostTags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Author>()
.HasKey(a => a.AuthorId);
modelBuilder.Entity<Author>()
.HasMany(a => a.Posts)
.WithOne(p => p.Author);
modelBuilder.Entity<Post>()
.ToTable("Posts");
modelBuilder.Entity<Post>()
.HasKey(p => p.Id);
modelBuilder.Entity<Post>()
.HasOne(p => p.Author)
.WithMany(a => a.Posts);
modelBuilder.Entity<Post>()
.Property(p => p.CreatedDate)
.IsRequired()
.HasColumnType("Date")
.HasDefaultValueSql("getutcdate()");
modelBuilder.Entity<Post>()
.Property(p => p.Title)
.IsRequired();
modelBuilder.Entity<Post>()
.Property(p => p.NoOfClaps)
.IsRequired();
modelBuilder.Entity<Post>()
.Property(p => p.Content)
.IsRequired();
I don't know where I seem to be getting it all wrong. Please
We Use FK for data integrity right now you have FOREIGN KEY with Author Table so :
"The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Posts_Authors_AuthorId". The conflict occurred in database "MediumDb", table "dbo.Authors", column 'AuthorId'. The statement has been terminated."
This means that when you create a Post, you must give an Author_ID that is on the Author table

Introducing FOREIGN KEY constraint with ON DELETE NO ACTION doesn't working

I have 4 tables with between them foreign keys as:
Classification - Classification level - Classification value - Classification language
on add-migration it is ok, but when running update-database I get the error:
Introducing FOREIGN KEY constraint 'FK_dbClassificationValue_dbClassificationLevel_ClassificationLevelId' on table 'dbClassificationValue' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint or index. See previous errors.
The tables as mentioned in the error are defined as:
public class SuClassificationLevelModel
{
public int Id { get; set; }
public int ClassificationId { get; set; }
public int Sequence { get; set; }
public bool DateLevel { get; set; }
public bool OnTheFly { get; set; }
public bool Alphabetically { get; set; }
public bool CanLink { get; set; }
public bool InDropDown { get; set; }
public Guid CreatorId { get; set; }
public Guid ModifierId { get; set; }
public DateTime ModifiedDate { get; set; }
public DateTime CreatedDate { get; set; }
public virtual SuClassificationModel Classification { get; set; }
public virtual ICollection<SuClassificationLevelLanguageModel> ClassificationLevelLanguages { get; set; }
public virtual ICollection<SuClassificationValueModel> ClassificationValues { get; set; }
}
and
public class SuClassificationValueModel
{
public int Id { get; set; }
public int ClassificationLevelId { get; set; }
public int ParentValueId { get; set; }
public DateTimeOffset DateFrom { get; set; }
public DateTimeOffset DateTo { get; set; }
public virtual SuClassificationLevelModel ClassificationLevel { get; set; }
public virtual ICollection<SuClassificationValueLanguageModel> ClassificationValueLanguages { get; set; }
}
I have added the delete behavior line in my DBContect class as:
modelBuilder.Entity<SuClassificationValueModel>()
.HasOne(u => u.ClassificationLevel)
.WithMany(u => u.ClassificationValues)
.HasForeignKey(u => u.ClassificationLevelId)
.OnDelete(DeleteBehavior.Restrict);
Also, I have put this on the foreign keys between all tables of the cascading structure.
modelBuilder.Entity<SuClassificationLevelModel>()
.HasOne(u => u.Classification)
.WithMany(u => u.ClassificationLevels)
.HasForeignKey(u => u.ClassificationId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<SuClassificationValueModel>()
.HasOne(u => u.ClassificationLevel)
.WithMany(u => u.ClassificationValues)
.HasForeignKey(u => u.ClassificationLevelId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<SuClassificationValueLanguageModel>()
.HasOne(u => u.ClassificationValue)
.WithMany(u => u.ClassificationValueLanguages)
.HasForeignKey(u => u.ClassificationValueId)
.OnDelete(DeleteBehavior.Restrict);
Further, I have tried to set it for all foreign keys with:
foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
{
relationship.DeleteBehavior = DeleteBehavior.Restrict;
}
As I don't need the cascading delete behavior.
After these different tries I did again an add-migration and update-database. But the error is still the same.
Any suggestions?
Finally, I went into the migration files and changed everywhere from cascade to restrict. As I don't want to use cascade anyway. And now it works.

How to define two FK in the same table?

I have a table called User which inherit the properties from IdentityUser, inside that table I added a reference to the UserFriendship table which need to store all the user friendship:
public class User : IdentityUser
{
public string FirstName { get; set; }
public DateTime BirthDate { get; set; }
public virtual ICollection<UserFriendship> UserFriendship { get; set; }
}
Essentially the UserFriendship contains two users, who are those who have a common friendship, this is the model definition:
public class UserFriendship
{
public int Id { get; set; }
[Key, ForeignKey("UserA")]
public string UserAId { get; set; }
public User UserA { get; set; }
[Key, ForeignKey("UserB")]
public string UserBId { get; set; }
public User UserB { get; set; }
[Required]
public DateTime DateTime { get; set; }
}
I defined the UserA and the UserB which are two FK of a User that are contained inside AspNetUsers table.
Now inside the FluentAPI I declared the following:
builder.Entity<UserFriendship>(entity =>
{
entity.HasKey(f => f.Id);
entity.HasOne(u => u.UserA)
.WithMany(n => n.UserFriendships)
.HasForeignKey(u => u.UserAId)
.IsRequired();
entity.HasOne(u => u.UserB)
.WithMany(n => n.UserFriendships)
.HasForeignKey(u => u.UserBId)
.IsRequired();
});
when I execute this command:
add-migration InitialMigration -context MyAppContext
I'll get:
Cannot create a relationship between 'User.UserFriendships' and 'UserFriendship.UserB', because there already is a relationship between 'User.UserFriendships' and 'UserFriendship.UserA'. Navigation properties can only participate in a single relationship.
I'm not an expert of EnityFramework, but based on that error I think that I cannot define two FK in the same table?
Sorry for any mistake, thanks.
You can define more than one FK in table.
The problem here is you are pointing two times to one navigation property - UserFriendships. The solution would be to create two navigation properties.
Navigation properties are used to browse the related data for specified foreign-key (you have one-to-many relationship) of entity.
Try this:
public class User
{
public string FirstName { get; set; }
public DateTime BirthDate { get; set; }
public ICollection<UserFriendship> UserAFriendships { get; set; }
public ICollection<UserFriendship> UserBFriendships { get; set; }
}
public class UserFriendship
{
public int Id { get; set; }
public string UserAId { get; set; }
public User UserA { get; set; }
public string UserBId { get; set; }
public User UserB { get; set; }
public DateTime DateTime { get; set; }
}
And define the relationship through fluent api as following:
modelBuilder.Entity<UserFriendship>(entity =>
{
entity.HasKey(f => f.Id);
entity.HasOne(u => u.UserA)
.WithMany(n => n.UserAFriendships)
.HasForeignKey(u => u.UserAId)
.IsRequired();
entity.HasOne(u => u.UserB)
.WithMany(n => n.UserBFriendships)
.HasForeignKey(u => u.UserBId)
.IsRequired();
});
What is more - you don't need to specify attributes Key, ForeignKey if you use Fluent API.

EF core , Code First Table rename not detected for migration definition, Scafolder is empty

I get empty migration builder when I change a class name in EF core.
In older EFs , it usually auto generate the code for renaming tables.
But not working in EF core
public class EventComment : Comment
{
[Key]
public int CommentID { get; set; }
public int? ParentID { get; set; }
public virtual EventComment Parent { get; set; }
public int EventID { get; set; }
public virtual EventMaster EventMaster { get; set; }
}
public class Comment
{
public string CommentTitle { get; set; }
public string CommentDetails { get; set; }
public int UpVoteCount { get; set; }
public int DownVoteCount { get; set; }
public int CommentEmotion { get; set; }
public string CommentedByID { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
}
now changing EventComment to CommentMaster. The migration is empty.
I use fluent API for configuring
builder.Entity<EventComment>()
.HasOne(e => e.EventMaster)
.WithMany()
.HasForeignKey(m => m.EventID);
builder.Entity<EventComment>()
.HasOne(e => e.ApplicationUser)
.WithMany()
.HasForeignKey(m => m.CommentedByID);
builder.Entity<EventComment>()
.HasOne(e => e.Parent)
.WithMany()
.HasForeignKey(x => x.ParentID);
This is because of the EF Core default table mapping convention (highlights are mine):
By convention, each entity will be setup to map to a table with the same name as the DbSet<TEntity> property that exposes the entity on the derived context. If no DbSet<TEntity> is included for the given entity, the class name is used.
I guess this is different from the previous EF. The essential part is that although you renamed the entity class, if you keep the old DbSet property name, the table name will not change.

Resources