How to change foreign key suffix in Entity Framework Core? - entity-framework-core

In EF Core with a code-first approach, by default column referencing another entity has an Id suffix - for example PersonId.
Is it possible - and if so, how? - to change it to _id, so to person_id?

Create the foreign key explicitly under the name you want - in your case Parent_Id. Keep a navigation property and foreign key property.
public int Parent_ID { get; set; }
public virtual Parent Parent { get; set; }
Map the foreign key relations using .HasForeignKey(). Something similar as below
builder.HasOne(d => d.Prop)
.WithMany(p => p.NavigationProp)
.HasForeignKey(d => d.ForeignKeyProp)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_ConstraintName");
If you prefer data annotation, you could also use
[Column("Parent_ID")]
public int ParentID { get; set; }

To add to WisdomSeeker's answer, you can use a [ForeignKey] annotation to point at a shadow property for the FK.
Given a class like a Course with a Person reference for a Teacher:
public class Course
{
[Key]
public int Id {get; set;}
// other fields.
[ForeignKey("person_id")]
public virtual Person Teacher { get; set; }
}
Alternatives as above would be:
[ForeignKey("Teacher")]
public int person_id { get; set; } // Not recommended naming convention in code.
public virtual Person Teacher { get; set; }
or
[Column("person_id"), ForeignKey("Teacher")]
public int TeacherId { get; set; }
public virtual Person Teacher { get; set; }
I generally avoid adding FK fields into classes as this leads to two sources of truth for what Teacher is assigned to a course. You have course.TeacherId and course.Teacher.Id, which could differ on update prior and after a SaveChanges. Shadow properties help avoid confusion and keep data updates consistent.
Using [Column] is common in Db-First implementations where you want to use a C# naming convention for properties to use in-code, but abide by existing/desired DB naming conventions in the database. I don't generally recommend using DB naming conventions in C# classes.

Related

One-to-one mapping in multiple tables

