I'm attempting to set up EF classes for a "code-first" approach, using the techniques outlined at the EF page at Data Developer Center, a related SO answer here, another SO thread here, and this article at CodeProject.com.
Two classes need to have one-to-many interaction using data annotations, specifically foreign keys.
Everything seems to be in order with my classes. I can perform a context.Add(), but when saving the changes through context.SaveChanges(), I get the following error message:
The ForeignKeyAttribute on property 'Machines' on type
'BacklogTracker.Models.EFModels.Customer' is not valid. The foreign
key name 'MachID' was not found on the dependent type.
Why am I getting this error?
My EF classes and foreign keys seem to be in order, based on the examples and techniques outlined in the links at the beginning of this question... but I can't figure out what's wrong. I'm a beginner at this, so it's very possible I'm missing something entirely.
I'm using VS2013 Express, .NET framework 4.5, EF 6.1.2. Here is code for the classes:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class Customer
{
public Customer()
{
Machines = new List<Machine>();
}
[Key]
public int Number { get; set; }
public string Name { get; set; }
public string MachID { get; set; }
[ForeignKey("MachID")]
public virtual List<Machine> Machines { get; set; }
}
and
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class Machine
{
public Machine()
{
Customer = new Customer();
}
[Key]
public string SN { get; set; }
public string Model { get; set; }
public int Hours { get; set; }
public string Location { get; set; }
public int CustID { get; set; }
[ForeignKey("CustID")]
public virtual Customer Customer { get; set; }
}
By your codes, I suppose to that the relationship between customer and machine is one-to-many. One customer has many machines, and a machine is owned by one customer.
The machines are grouped into customer by a foreign key CustID. For those machines with the same CustID, they are under the same customer. If customer has a column named MachID, it will mean that a machine has many customers. It will conflict the fact that one customer has many machines.
#Nathan is right about to remove those codes.
If the MachID should exist, then you need to answer a question about what relationship holds between customer and machine. Is it many-to-many, one-to-many or many-to-one ? If the relationship is many-to-many, then your codes are totally wrong.
public class Customer
{
[Key]
public int Number { get; set; }
// One customer has many machines, so the `MachID` SHOULD NOT exist.
// public string MachID { get; set; }
// [ForeignKey("MachID")]
public virtual List<Machine> Machines { get; set; }
}
public class Machine
{
[Key]
public string SN { get; set; }
...
public int CustID { get; set; }
[ForeignKey("CustID")]
public virtual Customer Customer { get; set; }
}
You should remove:
public string MachID { get; set; }
[ForeignKey("MachID")]
EF can infer the relationship from the machine side, if I understand you correctly
Also, shouldn't you have ID properties ?
It might be because you are annotating List rather than the Machine class itself. I'm not sure if relationships can be defined on a collection like that.
Related
I'm working on a serverside blazor project (.net 6) using Entity Framework with code first. I have two tables, let's say (in order to protect private data), we have the Tables Band and Bandsman. Originally, every band could have exactly one bandsman, a bandsman could be connected to more then one band though. It's an example, so please don't question this assumptive circumstances.
I created two classes:
[Table("Band")]
public partial class Band
{
[Key]
public int Id { get; set; }
public string BandName { get; set; }
public int? BandsmanId { get; set; }
public virtual Bandsman Bandsman { get; set; }
}
[Table("Bandsman")]
public partial class Bandsman
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Band> Band { get; set; }
}
So far everything works fine. Entity Framework set the correct foreign key. But now I have to insert a second bandsman. Let's say, the first bandsman is a keyboarder, now I need a drummer as well. So I altered the existing classes:
[Table("Band")]
public partial class Band
{
[Key]
public int Id { get; set; }
public string BandName { get; set; }
public int? BandsmanId { get; set; }
public int? DrummerId { get; set; }
public virtual Bandsman Bandsman { get; set; }
public virtual Bandsman Drummer { get; set; }
}
[Table("Bandsman")]
public partial class Bandsman
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Band> Band { get; set; }
public virtual List<Band> Drummer { get; set; }
}
I know I have to tell Entity Framework now how to map the tables. So I added mapping instructions to the OnModelCreating-Method in DbContext:
builder.Entity<Band>().HasOne(a => a.Bandsman).WithMany().HasForeignKey(b => b.BandsmanId);
builder.Entity<Band>().HasOne(a => a.Drummer).WithMany().HasForeignKey(b => b.DrummerId);
This doesn't work. When I create the migrations I see that Entity Frameworks tries to create new Columns BandsmanId1 and BandsmanId2 to the Band-Table instead of using the Columns I defined.
So I tried to add the instructions the other way around, too, in addition to the previous ones:
builder.Entity<Bandsman>().HasMany<Band>(a => a.Band).WithOne().HasForeignKey(b => b.BandsmanId);
builder.Entity<Bandsman>().HasMany<Band>(a => a.Drummer).WithOne().HasForeignKey(b => b.DrummerId);
It's still the same, Entity Framework tries to add new columns and map the foreign keys to them.
I also tried to rename Band.BandsmanId to Band.KeyboarderId or rather add and map a new column with the new name (so existing data won't get lost), rename Band.Bandsman to Band.Keyboarder and Bandsman.Band to Bandsman.Keyboarder. With no effect, Entity Framework still seems incapable to use the colums I want it to use. I guess the instructions I added to OnModelCreating in DbContext are incorrect, but I'm not able to find out how to put it right. I found some examples here on stackoverflow and elsewhere, but I can't manage to convert one of this examples to my code.
So I hope someone can help me to put the classes and instructions right.
After posting my question, I found the solution in a post that was shown as possibly related:
Entity Framework Code First - two Foreign Keys from same table
I was close, my only mistake was not to name the virtual List-Property of the Bandsman-Class in the .HasMany()-Part of the instructions. So Entity Framework didn't now these properties were related to the foreign key columns in the band-table and tried to create the assumed-to-be-missing columns on its own. This way it works:
builder.Entity<Band>().HasOne(a => a.Bandsman).WithMany(b => b.Band).HasForeignKey(a => a.BandsmanId);
builder.Entity<Band>().HasOne(a => a.Drummer).WithMany(b => b.Drummer).HasForeignKey(a => a.DrummerId);
I am getting this error
"The entity type 'DisplayFormatAttribute' requires a primary key to be defined." on the terminal when I try to run this code
Dotnet ef migrations add firstMigrationAddModels
I am creating a code first database migration using Entity-framework core 2.0
I have many models (Classes) and One class inherits from another, To solve that problem I used the Inheritance functionality of the Entity Framework core called Table Per Hierarchy (TPH)
https://www.learnentityframeworkcore.com/inheritance
I put both the derived and base class in Dbset of the dbcontext
public DbSet<Person> people { get; set; }
public DbSet<Student> students { get; set; }
The STUDENT class doesn't have PK because the Person has it.
I also have classes that have many to many relationships and I solved that by creating a bridge class
The error says I need the primary key inside "DisplayFormatAttribute"
but I don't have access to that class
I am using DataAnotationAttributes like Maxlength() and minlength() in my models so I am accessing that class some how.
Other types I am using are PhoneAttribute,EmailAddressAttribute
[MaxLength(15)]
public PhoneAttribute Phone { get; set; }
[MaxLength(254)]
public EmailAddressAttribute Email { get; set; }
I solved it. The problem was my phone number and email type attributes
public PhoneAttribute Phone { get; set; }
public EmailAddressAttribute Email { get; set; }
There is no SQL server equivalent type for PhoneAttribute and EmailAddressAttributes
I took them out and changed them to int and string respectively and it worked
public int Phone { get; set; }
public string Email { get; set; }
You have to set one of your properties using the data annotation [Key]
This [Key] will practically be the identifier of your data table.
I solved it. The problem was my phone number and email type attributes
public PhoneAttribute Phone { get; set; }
public EmailAddressAttribute Email { get; set; }
There is no SQL server equivalent type for PhoneAttribute and EmailAddressAttributes
I took them out and changed them to int and string respectively and it worked
public int Phone { get; set; }
public string Email { get; set; }
Đ¢his works for me thank you very much
I'm working on mapping a legacy application with classes and use EntityFramework against it.
One flaw I have found in this legacy database is that multiple tables refer to a specific table through 2 different fields.
I'm not sure if this is possible and why I can't seem to find anything about it so I am here.
Here is a visual sample:
public class Term {
[Key]
public string Id { get; set; } // sample value: "12-34-56/78"
public string CleanId { get; set; } // sample value: "12345678" (basically the Id without special characters)
public DateTime Date { get; set; }
}
public class App {
public int Id { get; set; }
public string CleanTermId { get; set; } // foreign key is in Term class using the `CleanId` field
}
public class Question {
public int Id { get; set; }
public string TermId { get; set; } // foreign key is in Term class using the `Id` field
}
How can I properly add a navigational property from App and Question to the Term class using either DataAnnotations (preferred) to Fluent API? I do not require a navigational property from Term to App or Question but it's ok if your answer includes it.
Let me know if this is not clear.
Joining on fields other than Primary Key was something that isnt supported in EF versions prior to EF Core, however with your mention of it being a legacy app I doubt you would want to overhaul it to be able to use EF Core.
There was a User Voice request for the feature to be added Here which the response is that they had no plans to add this functionality into EF6 - so Core would be the only way to really do this.
In terms of your classes you would be able to link Question and Term as its based PK - FK, but the App to Term is basing both on non-PK fields, even with a Unique constraint on the DB, this is something not supported in EF prior to Core
Hi this is the correct Code:
public class Term
{
[Key]
public string Id { get; set; }
public string CleanId { get; set; }
public DateTime Date { get; set; }
}
public class App
{
public int Id { get; set; }
[ForeignKey("CleanTermId")]
public Term MyTerm { get; set; }
public string CleanTermId { get; set; }
}
public class Question
{
public int Id { get; set; }
[ForeignKey("TermId")]
public Term MyTerm { get; set; }
public string TermId { get; set; }
}
I'm pretty new to Entity Framework as a FE Dev doing hobby stuff in my spare time. I'm trying to setup a many to many relationship with the following two classes. I want to have a table with all the users of the application. Each user can have multiple DuBists. In each DuBist there can participate multiple Users but only one User can be the active User. So I try like this (and many other things but that seams most logical to me):
public class DuBist : EntityData
{
public string Title { get; set; }
public virtual User ActiveUser { get; set; }
public int ChangeCount { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class User : EntityData
{
public string UserId { get; set; }
public string Name { get; set; }
public string ImageRef { get; set; }
[JsonIgnore]
public virtual ICollection<DuBist> DuBists { get; set; }
}
When I add a new DuBist I get this exception:
SqlException: Violation of PRIMARY KEY constraint 'PK_dbo.Users'. Cannot insert duplicate key in object 'dbo.Users'. The duplicate key value is (0).
Mock Data, so one of the users has the id "0".
Looks like I don't know enough to google what is wrong here, any help is appreciated a lot =)
What I am trying to do is I have two tables which can be linked many to many, but the object on either side may not exist yet. Whilst this gives me chills just thinking about it, it is required for what I am working on.
I've never had to do this before with the Entity Framework Code First, I have no problem creating the many to many relationship but only when both sides exist, so I'm not 100% certain that this is even possible but hopefully someone will be able to identify how I can achieve this.
So far as entities on both sides can be optional, you can do this using third entity:
public class Entity1
{
public int Id { get; set; }
}
public class Entity2
{
public int Id { get; set; }
}
public class Many2ManyRelationEntity
{
public int Id { get; set; }
public int? Entity1Id { get; set; }
public int? Entity2Id { get; set; }
}