I got Error on Entity framework insert. When I want to add records in sub table I got field not found error.
This is my main table class as below:
public class Rcp
{
public Rcp()
{
RcpFl = new HashSet<RcpFiles>();
}
[Column("Rcp_ID")]
public int RcpId { get; set; }
public String RcpTitle { get; set; }
public virtual ICollection<RcpFiles> RcpFl { get; set; }
}
And this is my sub table class:
public class RcpFiles
{
[Key]
public int RcpFile_Id { get; set; }
public byte[] Photo { get; set; }
public virtual Rcp rcp { get; set; }
}
On insert time I got error Field "RcpFile_Id" could not be found.
You are relying on convention regarding property names. This is how you can specify the relationships using annotations.
public class Rcp
{
public Rcp()
{
RcpFl = new HashSet<RcpFiles>();
}
[Key]
[Column("Rcp_ID")]
public int RcpId { get; set; }
public String RcpTitle { get; set; }
[InverseProperty(nameof(RcpFiles.rcp))]
public virtual ICollection<RcpFiles> RcpFl { get; set; }
}
public class RcpFiles
{
[Key]
public int RcpFile_Id { get; set; }
public byte[] Photo { get; set; }
[Column("Rcp_ID")]
public int RcpId { get; set; }
[ForeignKey(nameof(RcpId))]
public virtual Rcp rcp { get; set; }
}
It seems you have one-to-many relationship.
First you must add foreign key property to RcpFiles entity:
public class RcpFiles
{
[Key]
public int RcpFile_Id { get; set; }
public byte[] Photo { get; set; }
public virtual Rcp rcp { get; set; }
public int RcpId { get; set; }
}
Then you have to set configuration. You have two options to do that:
Fist is Fluent API:
public class SchoolContext : DbContext
{
public DbSet<RcpFiles> RcpFiles { get; set; }
public DbSet<Rcp> Rcpes{ get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// configures one-to-many relationship
modelBuilder.Entity<RcpFiles>()
.HasRequired<Rcp>(s => s.rcp)
.WithMany(g => g.RcpFl)
.HasForeignKey<int>(s => s.RcpId);
}
}
The second one is Data annotiation: this part explained by #brian-parker (https://stackoverflow.com/users/1492496/brian-parker)
For more information you can see: https://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx
Related
When i try to connect with my database and my class i got this error
But this error appear just for my Consoles,KeyboardMouse and Headphones tables. But they have already primary keys.
and here is my context class
public class EcommContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=.;Database=eCommerce;Trusted_Connection=true");
}
public DbSet<Product> Products { get; set; }
public DbSet<Card> Cards { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Consoles> Consoles { get; set; }
public DbSet<Headphone> Headphones { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> OrderDetails { get; set; }
public DbSet<Mouse> Mouses { get; set; }
public DbSet<MousePad> MousePads { get; set; }
public DbSet<Keyboard> Keyboards { get; set; }
public DbSet<KeyboardAndMouse> KeyboardMouse { get; set; }
public DbSet<Gamepad> Gamepads { get; set; }
public DbSet<Computer> Computers { get; set; }
}
And my entity classes
public class Headphone:IEntity
{
public int HeadphonesId { get; set; }
public int ProductId { get; set; }
public bool IsWireless { get; set; }
public string Type { get; set; }
public string Color { get; set; }
public bool IsGaming { get; set; }
}
public class KeyboardAndMouse:IEntity
{
public int KmId { get; set; }
public int ProductId { get; set; }
public string Color { get; set; }
}
public class Consoles:IEntity
{
public int ConsoleId { get; set; }
public int ProductId { get; set; }
public string Color { get; set; }
public int GamepadNumber { get; set; }
public int Capacity { get; set; }
}
How can I solve that. Does anyone help me ?
In your entity class you need to use [Key] annotation for primary key field. Try like below.
public class Headphone:IEntity
{
[Key]
public int HeadphonesId { get; set; }
}
public class KeyboardAndMouse:IEntity
{
[Key]
public int KmId { get; set; }
}
public class Consoles:IEntity
{
[Key]
public int ConsoleId { get; set; }
}
Please check this out for more information : https://learn.microsoft.com/en-us/ef/core/modeling/keys?tabs=data-annotations#configuring-a-primary-key
FYI - By convention, a property named Id or <type name>Id will be configured as the primary key of an entity.
So if you had HeadphoneId field in Headphone class then it will select that column as primary key by convention and no need to use [Key] annotation or Fluent API to define Primary key field.
I have some classes:
public class Values : Entity
{
[Key]
public int Values_ID { get; set; }
[Required]
public string Values_Name { get; set; }
[Required]
public int ValuesNumeric { get; set; }
public virtual ICollection<ValuesMetrics> ValuesMetrics { get; set; }
}
public class GQMetric : Entity
{
[Key]
public int GQMetric_ID { get; set; }
[Required]
public string GQMetricName { get; set; }
[Required]
public int Importance_ID { get; set; }
public virtual List<GQMetricsQuestions> GQMetricsQuestions { get; set; }
public virtual ICollection<ValuesMetrics> ValuesMetrics { get; set; }
public virtual ImportanceScale ImportanceScale { get; set; }
}
I need to create many-to-many relationship to my own created class ValuesMetrics, not to automatically generated table by entity framework. I have tried a lot of solutions here, here and here but none of it did not work. Eventually, I did this:
public class ValuesMetrics : Entity
{
public int GQMetric_ID { get; set; }
public int Value_ID { get; set; }
public virtual GQMetric GQMetric { get; set; }
public virtual Values Values { get; set; }
}
FluentAPI:
modelBuilder.Entity<ValuesMetrics>()
.HasKey(c => new { c.GQMetric_ID, c.Value_ID });
modelBuilder.Entity<GQMetricsQuestions>()
.HasKey(c => new { c.GQMetric_ID, c.Question_ID });
but created table (ValuesMetrics) have an excessive relationship (GQMetrics_GQMetric_ID). I need only two primary keys from Values and GQMetrics tables
Can you advice me how to solve this problem? Thanks for any help!
Applied #Esteban 's solution from the link already referenced by you: Create code first, many to many, with additional fields in association table
Basically I did the following three changes:
Used POCO entities instead of inheriting from Entity class
Removed EF attributes, since we'll be using fluent API anyway
Changed fluent API configuration
Resulting code:
public class MyContext : DbContext
{
public DbSet<Values> Values { get; set; }
public DbSet<GQMetric> GqMetric { get; set; }
public DbSet<ValuesMetrics> ValuesMetrics { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Values>().HasKey(values => values.Values_ID);
modelBuilder.Entity<GQMetric>().HasKey(metric => metric.GQMetric_ID);
modelBuilder
.Entity<ValuesMetrics>()
.HasKey(valuesMetrics => new
{
valuesMetrics.Value_ID,
valuesMetrics.GQMetric_ID
});
modelBuilder
.Entity<ValuesMetrics>()
.HasRequired(valuesMetrics => valuesMetrics.Values)
.WithMany(valueMetrics => valueMetrics.ValuesMetrics)
.HasForeignKey(valueMetrics => valueMetrics.Value_ID);
modelBuilder
.Entity<ValuesMetrics>()
.HasRequired(valuesMetrics => valuesMetrics.GQMetric)
.WithMany(valueMetrics => valueMetrics.ValuesMetrics)
.HasForeignKey(valueMetrics => valueMetrics.GQMetric_ID);
base.OnModelCreating(modelBuilder);
}
}
public class Values
{
public int Values_ID { get; set; }
public string Values_Name { get; set; }
public int ValuesNumeric { get; set; }
public virtual ICollection<ValuesMetrics> ValuesMetrics { get; set; }
}
public class GQMetric
{
public int GQMetric_ID { get; set; }
public string GQMetricName { get; set; }
public virtual ICollection<ValuesMetrics> ValuesMetrics { get; set; }
}
public class ValuesMetrics
{
public int GQMetric_ID { get; set; }
public int Value_ID { get; set; }
public virtual GQMetric GQMetric { get; set; }
public virtual Values Values { get; set; }
}
I am writing an application which uses inheritance and I'm trying to map this to a SQL Server database with TPT structure.
However, for some reason EF generates duplicate foreign keys in both the superclass and subclass tables.
I have these classes:
public abstract class Answer
{
public int AnswerId { get; set; }
[Required]
[MaxLength(250, ErrorMessage = "The answer cannot contain more than 250 characters")]
public String Text { get; set; }
[Required]
[MaxLength(1500, ErrorMessage = "The description cannot contain more than 1500 characters")]
public String Description { get; set; }
public User User { get; set; }
}
public class AgendaAnswer : Answer
{
[Required]
public AgendaModule AgendaModule { get; set; }
}
public class SolutionAnswer : Answer
{
[Required]
public SolutionModule SolutionModule { get; set; }
}
public abstract class Module
{
// for some reason EF doesn't recognize this as primary key
public int ModuleId { get; set; }
[Required]
public String Question { get; set; }
public String Description { get; set; }
[Required]
public DateTime StartTime { get; set; }
[Required]
public DateTime EndTime { get; set; }
public virtual IList<Tag> Tags { get; set; }
}
public class AgendaModule : Module
{
public IList<AgendaAnswer> AgendaAnswers { get; set; }
}
public class SolutionModule : Module
{
public IList<SolutionAnswer> SolutionAnswers { get; set; }
}
public class User
{
public int UserId { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
public int Zip { get; set; }
public bool Active { get; set; }
public virtual IList<AgendaAnswer> AgendaAnswers { get; set; }
public virtual IList<SolutionAnswer> SolutionAnswers { get; set; }
}
And this is the content of my DbContext class:
public DbSet<AgendaModule> AgendaModules { get; set; }
public DbSet<SolutionModule> SolutionModules { get; set; }
public DbSet<AgendaAnswer> AgendaAnswers { get; set; }
public DbSet<SolutionAnswer> SolutionAnswers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Entity<Module>().HasKey(m => m.ModuleId);
modelBuilder.Entity<Answer>().HasKey(a => a.AnswerId);
modelBuilder.Entity<AgendaAnswer>().Map(m =>
{
m.ToTable("AgendaAnswers");
});
modelBuilder.Entity<SolutionAnswer>().Map(m =>
{
m.ToTable("SolutionAnswers");
});
}
When I run my application, EF creates the tables how I want them (TPT), but it duplicates the foreign key to users in each of them (see picture).
Thanks in advance
As noted in my comment above, the solution is to remove the AgendaAnswers and SolutionAnswers properties from the User class.
If you want to keep those collections in the User class, you might have to remove the User and UserId properties from the Answer class and instead duplicate them in the AgendaAnswer and SolutionAnswer classes. See this SO question for more information.
got a little Problem with EF6 Code First (in a MVC Web App).
Enum to classify an Account in a "AccountCircle":
public enum AccountType
{
Circle1,
Circle2,
Circle3,
Circle4,
Circle5
}
Main class for Accounts:
[Table("Accounts")]
public class AccountModel
{
public AccountModel()
{
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
public string Name { get; set; }
public string EMail { get; set; }
}
The main Company-Model
[Table("Companys")]
public class CompanyModel
{
public CompanyModel()
{
this.AccountCircle = new AccountCircleModel();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
public string Name { get; set; }
public int? idAccountCircle { get; set; }
public AccountCircleModel AccountCircle { get; set; }
}
Class for a single circle:
[Table("AccountCircles")]
public class AccountCircleModel
{
public AccountCircleModel()
{
this.Member = new List<AccountCirleMemberModel>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
public int idCompany { get; set; }
public CompanyModel Company { get; set; }
public List<AccountCirleMemberModel> Member { get; set; }
}
and last but not least the account itself with an additinal information what type of member:
[Table("AccountCircleMember")]
public class AccountCirleMemberModel
{
public AccountCirleMemberModel()
{
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
public AccountType Typ { get; set; }
public int idAccount { get; set; }
public virtual AccountModel Account { get; set; }
public int idAccountCircle { get; set; }
public AccountCircleModel AccountCircle { get; set; }
}
And the DbContext
public class TestContext : DbContext
{
public TestContext()
: base()
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// modelBuilder Infos.....
base.OnModelCreating(modelBuilder);
}
#region Tables
public DbSet<AccountModel> Accounts { get; set; }
public DbSet<CompanyModel> Companys { get; set; }
public DbSet<AccountCircleModel> AccountCircles { get; set; }
#endregion
}
So there is a Company, which has an optional property of type "AccountCircle" (1:optional)
In the Accountcircle, there is a List of Accounts with a separate enum (AccountCirleMemberModel 1:many)
I tried hundred of modelBuilder methods to give the EF6 the necessary infos, but no success.
Has someone a hint, to give the DbModelBuilder in the "protected override void OnModelCreating" method the correct relations data?
Big thanks in advance!
monte
Not sure if this answers your question, but if you want to specify the relationships between tables in the DB, using EF Code First, you have to use modifier virtual for your "navigation" properties - those that map to another table. So the code would look like:
[Table("Companys")]
public class CompanyModel
{
// other properties and the rest of the code here
public virtual AccountCircleModel AccountCircle { get; set; }
}
[Table("AccountCircles")]
public class AccountCircleModel
{
// other properties and the rest of the code here
public virtual CompanyModel Company { get; set; }
public virtual ICollection<AccountCirleMemberModel> Member { get; set; }
}
[Table("AccountCircleMember")]
public class AccountCirleMemberModel
{
// other properties and the rest of the code here
public virtual AccountModel Account { get; set; }
public virtual AccountCircleModel AccountCircle { get; set; }
}
You don't need to add properties that would serve as foreign keys - EF would take care of that. You could specify them, but then you'd have to use fluent API to map those properties as foreign keys for specific tables.
I have been up to trying to do some Entity Framework Code First, but I am stuck with the 'FOREIGN KEY constraint may cause cycles or multiple cascade paths.' problem.
Here are my classes:
public class Course
{
public Course()
{
this.Subject = new HashSet<Subject>();
this.Student = new HashSet<Student>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Shift { get; set; }
public int Room { get; set; }
public virtual ICollection<Subject> Subject { get; set; }
public virtual ICollection<Student> Student { get; set; }
}
public class Subject
{
public Subject()
{
this.Deliverable = new HashSet<Deliverable>();
}
public int Id { get; set; }
public string Name { get; set; }
public int StartsAt { get; set; }
public int FinishesAt { get; set; }
public System.TimeSpan Weekdays { get; set; }
public int CourseId { get; set; }
public int TeacherId { get; set; }
public virtual Course Course { get; set; }
public virtual Teacher Teacher { get; set; }
public virtual ICollection<Deliverable> Deliverable { get; set; }
}
public class Student : Person
{
public Student()
{
this.Deliverable = new HashSet<Deliverable>();
}
public decimal Average { get; set; }
public int CourseId { get; set; }
public virtual Course Course { get; set; }
public virtual ICollection<Deliverable> Deliverable { get; set; }
}
public class Teacher : Person
{
public Teacher()
{
this.Subject = new HashSet<Subject>();
}
public virtual ICollection<Subject> Subject { get; set; }
}
public class Deliverable
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Mark { get; set; }
public System.DateTime DeliveredDate { get; set; }
public bool Delivered { get; set; }
public System.DateTime AnnounceDate { get; set; }
public int SubjectId { get; set; }
public int StudentId { get; set; }
public virtual Subject Subject { get; set; }
public virtual Student Student { get; set; }
}
I think it's a reference looping error, but I can't realize the approach on how to resolve it. I'm using Web API and I'm able to change the model, so feel free to modify it please. Could this be resolved using FluentAPI?
Here is the exception. It is thrown the first time I have executed the application:
'Introducing FOREIGN KEY constraint 'FK_dbo.Students_dbo.Courses_CourseId' on table 'Students' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.'
You have to use Fluent-API to disable delete / update. To do this, modify the OnModelCreating method:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Course>().HasMany(c => c.Student).WillCascadeOnDelete(false);
}
I'm not sure if it's the Course class or the Student class who causes issues, if this is not working, try to do a "WillCascadeOnDelete(false)" on your Student class.