Invalid column name error from SQL generated by EF - c#

Below you can see the SQL should join by using [ClassId1] instead of [Class1_ClassId] since the latter doesn't exist.
I'm pretty sure I can use Fluent API to correct this but not sure what methods.
Generated SQL
SELECT ...
FROM [dbo].[School] AS [Extent1]
LEFT OUTER JOIN [dbo].[Student] AS [Extent2] ON [Extent1].[SchoolId] = [Extent2].[SchoolId]
LEFT OUTER JOIN [dbo].[Class] AS [Extent3] ON [Extent2].[Class1_ClassId] = [Extent3].[ClassId]
LEFT OUTER JOIN [dbo].[Class] AS [Extent4] ON [Extent2].[Class2_ClassId] = [Extent4].[ClassId]
WHERE ...
Tables
School
- SchoolId
- Name
- StudentId
Student
- StudentId
- Name
- Class1Id
- Class2Id
Class
- ClassId
- Name
Models
public class School
{
[Required]
public long SchoolId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public long StudentId { get; set; }
public virtual Student Student { get; set; }
}
public class Student
{
[Required]
public long StudentId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public long ClassId1 { get; set; }
public long? ClassId2 { get; set; }
public virtual Class Class1 { get; set; }
public virtual Class Class2 { get; set; }
}
public class Class
{
[Required]
public long ClassId { get; set; }
[Required]
public string Name { get; set; }
}

[Required]
public long ClassId1 { get; set; }
public long? ClassId2 { get; set; }
public virtual Class Class1 { get; set; }
public virtual Class Class2 { get; set; }
You haven't setup any relationship between these properties. Since you haven't defined foreign key columns for Class1 or Class2, it'll create them for you: Class1_ClassId and Class2_ClassId. Creating a migration should create those columns for you; but you'd end up with duplicates (Class1Id and Class1_ClassId for example).
I believe EntityFramework will resolve relationships between properties if the name ends with Id. Which means your setup should be:
[Required]
public long Class1Id { get; set; }
public long? Class2Id { get; set; }
public virtual Class Class1 { get; set; }
public virtual Class Class2 { get; set; }
However, I find it's better to be explicit - purely for readability and to ensure EF doesn't try to get too smart. I'd write it like this:
[Required]
public long ClassId1 { get; set; }
public long? ClassId2 { get; set; }
[ForeignKey("ClassId1")]
public virtual Class Class1 { get; set; }
[ForeignKey("ClassId2")]
public virtual Class Class2 { get; set; }
This should properly setup your foreign key relationships in the database.

I think Entity Framework constructed this SQL from your linq, because the relations between the classes in your model are unclear.
According to your model a School has only one Student, a Student doesn't know which School he attends, and is obliged to have one Class, and possibly a second one. A class does not know in which School it is, nor which Students are in the Class.
Are you sure about your model?
I'd gather that a School would have zero or more Students. A School also has zero or more Classes. Each class is a class in a School.
In database terms this is a typical one-to-many relationship. See Entity Framework Configure One-to-Many Relationship
Furthermore a Student attends zero or more Classes, a Class has one or more Students.
In database terms this is a typical many-to-many relationship. See: Entity Framework configure many-to-many relationship
These articles also describe schools, students and couses. Summarized the class definitions ought to be:
class School
{
public int Id {get; set;}
// a School has many Students:
public virtual ICollection<Student> Students {get; set;}
// a School has many Classes:
public virtual ICollection<Class> Classes {get; set;}
...
}
public class Student
{
public int Id {get; set;}
// A student belongs to one School via Foreign Key
public int SchoolId {get; set;}
public virtual School School {get; set;}
// A student attends many classes
public virtual ICollection<Class> Classes {get; set;}
...
}
class Class
{
public int Id {get; set;}
// a class belongs to one School via foreign key:
public int SchoolId {get; set;}
public virtual School School {get; set;}
// a class has many Students
public virtual ICollection<Student> Students {get; set;}
...
}
After this the DbContext will be as follows:
class MyDbContext : DbContext
{
public DbSet<School> Schools {get; set;}
public DbSet<Student> Students {get; set;}
public DbSet<Class> Classes {get; set;}
}
If you model it like this, entity framework will automatically recognize the one-to-many relationships between School and Students, and create proper foreign keys for it. It will also recognize the many-to-many relationship between Students and Classes. It will even create a table for the many-to-many, which you won't need in your LINQ queries.
Entity Framework uses default conventions If you follow them, you won't need to tell the model about Table names and column names, about primary keys and foreign keys etc.
Back to your question
You want to tell your model that it should use a certain column name for a property instead of the column name it constructed from your class relations.
This can be done using Data Annotations within your class, or using Fluent API within your DbContext. I prefer using Fluent Api, because it allows you to use the same classes in different database structures without having to change the classes. If you want different table names, or different names for primary keys, different precision for decimals, etc, all you have to do is create a new DbContext. You don't have to change your classes, users of your classes won't notice the changes.
Fluent API is described here.
In you case: specify a table name instead of the default table name.
In my example, A Class would be put in table Classs, while of course you'd want it in table Classes:
class MyDbContext : DbContext
{
public DbSet<School> Schools {get; set;}
public DbSet<Student> Students {get; set;}
public DbSet<Class> Classes {get; set;}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Entity Class should be put in table Classes
modelBuilder.Entity<Class>().ToTable("Classes");
// property Student.ClassId in column "ClassId1"
modelBuilder.Entity<Student>() // from class Student
.Property(student => student.ClassId) // take property ClassId
.HasColumnName("ClassId1"); // give it the column name "ClassId1"
}
}

