How to specify foreign table key in EF Data Annotations? - c#

I'm trying to configure relations between tables using Data Annotations of Entity Framework. I've found the following example:
public class Student
{
public Student() { }
public int StudentId { get; set; }
public string StudentName { get; set; }
public int StdandardRefId { get; set; }
[ForeignKey("StandardRefId")]
public virtual Standard Standard { get; set; }
}
public class Standard
{
public Standard()
{
StudentsList = new List<Student>();
}
public int StandardId { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
Now, the ForeignKey attribute informs, that StandardRefId is a foregin key. I guess, that EF deduces the target table from type of property (Standard). However, I fail to see, how to define, which column the foreign key refers to. I tried:
[Column("CompanyId")]
public int CompanyId { get; set; }
[ForeignKey("CompanyId")]
[InverseProperty("Id")]
public CompanyDAL Company { get; set; }
However, all I got was the following exception:
An unhandled exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll
Additional information: The property 'Id' cannot be configured as a navigation property. The property must be a valid entity type and the property should have a non-abstract getter and setter. For collection properties the type must implement ICollection where T is a valid entity type.
How can I explicitly say, that CompanyId points to Id property of Company table?

A Foreign Key will always refer to a Primary Key. When you create a navigation property to Company, that FK will refer to the PK of Company.
Entity Framework relies on every entity having a key value that it uses for tracking entities. One of the conventions that code first depends on is how it implies which property is the key in each of the code first classes. That convention is to look for a property named “Id” or one that combines the class name and “Id”, such as “BlogId”. The property will map to a primary key column in the database.
Source
What this means is that unless you have specified a different PK for Company, the "Id" property (and column) will be the PK for that entity.
Note: For the example you found, Standard uses the second convention for PK ie Id

Related

How do you add column description for a foreign key in another table utilizing EF 6?

Referring to this previous post: How to add description to columns in Entity Framework 4.3 code first using migrations?
I have successfully implemented the modified solution proposed by user Abdullah but I have encountered the exception below:
System.Data.SqlClient.SqlException HResult=0x80131904 Message=Object
is invalid. Extended properties are not permitted on
'dbo.School.Students', or the object does not exist.
Sample code as below:
public class School
{
public School()
{
Students = new HashSet<Student>();
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id { get; set; }
[Description("Some Text")]
public string Description { get; set; }
[Description("Some text")]
public ICollection<Student> Students{ get; set; }
}
I understand from the exception message, there is no column generated for Students. Checking the DB shows that the Student table have the column SchoolId as FK.
So the question here is: how do I go about adding/updating the FK description when EF generates the FK column in another table?
As you already understand the foreign key is defined in Student entity and the field is SchoolId so you have to add descriptor there. The Students property in the School entity is the navigation property; a feature from EF to easily get the list of all the students of a particular school.
Although he did not answer my question, I have to thank Raihan for giving me the idea to check again on how Foreign Keys can be declared. :)
Based on Entity Framework Tutorial, a foreign key can be declared 3 ways:
[ForeignKey(NavigationPropertyName)] on the foreign key scalar property in the dependent entity.
[ForeignKey(ForeignKeyPropertyName)] on the related reference navigation property in the dependent entity.
[ForeignKey(ForeignKeyPropertyName)] on the navigation property in the principal entity.
Also referencing to how a one-many relationship can be declared section in Entity Framework Tutorial website, we can see that the method which I had described in my question is Convention 2.
In order for User Raihan's suggestion to work, I will need to change the one-many declaration to Convention 3, which is to declare a navigational properties at both the School and Student classes. Like below:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public School School { get; set; }
}
public class School
{
public int GradeID { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
public ICollection<Student> Student { get; set; }
}
Referencing the foreign key declaration sample in the same website, the Student class needs to be further modified as shown below in order for the (Description) attribute to work:
public class Student
{
[Description("Id of Student")]
[Key]
public int Id { get; set; }
[Description("Name of Student")]
public string Name { get; set; }
[Description("Some Description")]
public int SchoolId {get; set;}
public School School { get; set; }
}
I am still looking for a shorter way to get the column description in so please do reply if you think your solution is more elegant than mine.. :)

Why do we need to declare a property in order to put Foreign Key attribute with the same name? [duplicate]

This question already has answers here:
What are Independent Associations and Foreign Key Associations? [duplicate]
(2 answers)
Closed 4 years ago.
Why do we need to create a primitive type i.e. User_ID if I have to declare a foregin key name over reference navigational proeperty?
e.g.
public class Sims
{
public int ID { get; set; }
public int Users_ID { get; set; }
[ForeignKey("Users_ID")]
public Users Users { get; set; }
}
Why do I need public int Users_ID { get; set; } in order to put only a foreign key attribute over the Users?
Because that's telling EF that the foreign key field to use to store the id of the linked "Users" record is named "Users_ID".
If you don't explicitly need to have that field available in your Sims Entity, then you can just leave it out altogether & you don't need to have the ForeignKey Attribute at all & EF will manage that for you behind the scenes.
Alternatively, you could name the foreign key field "UsersId" and it will assume that's the foreign key due to convention.
So any of these should be completely fine:
//no explicit foreign key
public class Sims
{
public int ID { get; set; }
public Users Users { get; set; }
}
//explicit foreign key but EF works it out via convention
public class Sims
{
public int ID { get; set; }
public int UsersId { get; set; }
public Users Users { get; set; }
}
//explicitly named foreign key which is named differently from
//convention so needs to be pointed at. note nameof() operator
//which will give a compiler error should you rename it, so is
//better than a magic string
public class Sims
{
public int ID { get; set; }
[ForeignKey(nameof(Users))]
public int MyUsersFkField { get; set; }
public Users Users { get; set; }
}
You can also add the attribute to the Users property and point it at the Id field.
An important note is that if you use a non-conventionally named FK property and don't specify the foreign key at all, then EF will create a FK UsersId Field in the underlying database and use that (but this won't be exposed in your model)
The [ForeignKey] attribute overrides the default convention for a foreign key. It allows us to specify the foreign key property in the dependent entity whose name does not match with the primary key property of the principal entity.
In your case this will create the foreign key column named Users_ID in the Sims table, preventing the generation of a ID column in the database.