I'm trying to solve one puzzle, but with no luck so far.
I have an article (or blog post) and comment entities, they both have content. In order to support lazy loading for content (there is no need to load the content when I need to display a list of articles or comments) I decided to move content to separate table and organize one-to-one mapping. Here is an example of what I think:
public class Content {
[Key]
public int ID { get; set; }
public string RawContent { get; set; }
// a bunch of scalar properties, like content type and so on
}
public class BlogArticle {
[Key]
public int ID { get; set; }
public int ContentID { get; set; }
[ForeignKey(nameof(ContentID)]
public virtual Content Text { get; set; }
// other properties related to BlogArticle
}
public class Comment {
[Key]
public int ID { get; set; }
public int ContentID { get; set; }
[ForeignKey(nameof(ContentID)]
public virtual Content Text { get; set; }
// other properties related to comment
}
<...>
From first look it seems ok: I can create blog articles, comments and attach content (at first I insert content, obviously). Update works as well. However, deletion doesn't work: when I delete blog article or comment, content is not deleted (but I want to delete it when blog article or comment are deleted, not opposite).
From what I understand my biggest issue because of relationship direction: in my case, Content entity is principal end and BlogArticle and Comment are dependent ends. In order to solve the puzzle, I need to change principal/dependent relationship. Again, from what I understand in order to change relationship direction I need to have a foreign key in Content entity and use fluent API to describe who is parent (principal) and who is child (dependent) in one-to-one relationship. Since many tables (there might be other entities with content property) are pointing to Content table, it doesn't seem very easy. Am I correct in my understanding?
One possible solution I could imagine is to create multiple foreign keys in Content table and point to each related table:
public class Content {
[Key]
public int ID { get; set; }
public string RawContent { get; set; }
// foreign keys
public int BlogArticleID { get; set; }
public int CommentID { get; set; }
public int WebWidgetID { get; set; }
// other foreign keys if necessary
}
probably, foreign keys must be nullable (because only single foreign key is used at once). Then use Entity Framework fluent API to describe relationship directions and organize cascade delete. For me it looks ugly, but I have no other ideas.
My question: is my proposed solution good/reliable? Are there other options I can look at?
Thanks in advance!
All your thoughts are correct. And your proposed solution is the only way with traditional relational design. The drawback of course is the need of multiple mutually exclusive nullable FKs.
The other options I see are as follows:
(1) Using EF inheritance for the entities holding Content. e.g.
public abstract class EntityWithContent
{
[Key]
public int ID { get; set; }
public virtual Content Text { get; set; }
}
public class BlogArticle : EntityWithContent
{
// other specific properties
}
public class Comment : EntityWithContent
{
// other specific properties
}
and configured one-to-one relationship between Content (dependent) and EntityWithContent (principal) using either shared PK association or FK association.
But since EF Core currently supports only TPH strategy (i.e. all the derived entities share one and the same table with union of all fields), I won't recommend it.
(2) Making Content owned type.
This is closer to the intent, but unfortunately EF Core currently always loads the owned entity data along with the owner data (even if they are configured to be provided by different database tables), which is against your original goal, so I won't suggest that either.
(3) Using table splitting feature.
If the main goal is simple to support controlled (lazy/eager/explicit) loading and the Content is always required, then this might be the best solution so far.
It would require a bit more configuration, but at the end it will give you the original table design (single table per entity) with the desired loading behavior:
Model:
public abstract class Content
{
[Key]
public int ID { get; set; }
public string RawContent { get; set; }
// a bunch of scalar properties, like content type and so on
}
public class BlogArticle
{
[Key]
public int ID { get; set; }
public virtual BlogArticleContent Text { get; set; }
// other properties related to BlogArticle
}
public class BlogArticleContent : Content
{
}
public class Comment
{
[Key]
public int ID { get; set; }
public virtual CommentContent Text { get; set; }
// other properties related to comment
}
public class CommentContent : Content
{
}
Note that here Content class is not part of EF inheritance hierarchy, but simple base class with the common properties (abstract modifier is not strongly necessary). The actual derived classes might or might not define their own properties.
Configuration:
modelBuilder.Entity<BlogArticle>().ToTable("BlogArticles");
modelBuilder.Entity<BlogArticle>()
.HasOne(e => e.Text)
.WithOne()
.HasForeignKey<BlogArticleContent>(e => e.ID);
modelBuilder.Entity<BlogArticleContent>().ToTable("BlogArticles");
modelBuilder.Entity<Comment>().ToTable("Comments");
modelBuilder.Entity<Comment>()
.HasOne(e => e.Text)
.WithOne()
.HasForeignKey<CommentContent>(e => e.ID);
modelBuilder.Entity<CommentContent>().ToTable("Comments");

EF CF - How do I build optional:optional relationship?

I want Foo to have an optional Bar and Bar to have an optional Foo.
I seemed to manage to get it working but I had an extra column being created on only one of the tables, e.g. it made InvitationId and then also Invitation_Id in SQL on only one of the tables, even though both entities are setup the same way, but in reverse.
So I wanted to make a smaller repro so I could ask the question on SO, but in the process, and although I have just copied the original entities, removed some properties, I now have a different error, which is worryingly non-deterministic.
Ok, code.
[Table("Foo")]
public partial class Foo
{
[Key]
public Guid Id { get; set; }
[Required]
[StringLength(128)]
public string Name { get; set; }
// Referential
[ForeignKey("Bar")]
public Guid? BarId { get; set; }
public virtual Bar Bar { get; set; }
}
[Table("Bar")]
public partial class Bar
{
[Key]
public Guid Id { get; set; }
[Required]
[StringLength(128)]
public string Name { get; set; }
// Referential
[ForeignKey("Foo")]
public Guid? FooId { get; set; }
public virtual Foo Foo { get; set; }
}
And in OnModelCreating
modelBuilder.Entity<Foo>()
.HasOptional<Bar>(foo => foo.Bar)
.WithOptionalPrincipal(bar => bar.Foo);
The error is:
The navigation property 'Foo' declared on type 'Product.Data.Entities.Bar' has been configured with conflicting foreign keys.
The original entities still exist in the project and are setup in exactly the same way except they have more properties, but they get created without error, except one has the extraneous FK column.
So there's a number of issues:
Why did I get the extra Invitation_Id column when it already has InvitationId?
Why can I not reproduce it?
Why does the error now appear? And if I solve that, is it going to help me with my original entities if they don't have the same issue.
What's the proper way of achieving my objective in my opening sentence above?
Meanwhile, I'm going to begin building Foo and Bar back into Invitation and Expectation bit by bit until it goes funny.
Update
So I ended up with EXACT copies of the original entities in all but name. These copies caused the FK conflict error above, but the originals do not!!
I then removed the originals and renamed the copies to their original names, changing none of the properties or attributes, and the error went away and I was back to the original issue of the extraneous FK column!
Bonkers.
Luke
The first thing is in an one to one relationship one end must be the principal and the another one is the dependent, so you can't specify a FK property in both entities. The second thing is if you are going to use a FK property, EF requires the PK of the dependent entity should be FK too:
public class Principal
{
public int Id{get;set;}
public virtual Dependent Dependent{get;set;}
}
public class Dependent
{
[Key, ForeignKey("Principal")]
public int PrincipalId{get;set;}
public virtual Principal Principal{get;set;}
}
The third thing is EF lets you configure a one-to-one relationship with optional in both sides using Fluent API, but you can specify the FK, because as I said before, it should be configured as PK too, so EF will handle that FK for you in DB, that's way you have an extra Invitation_Id column.
To resolve your issue your model should be this way(remove the FK properties):
[Table("Foo")]
public partial class Foo
{
[Key]
public Guid Id { get; set; }
[Required]
[StringLength(128)]
public string Name { get; set; }
// Referential
public virtual Bar Bar { get; set; }
}
[Table("Bar")]
public partial class Bar
{
[Key]
public Guid Id { get; set; }
[Required]
[StringLength(128)]
public string Name { get; set; }
// Referential
public virtual Foo Foo { get; set; }
}
And use the same Fluent Api configuration:
modelBuilder.Entity<Foo>()
.HasOptional(foo => foo.Bar)
.WithOptionalPrincipal(bar => bar.Foo);
About why the exception is not happened in your real code, I think the same as #user2697817, you should be creating two different relationships, but I can fully ensure that because I'm not seeing your real model.
A second option could be the solution that is showed by #user2697817, but in that case you are going to have two different relationships.
As I mentioned in my comment, because there is two relationships and it's possible to have a navigation property for each side of the relationship I think EF is having trouble distinguishing which navigation prop is part of which relationship.
I would suggest defining both relationships explicitly in your OnModelCreating
modelBuilder.Entity<Foo>().HasOptional(f => f.Bar)
.WithMany()
.HasForeignKey(f => f.BarId);
modelBuilder.Entity<Bar>().HasOptional(b => b.Foo)
.WithMany()
.HasForeignKey(b => b.FooId);

EF: Unable to determine the principal end of an association between the types

Unable to determine the principal end of an association between the types. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
Models:
`
[Table("Employees")]
public class Employee : Entity
{
public string Name { get; set; }
public int? AbsenceId { get; set; }
[ForeignKey("AbsenceId")]
public virtual Absence Absence { get; set; }
}
[Table("Absences")]
public class Absence : Entity
{
public DateTime From { get; set; }
public DateTime To { get; set; }
public string Reason { get; set; }
public int? SubstituteId { get; set; }
[ForeignKey("SubstituteId")]
public virtual Employee Substitute { get; set; }
}
`
The Employee have a Absence that can have a Employee that is not same Employee that have a Absence mentioned.
Any solution for this case?
Well, first of all.. You do not need to specify ForeignKey when you are following the Entity Framework conventions. By convention, EF will reocognize the fact that your Navigation property is called Foo and your ForeignKey will be called FooId.
However, the real problem is that you are attempting to create a 1:1 association between two entities and EF does not support associations like this.
EF only supports 1:1 associations with shared primary keys, that is where both tables have the same primary key and one table's PK is a FK to the other table's PK.
If you think about this, it makes sense. There is no native 1:1 relationship in SQL that does not have a shared primary key. If you add a FK in one table to the other, it creates a 1:Many. You can simulate a 1:1 by creating a unique constraint on the FK but EF does not support constraints.
Looking at your model. Do you really want a 1:1 anyways? Can an employee really only have a single absence? Ever? Probably not. You probably want Absence to be a 1:Many. So remove AbsenceId and change Absence to:
public virtual List<Absence> Absences { get; set; }

Entity Framework code first FK field

I have two classes:
public class Fighter
{
public int FighterID { get; set; }
public int DivsionID { get; set; }
public string Name { get; set; }
//...
public virtual Division Division { get; set; }
}
public class Division
{
public int DivisionID { get; set; }
public string Name { get; set; }
public int? FromWeight { get; set; }
public int? ToWeight { get; set; }
public ICollection<Fighter> Fighters { get; set; }
}
Why do I have Division_DivisionID on my Fighters table ? I thought the DevisionID should be the FK.
I wrote an article on how this works, take a look at http://blog.staticvoid.co.nz/2012/07/entity-framework-navigation-property.html - See How does Entity Framework detect Navigation Properties
In short this is due to a convention which says FKs are named
<LocalPropertyName>_<ForeignIdPropertyName>
Also see Entity Framework Navigation Property generation rules
to make EF name the FK DivisionID, add the following to your modelbuilder
modelBuilder.Entity<Fighter>()
.HasRequired(f => f.Division)
.WithMany(d => d.Fighters)
.HasForeignKey(f => f.DivisionID);
You are mixing the EF FK Association concept with your database FK concept, they are not the same. The FK Association concept on EF was introduced so you could do things like lookups and data binding more easily (like DropDownList data binding for example).
The ER FK concept that is created in your table is a mapping for the composition you have on the Fighter class, in this case the Division property. The naming of that table column follows EF's rules.
For more on the EF FK Association read this article.

Why use Base class on POCO's with EF Repository Pattern?

I've seen many EF POCO examples where each POCO class inherits a base Entity class or implements an IEntity interface.
I kind of understand why this is used, but I can't see that it will work in all situations, unless I'm missing something.
The Entity base class might look like this:
public class Entity
{
#region Primitive Properties
[Key]
public int Id { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
[Timestamp]
public byte[] rowversion { get; set; }
#endregion
}
... and the concrete POCO class would look like this:
public class BlogCategory : Entity
{
#region Properties
[Required(ErrorMessage = "Category Name is required.")]
public string CategoryName { get; set; }
public virtual ICollection<Blog> BlogList { get; set; }
#endregion
}
This is fine when all my classes contain a single Primary Key property, but what happens when I have a many-to-many relationship? Usually in a many-to-many relationship, the entity has dual properties that represent the Primary Key of this entity.
Such as:
public class ClaimQuestionAnswer : Entity <-- this will not work, will it?
{
[Key]
public int QuestionId { get; set; }
[Key]
public int AnswerId { get; set; }
public string Answer { get; set; }
public byte[] rowversion { get; set; }
}
Will this particular POCO not inherit the base class?
Any clarification is appreciated.
Thanks.
You might have seen only examples which just don't use any entity classes with composite key. Otherwise they had the same problem you are facing now.
The many-to-many relationship is not the best example because in a true many-to-many relationship the join table does not have a corresponding entity in your model. But you might have for any other reason a composite key in an entity, or you could have entities whose key simply need to have another type (string, long, Guid or whatever).
In this case you cannot use your base class because the key is not a common property anymore for all entities. You could move the key out of the base class and put it into the different derived classes - only DateCreated, DateModified and rowversion are common properties. Or you can create multiple base classes for the different key types you are using.
It all depends what common properties you want to support in all entities.