Related

How can we add multiple foreign keys from one model to another on ASP.NET Core & EF Core & C#

So let's say I have an ApplicationUser : IdentityUser model class that has the identity relations and it has a String ID by default and roles assigned when the user signs up.
ApplicationUsers will have different roles for example Student and Library.
The Library will have a list of books while the Student will have list of orders.
Now I want to create a List of another model which will have the name Orders, but the Orders model class will have two UserIds as foreign keys from ApplicationUser.
ApplicationUser: IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Libraries> Libraries { get; set; }
public List<Orders> Orders { get; set; }
}
Since the ApplicationUser is connected with ASPNetRoles, what I want to achieve on Orders model class is that I want to have different StudentId and LibraryId from the same table which is ApplicationUser:
public class Orders
{
[Key]
public id OrderId {get; set;}
[ForeignKey("StudentId")]
public string StudentId { get; set; }
public ApplicationUser Student {get; set;}
[ForeignKey("LibraryId")]
public string LibraryId {get; set;}
public ApplicationUser Library {get; set;}
}
Is there any way I can achieve this? What are the best solutions for this case? I did try ICollection and list but still same. Any suggestion about this would be great.
When I run Add-Migrations, I get this error:
System.InvalidOperationException: Unable to determine the relationship represented by navigation 'ApplicationUser.OrdersLists' of type 'ICollection'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
Thank you.
Ok, something in you model doesn't look quite right...
In your User class you have a collection of Orders and an collection of a class called Library. Yet within your Order class you have a property called Library, but point that at an ApplicationUser class?
EF does support having multiple references to the same class, though you need to explicitly tell it what the FK names would be. EF's default convention is to base FK names on the type of the navigation property, not the name of the navigation property.
Take the following:
public class Order
{
....
public int CreatedById { get; set; }
public virtual ApplicationUser CreatedBy { get; set; }
public int LastModifiedById { get; set; }
public virtual ApplicationUser LastModifiedBy { get; set; }
}
Here by default EF would want to use "ApplicationUser_Id" or "ApplicationUserId" as a FK name for both of the two navigation properties, settling on something like "ApplicationUser_Id" and "ApplicationUser_Id1" if left to its own devices with the schema. In this situation we would need to configure it to use our desired FK properties:
[ForeignKey("CreatedBy")]
public int CreatedById { get; set; }
public virtual ApplicationUser CreatedBy { get; set; }
[ForeignKey("LastModifiedBy")]
public int LastModifiedById { get; set; }
public virtual ApplicationUser LastModifiedBy { get; set; }
or the FK attribute can be put on the navigation property:
public int CreatedById { get; set; }
[ForeignKey("CreatedById")]
public virtual ApplicationUser CreatedBy { get; set; }
public int LastModifiedById { get; set; }
[ForeignKey("LastModifiedById")]
public virtual ApplicationUser LastModifiedBy { get; set; }
The ForeignKey Attribute is a bit weird, as it represents either "I am the FK of ..." if on the FK property, or it represents "My FK is ...." if on the navigation property.
With EF Core the FK property can be left off and treated by EF as a shadow property which is recommended to avoid having two sources of truth in the entity.
[ForeignKey("CreatedById")]
public virtual ApplicationUser CreatedBy { get; set; }
[ForeignKey("LastModifiedById")]
public virtual ApplicationUser LastModifiedBy { get; set; }
In situations where you want bi-directional references in the other side of the relationship, you may need to map those out. For instance if I want a "CreatedOrders" in my ApplicationUser class:
public class ApplicationUser
{
// ...
public virtual ICollection<Order> CreatedOrders { get; set; } = new List<Order>();
}
Now it's generally a good idea to tell EF what to relate this back to since Order has two references to the application user. Again, this can be done on either side of the relationship. So in the case of back in our Order class:
[ForeignKey("CreatedById"), InverseProperty("CreatedOrders")]
public virtual ApplicationUser CreatedBy { get; set; }
This tells EF that CreatedBy on this record is the link to use when accessing the orders for CreatedOrders.
Back to your example it is a bit confusing why ApplicationUser would contain a collection of Libraries while an Order expects a "library" to be a User.

