Entity Framework foreign key object name change - entity-framework

I have an annoying problem that i can't seem to solve. Lets say i have a database with two tables.
Student
INT Id
NVARCHAR(30) Name
INT PrimaryTeacherId
INT SecondaryTeacherId
Teacher
INT Id
NVARCHAR(30) Name
Now when i set foreign key for PrimaryTeacherId and SecondaryTeacherId and use DatabaseFirst mapping in my project i get something like this for Student table
public partial class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int PrimaryTeacherId { get; set; }
public int SecondaryTeacherId { get; set; }
public virtual Teacher Teacher { get; set; }
public virtual Teacher Teacher1 { get; set; }
}
Note the virtual part of the class and their names, Teacher and Teacher1. No matter how i call my FKs entity framework will just override it and set increment names. That's ok if i have one or two keys to the same table but when there is more it's easy to get lost and code looks kinda annoying having object names with numbers in them. I know i can change generated classes name in my solution but when i update model changes will be lost. I'm also using Metadata partial classes for generated classes (mostly for validation and display attributes), can i change name there maybe?
TLDR: I would like to have Teacher and Teacher1 have custom names, so something like this would be awesome
public partial class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int PrimaryTeacherId { get; set; }
public int SecondaryTeacherId { get; set; }
public virtual Teacher PrimaryTeacher { get; set; }
public virtual Teacher SecondaryTeacher { get; set; }
}

Related

FOREIGN KEY constraint May cause cycles or multiple paths

I have read tons of articles seemingly similar to my issue, but just haven't been able to arrive at my ideal solution.
My specific error says:
Introducing FOREIGN KEY constraint 'FK_Scores_Tees_TeeId' on table 'Scores' may cause cycles or multiple cascade paths.
So, the table in question here, looks like this:
{
[Key]
public Guid ScoreId { get; set; }
public int Strokes { get; set; }
public Guid PersonId { get; set; }
public Guid CourseId { get; set; }
public Guid TeeId { get; set; }
[ForeignKey("PersonId")]
public virtual Person Person { get; set; }
[ForeignKey("CourseId")]
public virtual Course Course { get; set; }
[ForeignKey("TeeId")]
public virtual Tee Tee { get; set; }
}
Now, this table references Tees table, shown here:
public class Tee
{
[Key]
public Guid TeeId { get; set; }
public string Name { get; set; }
public int Par { get; set; }
public int Yards { get; set; }
public float Rating { get; set; }
public int Slope { get; set; }
public Guid CourseId { get; set; }
[ForeignKey("CourseId")]
public virtual Course Course { get; set; }
}
I read about making the TeeId nullable in the Scores table. I did that and was able to build run my migration successfully... however I do need this field to be required. If that id is empty/null then I don't have enough information about that particular Score record.
Both Tee and Score have a required reference to Course. When you delete a referenced Course, EF will want to delete the associated Tee and Score. When Tee is deleted, EF will again want to delete the associated Score. This is the "multiple cascade path" problem.
This error brings to light a problem with the design; the two references to Course can be different values which makes no sense in the context used (the score is for one course while referencing a "tee" from another course?). You should refactor your design.
Tees in golf are usually a small subset of value by either color (blue, white, gold, red) or name (ladies', back/champions', seniors, etc). One way to resolve your design issue is to normalize these name and/or color values in a Tee table, then have a CourseTee table that defines the properties of the Course's tees. This would be done by using a compound key either as primary key or candidate key (called alternate key in EF) composed of FK's to Course and Tee. This entity is where you would then define the properties of the course's tees:
public class CourseTee
{
[Key]
public Guid CourseId { get; set; }
public Course Course { get; set; ]
[Key]
public Guid TeeId { get; set; }
public Tee Tee { get; set; }
public int Par { get; set; }
// additional course-tee specific properties
...
}
public class Score // as a golfer, change this to `Round`
{
[Key]
public Guid ScoreId { get; set; } // RoundId :D
public Person Player { get; set; }
public CourseTee CourseTee { get; set; }
public int Strokes { get; set; }
...
}
public class Tee
{
public Guid TeeId { get; set; }
public string Color { get; set }
public string Name { get; set; }
}
Now Course is only defined once in a Score's object graph. To get the Course for a given Score is simply an extra hop: score.CourseTee.Course

Entity Frameworks Creates Auto Column