One-to-one relationship in Entity Framework with ASP.NET Identity tables [duplicate]

I am having an issue getting a reference to the employee object from the PayGroup object using Entity Framework 6.1. I have a foreign key in the database on PayGroup.SupervisorId -> Employee.EmployeeId. Note that this is a zero or one-to-one relationship (a pay group can only have one supervisor and an employee can only be the supervisor of one pay group).
According to this post on GitHub, it is not possible to have a foreign key on a table with a different primary key. I've added the foreign key to the database manually but I can't figure out how to set up the fluent api mapping to be able to get the employee object from pay group.
Pay Group Table
Employee Table
Note: There is a foreign key from PayGroup.SupervisorId - Employee.EmployeeId in the database.
Below are the DTO's (I don't currently have any working relationship mapping between these classes):
public class PayGroup
{
public int Id { get; set; }
public string SupervisorId { get; set; }
public virtual Employee Supervisor { get; set; }
}
public class Employee
{
public string EmployeeId { get; set; }
public string FullName { get; set; }
}
one-to-one relationship with explicit FK property (like your PayGroup.SupervisorId) is not supported.
So remove that property from the model:
public class PayGroup
{
public int Id { get; set; }
public virtual Employee Supervisor { get; set; }
}
and use the following fluent mapping:
modelBuilder.Entity<PayGroup>()
.HasRequired(e => e.Supervisor)
.WithOptional()
.Map(m => m.MapKey("SupervisorId"));
The WithOptional() call specifies two things. First that there is no inverse navigation property in Employee class, and second that the FK is optional (Allow Nulls = true in the table).
If you decide to add inverse navigation property
public class Employee
{
public string EmployeeId { get; set; }
public string FullName { get; set; }
public virtual PayGroup PayGroup { get; set; } // <=
}
change it to WithOptional(e => e.PayGroup).
If you want to make it required (Allow Nulls = false in the table), then use the corresponding WithRequiredDependent overload (Dependent here means that the Employee will be the principal and PayGroup will be the dependent).

Modeling to use same FK name of a unchanged database