Double column with code first EF

Doing code first try with EF in C# and I got stuck because I declared
public class Members
{
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
public string Surname { get; set; }
[Display(Name = "someDisplayName")]
public bool ABool{ get; set; }
public ReferenceClass ReferenceClass { get; set; }
public byte ReferenceClassId { get; set; }
}
Entity framework adding migration after creating this i got
ID
NAME
SURNAME
ABool
ReferenceClassID
ReferenceClass_ID
in my SQL database. Now nothings maps correctly. How to fix it?!
Your model is unclear to entity framework.
If I look at the names of your identifiers, it seems that you want to model a one-to-many relationship between ReferenceClasses and Members: every ReferenceClass has zero or moreMembers, everyMemberbelongs to exactly oneReferenceClass`.
This is not how you designed your model.You told entity framework that Members is a composition of the complex type ReferenceClass and a byte property ReferenceClassId.
See:
Stack Overflow: Entity Framework Complex Type
Entity Framework: model various types of relations (a.o. one-to-many)
If you look at the column names that entity framework modelled for you, it is clear that it sees ReferenceClass as a complex type (used for composition)
If you want one-to-many you'll have to add the proper navigation properties. You were half way, except for the byte foreign key.
class Member
{
public int Id {get; set;}
...
// Navigation properties:
// a member belongs to exactly one ReferenceClass via foreign key
public int ReferenceClassId {get; set;}
public ReferenceClass ReferenceClass {get; set;}
}
class ReferenceClass {get; set;}
{
public int Id {get; set;}
...
// Navigation Properties:
// A reference class has zero or more Members:
public virtual ICollection<Member> Members {get; set;}
}
If you follow the code-first conventions, then this is enough for entity framework to recognize the one-to-many. Don't forget the virtual near the ICollection!
If you want special column names or table names, you could use Attributes to name them. Although I prefer fluent API, because that would allow you to use the same classes in different databases with different tables.
One-to-many in fluent api: in your DbContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// a ReferenceClass has zero or more Members
// every member belongs to exactly one ReferenceClass
// via foreign key ReferenceClassId
modelBuilder.Entity<ReferenceClass>()
.HasMany(refClass => refClass.Members)
.WithRequired(member => member.ReferenceClass)
.HasforeignKey(member => member.ReferenceClassId)
You can use this if you have different names in your properties. You could also use ToTable and HasColumName if you want to specify different names
modelBuilder.Entity<ReferenceClass>()
.ToTable("MyTable")
.Property(refClass => refClass.Name)
.IsRequired()
.HasColumnName("MyColumnName")
.HasMaxLength(40);
A very good tutorial for entity framework code first
as #BobMeijwaard pointed out it is likely that you want your class definition to be
public class Members
{
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
public string Surname { get; set; }
[Display(Name = "someDisplayName")]
public bool ABool{ get; set; }
public ReferenceClass ReferenceClass { get; set; }
public int ReferenceClassId { get; set; }
}
changing public byte ReferenceClassId { get; set; } to public int ReferenceClassId { get; set; }
if more information can be provided i can update my answer if this is not correct

Entity framework fluent API on already existing data

Model1)
public class Student {
int StudentID {get;set;}
string FirstName {get;set;}
string LastName {get;set;}
ICollection courses = {get; set;}
}
Model2)
public class Course{
int CourseID {get;set;}
string CourseName {get;set;}
int CreditHours {get;set;}
}
Model3)
public class StudentCourse{
int StudentCourseID {get;set;}
int StudentID {get;set;}
int CourseID {get;set;}
}
Now I add a bunch of data to the database...
and the relationship between student to course (one to many) is lost.
That is now I only have three data tables based on the models above in the database
with no relationship between them whatsoever.
If I create another application, write 3 models matching exactly as the models above and define the one to many relationship between
student and course using fluent API, will that work? That is will I be able to relate the data that already exists?
For example,
After doing the step above and querying a list of student and doing student.courses.ToList(); will the courses with matching studentID be returned as a list with that query?
and the relationship between student to course (one to many) is lost.
The relationship isn't working because you're only setting a link on the Student side of it. You also need to add an endpoint for the relationship on Courses:
public class Student {
public virtual ICollection<Course> Courses { get; set; }
}
public class Course {
public virtual Student Student { get; set; }
}
This should set up the 1-many relationship.
many students take the same courses though, so I'd set it up as a many-many relationship:
public class Student {
public virtual ICollection<Course> Courses { get; set; }
}
public class Course {
public virtual ICollection<Student> Students { get; set; }
}
I believe that this should eliminate the need for the StudentCourse table, but I stand under correction on this point.
Now, for your link between them (StudentCourse), you'll want to properly structure your relationships on this one, too:
public class StudentCourse
{
public int Id { get; set; }
public virtual Student Student { get; set; }
public virtual Course Course { get; set; }
}

Entity framework: Unable to define 1:1 relationship

I'd like to define relationship where Student can have only one favorite Course. I expect it would look like this in DB:
STUDENT
ID
Name
FavoriteCourseID
COURSE
ID
Name
How to achieve this with entity framework? I'd prefer to specify it just by attributes. I tried:
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public Course FavoriteCourse { get; set; }
public int? FavoriteCourseID { get; set; }
}
public class Class
{
public int ID { get; set; }
public string Name { get; set; }
}
which gave me this DB model:
STUDENT
ID
Name
FavoriteCourseID
COURSE
ID
Name
StudentID // how to remove this?
Note, that it may happen that several students have the same favorite class and therefore this is unacceptable solution.
Another question: what type of relationship this is? (1:1 / 1:N ?)
To specify 1 to 1 relationship, it is assumed, that primary key for the related entity matches the primary key of first entity. Also you should specify a virtual property to related entity:
public class Student
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public Course FavoriteCourse { get; set; }
public int? FavoriteCourseID { get; set; }
}
public class Class
{
[Key]
[ForeignKey("Student")]
public int ID { get; set; }
public string Name { get; set; }
public virtual Student Student { get; set; }
}
And it will be one-to-zero-or-one relationship. Check this tutorial.
If you will mark FavouriteCourse property with RequiredAttribute, it seems, that it will result in strong one to one relationship.
It will result in adequate database structure:
STUDENT
ID
Name
FavoriteCourseID
COURSE
ID
Name
However, if many students could have one favourite course, this structure will be a problem, as you want one-to-many instead of one-to-one. And you will have a duplicate records in database, because one course can refer only to one student. You have to think about your db design.
You can try this:
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
[ForeignKey("FavoriteCourseId")]
public Course FavoriteCourse { get; set; }
public int? FavoriteCourseId { get; set; }
}
Normally, you define one of the following relations:
Optional:Optional
Required:Optional
Optional:Many
Required:Many
Many:Many
Having Required:Required is not a usual relation, inserting the first entry with such a relation needs special treatment.
I Suppose you want Required:Many as in "Each student has one favorite course but many students may chose the same favorite course".

Entity Framework Mapping join table fields

I have a join table that has a field in it that I need to get into an Entity and have it updatable. I have the Table setup below, the column I need is "PersonelleID" in the "Account" table. Now, there may be multiple, so in that case, there's a concept of primary (think of it as if you were a student who went from one school to another, you'd have the same account but multiple schools).
Any idea how I can bring this into the Entity world? Generating the database ignores this field on the join table (probably because it doesn't know where to put it).
Trying to see what the best route to go is.
if you are using the Code-First approach you would create an entity for the join table that has foreign keys to both Account and School and your extra properties.
public class Account
{
public int AccountId { get; set; }
public string UserName { get; set;}
}
public class AccountSchool
{
[ForeignKey("Account")]
public int AccountId { get; set; }
[ForeignKey("School")]
public string CEEBCodeId { get; set; }
public string PersonelleID { get; set; }
}
public class School
{
[Key]
public string CEEBCodeId { get; set; }
public string Name { get; set;}
}
This is how I've done it and here's is an article explaining how to do it as well:
http://www.itq.nl/blogs/post/Code-First-Entity-Framework-Additional-properties-on-many-to-many-join-tables.aspx

Categories