I am having a problem in Entity Framework. Entity Framework is generating auto column in sql-server and I am not geting how to make insert operation in that particuler column.
For Example in Teacher class,
public class Teacher
{
[Key]
public String Email { set; get; }
public String Name { set; get; }
public List<TeacherBasicInformation> Teacher_Basic_Information { set; get; } = new List<TeacherBasicInformation>();
public String Password { set; get; }
public List<Course> course { set; get; } = new List<Course>();
[JsonIgnore]
public String JWT_Token { set; get; }
[NotMapped]
[Compare("Password")]
public String ConfrimPassword { set; get; }
}
And in TeacherBasicInformation class ,
public class TeacherBasicInformation
{
[Key]
public int ID { set; get; }
[Required]
[MaxLength(20)]
public String Phone { set; get; }
[Required]
[MaxLength(100)]
public String Address { set; get; }
}
After the migration in the sql server, in TeacherBasicInformation table a auto column is created named 'TeacherEmail'. How Can I insert data into this column using form in asp.net core.
In order to prevent auto-generated columns for FK, use [ForeignKey("YourForeignKey")] on the related table in the entity class:
public int TeacherId { get; set; }
[ForeignKey("TeacherId")]
public virtual Teacher Teacher { get; set; }
It looks like you have the email column set up as the primary key column in your Teacher class, and the related database column. If that's the case, you're going to have trouble with it as it will need to be unique to that record, and primary keys aren't designed to be changed. It can be done in certain scenarios but isn't a best practice.
Perhaps a better approach is to have the [Key] attribute on a property of public int Id { get; set; } so they primary key is now a discrete number instead of an email address. Then you can access, set, and update the email address on each record, without interfering with the key at all.

Can I have a child collection linked by more than one relationship?

I have some entities that can be associated with each other. A simple pair of classes to do this would ideally look like:
public class linkableEntity
{
public int Id { get; set;}
public virtual ICollection<Link> Links { get; set; }
}
public class Link
{
public int Id { get; set; }
public int SomeProperty { get; set; }
public int entity1Id { get; set; }
public virtual LinkableEntity entity1 { get; set;}
public int entity2Id { get; set; }
public virtual LinkableEntity entity2 { get; set;}
}
With tables something like:
Table linkableEntity
Column Id
Table link
Column entityId1 - foreign key to linkableEntity.Id
Column entityId2 - foreign key to linkableEntity.Id
Column someProperty
Having tried this out, and looking at this question: Entity Framework Code First - two Foreign Keys from same table I don't think that what I want to do was possible in EF4, has anything changed in EF6 that would make this possible? (I haven't found any more recent questions addressing this subject)
If not, is there a better way of representing this than changing linkableEntity to something like:
public class linkableEntity
{
public int Id { get; set;}
public virtual ICollection<Link> LinksWhereFirst { get; set; }
public virtual ICollection<Link> LinksWhereSecond { get; set; }
}
and then dealing with the mess?

EF Code first : set optional one to one relationship with data annotation