I am using EF6 but...
I can not change the database.
So, if I'm not wrong, I need to create a model that suits the database.
I have to models in relationship one to many:
[Table("ReceCli")]
public class ReceCli
{
[Key]
public int Indice { get; set; }
[Required, StringLength(12)]
[Display(Name = "Nº Documento")]
public string NDOC { get; set; }
[Display(Name = "Banco do boleto")]
[Column("CodBancoBoleto")]
public int CodBancoBoleto { get; set; }
public Banco Banco { get; set; }
}
and
[Table("Bancos")]
public class Banco
{
[Key]
public int CodBanco { get; set; }
[Column("Banco")]
[Required, StringLength(50)]
[Display(Name = "Banco")]
public string Nome { get; set; }
}
In the database this relations are expressing like:
ALTER TABLE [dbo].[ReceCli] WITH NOCHECK ADD CONSTRAINT [ReceCli_CodBancoBoleto] FOREIGN KEY([CodBancoBoleto])
REFERENCES [dbo].[Bancos] ([CodBanco])
GO
ALTER TABLE [dbo].[ReceCli] CHECK CONSTRAINT [ReceCli_CodBancoBoleto]
When executing return an error:
Invalid column name 'Banco_CodBanco'.
I can not change the database.
How can I change the model to EF use ReceCli_CodBancoBoleto name of column instead of Banco_CodBanco ?
You can do model an existing db by hand but you can also tell EF to generate the model from an existing database.
As for your example, a couple of things:
The relationship you have modeled is not one to many but one to one.
Public Banco Banco {get; set;}
Change To:
Public ICollection<Banco> Bancos {get;set;}
There are several ways you can model relationships with EF. Here's a sample of Modeling 1 to many relationships in EF.
The Column attribute is used to match to names in the DB. Make sure your EF CF properties that don't match the database have a Column Attribute. For Your RecCli it should look something like:
[Column("CodBanco")]
public int CodBancoBoleto { get; set; }
or
public int CodBanco { get; set; }
However, you are mapping a 1 to many relationship so having the CodBancoBoleto is not needed. Just use the navigation property of Public ICollection<Banco> Bancos {get;set;}. This should suffice except you might have to put a ForeignKey attribute for it telling it to use CodBanco as the key for the navigation.
[ForeignKey("CodBanco")]
Public ICollection<Banco> Bancos {get;set;}
You might have to do this for all your keys as the default code first convention for keys end with Id. I say might as your Banco Class's key is named properly CodBanco and marked with the Key. So you might be fine.
A final note is that you appear to be trying to use the constraints name for the mapping. You don't use the constraint name, rather the actual column names, aka the references part of the constraint.

ASP.Net MVC Model Class key identifier

I am new to ASP.Net MVC and I am trying to get a better understanding of ASP.Net MVC. I did a couple tutorials and made a few models in those tutorials. One question that kept popping up in my head was: When would I use public int Id { get; set; } and when would I be using public int MyClassNameId { get; set; } instead as identifier for my model class? Would it matter if I would use a custom property name instead of the default Id name for my identifier for a model class?
For example, why would I use public int ArtistId { get; set; } over public int Id { get; set; }?:
public class Artist
{
public int ArtistId { get; set; }
public string Name { get; set; }
}
Is it so that it matches a property name in another class in which it will be used as Foreign Key?
Entity Framework CodeFirst recognize the key, by default, by name. Valid names are Id or <YourClassName>Id.
Your property should be named Id or AccountTypesId
Another way is to use the ModelBuilder to specify the key.
Sample
public class MyDbContext : DbContext
{
public DbSet<Artists> Artists{ get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Artists>.HasKey(x => x.ArtistId);
base.OnModelCreating(modelBuilder);
}
}
More about it you can find here
If you use custom property names then compiler will not understand it's meaning that it is an id and must be used as primary key in database table.
when you name it id compiler understands it's meaning .
This depends on whether or not using Entity Framework to set up your databases. If you are Entity Framework looks for specific property names to identity as Primary Keys.
For example, let's say you have a model called Book.
public class Book
{
public string Title {get; set;}
//all other properties here
}
When Entity Framework tries to set up your database, it looks for a property that it can identify as a primary key corresponding to the specific model. In this case EF would look for "BookID" as a primary key. So if you wished to have an accessible primary key property you would set it up like this.
public class Book
{
public int BookID {get;set;}
public string Title {get; set;}
//all other properties here
}
If you wished to set up a primary key that was not called "BookID", you could use a data annotation:
public class Book
{
[Key]
public int BookIdentifier{get;set;}
public string Title {get; set;}
//all other properties here
}

Categories