How to allow null values on Foreign keys using EF?
public class User
{
public User()
{
}
public int idUser; { get; set; }
[Required]
public string UserName { get; set; }
public virtual Computer Computer{ get; set; }
}
public class Computer
{
public Computer()
{
}
[Key, ForeignKey("User")]
public int idUser{ get; set; }
public string ComputerName {get;set;}
public virtual User User { get; set; }
}
Running this I'm getting not null on the foreign key.
I assume you are using code first. If that is the case then you override OnModelCreating in the context class and add the following line
modelBuilder.Entity<Computer>().HasOptional(c => c.User);
================
Ok, you changed your post after I posted my answer.
You can use
int? idUser
for your user ID, this will let EF know that you are allowing a nullable relationship.
You can make use of ? keyword. It makes your type a Nullable type.
For example int doesn't allow nulls normally.
But after appending a ? to int you can assign null to it.
int? iCanHaveNull = null;
Late answer, I know, but it is an important topic.
You are trying to setup navigation properties. If you declare it correctly (as shown in the example below), then:
The property Computer contained in the User class is referring to ("points to") a computer by using foreign key idComputer.
Likewise, the property User contained in the Computer class is referring to ("points to") a User by using a foreign key idUser.
EF introduces this foreign key automatically if
You decorate the primary key Id of each entity with a [Key] attribute. A primary key must not be nullable per definition.
You declare the navigation property correctly (e.g. public virtual Computer Computer { get; set; } - which creates by convention a foreign key explicitly named via the ForeignKey attribute as idComputer). This foreign key is per definition nullable, unless you add the [Required] attribute to the navigation property. For example, if you want to make the foreign key in the User entity referring to ("pointing to") Computer mandatory, the declaration [Key, ForeignKey("idComputer"), Required] would do that.
Special Note for EF Core: You have to create a migration in the package manager console via
dotnet ef migrations add CreateMyDatabase
And then apply it to the database via:
dotnet ef database update --context myDbContext --project myProject
(replace CreateMyDatabase, myDbContext and myProjects by names of your choice - but myDbContext and myProjects must exist in your solution).
This is using toolset 5.0.3, you might need to upgrade it via
dotnet tool update --global dotnet-ef --version 5.0.3
Example:
// using System.ComponentModel.DataAnnotations;
// using System.ComponentModel.DataAnnotations.Schema;
public class User
{
public User() {}
[Key]
public int Id { get; set; }
[Required]
public string UserName { get; set; }
[Key, ForeignKey("idComputer")]
public virtual Computer Computer { get; set; }
}
public class Computer
{
public Computer() {}
[Key]
public int Id { get; set; }
[Required]
public string ComputerName { get; set; }
[Key, ForeignKey("idUser")]
public virtual User User { get; set; }
}
It might look weird to have something like public virtual User User { get; set} but this is a convention telling EF it is a navigation property, and all that is created in the database table is a foreign key (here: idUser in table Computer).
You can find a good description with some additional information here:
https://www.tektutorialshub.com/entity-framework-core/ef-core-relationships-navigation-properties/
How to allow null values on Foreign keys using EF?
Your database table should allow nulls as well if you are planning to take the following approach:
change
public int idUser; { get; set; }
[Required]
public string UserName { get; set; }
public virtual Computer Computer { get; set; }
To
public int idUser; { get; set; }
[Required]
public string UserName { get; set; }
public virtual Computer Computer{ get; set; }
And change
[Key, ForeignKey("User")]
public int idUser { get; set; }
public string ComputerName { get; set; }
public virtual User User { get; set; }
To
[Key, ForeignKey("User")]
public int? idUser { get; set; }
public string ComputerName { get; set; }
public virtual User User { get; set; }
The ? character, makes a field nullable. Make sure it is nullable in your database as well.
Related
I am getting the above error when trying to add migration after add a foreign key using Entity Framework core.
I am adding FK in
public class ApplicantDetail
{
[Key]
public int Id { get; set; }
[ForeignKey("GrantProgramFK")]
public GrantProgram GrantProgramId { get; set; }
--------
}
This FK ties to class
public class GrantProgram
{
[Key]
public int Id { get; set; }
-----
}
Any help is appreciated. I tried to remove the entity and run migration again, but failed.
Full error:
The property 'GrantProgramId' cannot be removed from entity type 'EFDataAccessLibrary.Models.ApplicantDetail' because it is being used in the foreign key {'GrantProgramId'} on 'EFDataAccessLibrary.Models.ApplicantDetail'. All containing foreign keys must be removed or redefined before the property can be removed
I found a page,
click here, but what does that mean? how to resolve it.
I had the same problem. I solved it by removing the "id" in the foreign key:
public class ApplicantDetail
{
[Key]
public int Id { get; set; }
[ForeignKey("GrantProgramFK")]
public GrantProgram GrantProgram { get; set; }
--------
}
I still don't know why. If anybody can explain, or give a solution to leave "id" in it, don't hesitate to tell us.
Since entityframework auomatically uses any identifoer ending with 'ID or Id or id', ensure no other property name ends with 'ID or Id or id'
I'd recommend to delete previous migrations file in the solution, this works for me
I was getting the same error, in my case all I did was undo the changes in AppDbContextModelSnapshot file (you can also delete the file) which is created in the migrations folder.
Turns out I had made an error before performing the migration, after which a model snapshot of my AppDbContext was created. After fixing the error, I tried the migration again, but the AppDbContextModelSnapshot was already modified, EF was not allowing to override with the same key of the same model (in this case GrantProgramFK from GrantProgram model) . So just undo the changes in your AppDbContextModelSnapshot file and perform the migration again.
I was able to solve the issue by going into ModelSnapShot.cs in the Migrations folder and making sure to delete all references to the property causing issues. You'll be looking for any references to 'GrantProgramIdId'.
Make sure to delete any lines where the snapshot creates foreign keys.
Change any instance where the property name includes the incorrect property name above.
Make sure you check the entire file. There should be two separate places where issues exist.
Also, delete any migrations where this property was included, then create a new migration and should be good to go.
I had a same issue. You have to delete(remove migration did not work either so I deleted manually) the migration and snapshot and change this field:
public GrantProgram GrantProgramId { get; set; }
to
public int GrantProgramId { get; set; }
You have to fix your classes before migration:
public class ApplicantDetail
{
[Key]
public int Id { get; set; }
public int? GrantProgramId { get; set; }
[ForeignKey("GrantProgramId")]
[InverseProperty("ApplicantDetails")]
public GrantProgram GrantProgram{ get; set; }
--------
}
public class GrantProgram
{
[Key]
public int Id { get; set; }
[InverseProperty(nameof(ApplicantDetail.GrantProram))]
public virtual ICollection<ApplicantDetail> ApplicantDetails{ get; set; }
-----
}
Add data annotations and everything will work smooth, see
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class Address
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Display(Name ="Address Id")]
public int AddressId { get; set; }
public string Street { get; set; } = string.Empty;
public string City { get; set; } = string.Empty;
public int? StateId { get; set; }
public string Country { get; set; } = string.Empty;
public string ZipCode { get; set; } = string.Empty;
}
public class State
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Display(Name ="State Id")]
public int StateId { get; set; }
public string StateName { get; set; } = string.Empty;
}
I'm using Entity Framework 6.1.1 and I have a Users table and a User_Documents table (1:many). I already had a navigation property from User_Documents to User were things were working fine.
public partial class User_Document
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long User_Document_ID { get; set; }
public long User_ID { get; set; }
[ForeignKey("User_ID")]
public virtual User User { get; set; }
}
I added a navigation property from Users to User_Documents
public partial class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long User_ID { get; set; }
[StringLength(50)]
public string Username { get; set; }
public virtual List<User_Document> Documents { get; set; }
}
and now I'm getting an error when I try to run the application:
System.Data.Entity.ModelConfiguration.ModelValidationException: One or
more validation errors were detected during model generation:
User_Documents: Name: Each member name in an EntityContainer must be
unique. A member with name 'User_Documents' is already defined.
Of course there is a table called User_Documents but no other property with that name. I'm not sure what's it getting confused by. Maybe it's taking the table name "User" and the property name "Documents" and trying to create something called "User_Documents" out of it? If I rename it to from Documents
to Some_Documents like this
public virtual List<User_Document> Some_Documents { get; set; }
then I get a different error stating
System.InvalidOperationException: The model backing the
'PipeTrackerContext' context has changed since the database was
created. Consider using Code First Migrations to update the database
So I run Add-Migration and I get this:
public override void Up()
{
AddColumn("dbo.User_Documents", "User_User_ID", c => c.Long());
CreateIndex("dbo.User_Documents", "User_User_ID");
AddForeignKey("dbo.User_Documents", "User_User_ID", "dbo.Users", "User_ID");
}
Why is it trying to add a new column called User_User_ID? Why can't I just add the Document navigation property like I want?
use InverseProperty Like this :
public partial class User_Document
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long User_Document_ID { get; set; }
public long User_ID { get; set; }
[ForeignKey("User_ID")]
[InverseProperty("Documents")]
public virtual User User { get; set; }
}
And :
public partial class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long User_ID { get; set; }
[StringLength(50)]
public string Username { get; set; }
[InverseProperty("User")]
public virtual List<User_Document> Documents { get; set; }
}
Why is it trying to add a new column called User_User_ID? Why can't I
just add the Document navigation property like I want?
By convention, it will create the foreign key as tablename_columnName which is User_User_ID. This happens when you remove the [ForeignKey("User_ID")] attribute OR don't have foreign key property.
If you change the property name Documents to something else (likeUserDocuments) you wont face this conflict of names.
I'm pretty new to Entity Framework and the code first approach and I'm stuck. Sorry if it's a dumb question.
I found some questions around here that look the same, but I get an other error then the ones other people get and I would love to solve it without the need to add other parameters if possible.
So Basically, I have my ApplicationUser(load in from Identity) that looks like this:
public class ApplicationUser : IdentityUser
{
public virtual Province Provincie { get; set; }
[ForeignKey("From")]
public virtual ICollection<Message> SentMessages { get; set; }
[ForeignKey("To")]
public virtual ICollection<Message> ReceivedMessages { get; set; }
}
And I have a Message Class that looks like:
public class Message
{
[Key]
public int ID { get; set; }
public virtual ApplicationUser From { get; set; }
public virtual ApplicationUser To { get; set; }
public String MessageContent { get; set; }
public DateTime Date { get; set; }
}
Now, when I try to add a migration i get the following error:
The ForeignKeyAttribute on property 'ReceivedMessages' on type 'EF_CF_Basics.Models.ApplicationUser' is not valid. The foreign key name 'To' was not found on the dependent type 'EF_CF_Basics.Models.Message'. The Name value should be a comma separated list of foreign key property names.
So actually, visual studio tells me it can't find the To in Message, but it is really there.
You probably want to use [InverseProperty("From")] instead of [ForeignKey("From")] and [InverseProperty("To")] instead of [ForeignKey("To")]. Foreign key properties must be scalars (int, string, Guid, etc.) but your From and To properties are actually entities, i.e. they are navigation properties.
I have created Entity Data Model in Visual Studio. Now I have file with SQL queries and C# classes generated from Model.
Question:
Classes are generated without annotations or code behind (Fluent API). Is it OK? I tried to run my application but exception was thrown:
Unable to determine the principal end of an association between the types 'Runnection.Models.Address' and 'Runnection.Models.User'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
I read that I can not use Fluent API with "Model First". So what can I do?
Code:
User
public partial class User
{
public User()
{
this.Events = new HashSet<Event>();
this.CreatedEvents = new HashSet<Event>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Photo { get; set; }
public int EventId { get; set; }
public string Nickname { get; set; }
public OwnerType OwnerType { get; set; }
public NetworkPlaceType PlaceType { get; set; }
public virtual ICollection<Event> Events { get; set; }
public virtual Address Address { get; set; }
public virtual ICollection<Event> CreatedEvents { get; set; }
public virtual Owner Owner { get; set; }
}
Address
public partial class Address
{
public int Id { get; set; }
public string Street { get; set; }
public string StreetNumber { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
public virtual User User { get; set; }
}
Context
//Model First does not use this method
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Address>().HasRequired(address => address.User)
.WithRequiredDependent();
modelBuilder.Entity<User>().HasRequired(user => user.Address)
.WithRequiredPrincipal();
base.OnModelCreating(modelBuilder);
}
You have to specify the principal in a one-to-one relationship.
public partial class Address
{
[Key, ForeignKey("User")]
public int Id { get; set; }
public string Street { get; set; }
public string StreetNumber { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
public virtual User User { get; set; }
}
By specifying a FK constraint, EF knows the User must exists first (the principal) and the Address follows.
Further reading at MSDN.
Also, see this SO answer.
Updated from comments
In the designer, select the association (line between Users & Address). On the properties window, hit the button with the [...] on Referential Constraint (or double click the line). Set the Principal as User.
Error:
Had same error of "Unable to determine the principal end of an association between the types 'Providence.Common.Data.Batch' and 'Providence.Common.Data.Batch'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.".
HOWEVER, note that this is the SAME table.
Cause: My database was MS SQL Server. Unfortunately when MS SQL Server's Management Studio adds foreign keys, it adds the default foreign key as Batch ID column of Batch table linking back to itself. You as developer are suppose to pick another table and id to truly foreign key to, but if you fail to it will still allow entry of the self referencing FK.
Solution:
Solution was to delete the default FK.
Cause 2: Another situation is that the current table may be fixed but the old historical image of the table when the EF's edmx was done had the default FK.
Solution 2: is to delete the table from the Model Browser's Entity Types list and click "yes" and then "Update Model from the Database" again.
I'm slightly confused on how to properly setup my model. Below you'll see my POCOs and I'm wondering how I can auto increment the ID's and if it's necessary to set the data annotation [Key]. Is there a naming convention of some sort which makes EF recognize the ID/primary key or do I have to use the [Key] data annotation?
Also is it necessary to set a [Key] data annotation in the child entity?
public class User
{
[Key]
public int UserId { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public DateTime Reg { get; set; }
public virtual ICollection<Stats> Stats { get; set; }
}
public class Stats
{
[Key]
public int StatId { get; set; }
public string Age { get; set; }
public string Height { get; set; }
public string Weight { get; set; }
public bool Sex { get; set; }
}
public class BodylogContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Stats> Stats { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<BodylogContext>(null);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
You should look up Entity Framework Code First tutorials for more details.
Specifically, in your case and a few basic rules (disclaimer:) I'm not trying to cover everything just a few basic ones....
You can remove [Key] -
if you use <Entity>Id - or just Id it's made into a PK by default.
Same goes for 'FK-s' and related navigation properties (except that <Property>Id is also mapped by convention),
It's case insensitive.
Identity is by default - for pk types that makes sense - int, long... - not for strings,
If you have more than one pk - then you'd need to 'decorate' it with Key - or in fluent config,
etc...
Note: you can adjust and remove conventions from the fluent configuration.
Also from EF6 you'll be able to define a new ones for your code.
My recommendation: Turn on Migrations and look up the migrations
script code (.cs file) generated file. It always has the clear
description of what are keys, indexes etc. Best way to learn how your
Db is actually created.
I'm just getting with MVC too and I found that this tutorial answered most of the questions you have asked.
By default, the Entity Framework interprets a property that's named ID or classnameID as the primary key. So in your User class, you do not need the [Key] attribute on the UserId property. In your Stats class, the property does not match the name of the class (you have pluralised the name) so here you would need the attribute.
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application