I've the following situation I try to solve : I've 2 tables, a Course table with some fields and a CourseDescription table which is optional (so Course may have a CourseDescription but CourseDescription must have a Course). I'm trying to set this up. So far, here's what I have :
public class Course
{
[Key, Column("Key_Course")]
public int ID { get; set; }
public string Name { get; set; }
public virtual CourseDescription CourseDescription { get; set; }
}
public class CourseDescription
{
[Key, ForeignKey("Course")]
public int ID { get; set; }
public string Description { get; set; }
public string PreRequis { get; set; }
public int CoursesID { get; set; }
[ForeignKey("CoursesID")]
public Course Course { get; set; }
}
This "works" meaning that EF doesn't complains about my model but the relation is not properly done because EF associate the PK of CourseDescription with the PK of Course. In my database, this is not the case (ex : CourseDescription.ID=1 is associated with CourseDescription.CoursesID=3, not 1).
Is there a way to fix that with data annotation ? I know I can use the fluent API but I don't want to override the model building just for that (unless there's no other way).
Thanks
Well, I think you have two choices:
Configure an one to many relationship
If you want to map the FK of the relationship between Course and CourseDescription, and you don't want to declare that FK property as Key of the CourseDescription entity, then, you don't have other choice that configure an one-to-many relationship. In that case your model would be like this:
public class Course
{
[Key, Column("Key_Course")]
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<CourseDescription> CourseDescriptions { get; set;}
}
public class CourseDescription
{
[Key]
public int ID { get; set; }
public string Description { get; set; }
public string PreRequis { get; set; }
[ForeignKey("Course")]
public int CourseID { get; set; }
public Course Course { get; set; }
}
Configure an one-to-one relationship but not map the FK of the
relationship
The only way that EF lets you map the FK in an one-to-one relationship is when the FK is declared as a PK too, so if you want to have diferent Ids in both entities and you want to stablish an one-to-one relationship, then you could do something like this:
public class Course
{
[Key, Column("Key_Course")]
public int ID { get; set; }
public string Name { get; set; }
public CourseDescription CourseDescription { get; set;}
}
public class CourseDescription
{
[Key]
public int ID { get; set; }
public string Description { get; set; }
public string PreRequis { get; set; }
[Required]
public Course Course { get; set; }
}
And work with the navigations properties.
It looks like you should not use ForeignKey attribute for ID property of CourseDescription class as you don't want to have an association between primary keys. Try to remove it.
Edit: It looks like I misunderstood the question previous time.
You can have your CourseDescription this way.
public class CourseDescription
{
[Key, ForeignKey("Course")]
public int ID { get; set; }
public string Description { get; set; }
public string PreRequis { get; set; }
public Course Course { get; set; }
}
In this case you don't need to have CoursesID field. Entities will be connected by primary keys.

Why am I getting an extra foreign key column with Entity Framework Code First Foreign Key Attributes?

I recently came across this strange problem with Entity Framework Code First.
My class looks like this
public class Status
{
[Key]
public int StatusID { get; set; }
public string Name { get; set; }
public int MemberID { get; set; }
[ForeignKey("MemberID")]
public virtual Member Member { get; set; }
public int PosterID { get; set; }
[ForeignKey("PosterID")]
public virtual Member Poster { get; set; }
public virtual ICollection<StatusLike> StatusLikes { get; set; }
public virtual ICollection<StatusComment> StatusComments { get; set; }
}
My Member class looks like this
public class Member
{
[Key]
public int MemberID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Bio { get; set; }
public virtual ICollection<MemberCourseTaken> MemberCourseTakens { get; set; }
public virtual ICollection<Status> Statuses { get; set; }
public virtual ICollection<Club> FoundedClubs { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
public string Phone { get; set; }
public int AccountSourceID { get; set; }
public AccountSource AccountSource { get; set; }
public int AddressID { get; set; }
public Address Address { get; set; }
public string ProfilePhoto { get; set; }
public int MemberRankID { get; set; }
public MemberRank MemberRank { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
}
And for whatever reason the database table that is created has the following columns
StatusID
Name
MemberID
PosterID
Member_MemberID
with MemberID, PosterID, and Member_MemberID being foreign keys.
How can I keep Member_MemberID from being generated?
Your Member_MemberID column is created because of the Member.Statuses property. I can imagine that this is not what you want. Probably members and statuses should exist independent of each other, so you need a junction table.
I don't know if you already use the OnModelCreating override of the DbContext, but that's the place to change the mapping between Member and Status:
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Entity<Member>().HasMany(m => m.Statuses).WithMany();
}
This will create a table MemberStatuses table with the two Id columns as foreign keys. This is a way to model a many-to-many relationship without a navigation property on the "other" side of the association. (I don't think you want a Members property in Status).
I've seen this before. In my case (Using EF 6.1), it was because my Fluent API Mapping was set up like so:
// In my EntityTypeConfiguration<Status>
HasRequired(x => x.Member).WithMany().HasForeignKey(x => x.MemberID);
That code works perfectly fine, but it doesn't tell EF that my Member class's Collection Navigational Property Status ha been taken into account. So, while I explicitly handled the existence of a Member Navigational Property in my Status Class, I now left an orphaned related collection property. That orphaned property, being a collection, tells EF that my Status class needs to have a Foreign Key to it. So it creates that on the Status Class.
To fix it, I had to be 100% explicit.
HasRequired(x => x.Member).WithMany(x => x.Statuses).HasForeignKey(x => x.MemberID)
It could bee that your Statuses Collection property in Member needs an attribute telling it that it is already considered, and not to go auto-creating mappings. I don't know that attribute.