Setting up foreign key in ASP.NET MVC 4 - c#

I have 2 models and want to create a foreign key relationship. Basically each note should be assigned to a user.
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
}
[Table("UserNotes")]
public class UserNotes
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int NoteId { get; set; }
[ForeignKey("UserProfile")]
public virtual int UserId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public string Added { get; set; }
public DateTime? Edited { get; set; }
}
When I attempt to add new user note I get:
The ForeignKeyAttribute on property 'UserId' on type 'note.DO.Models.UserNotes' is not valid. The navigation property 'UserProfile' was not found on the dependent type 'note.DO.Models.UserNotes'. The Name value should be a valid navigation property name.
I have tried a lot of combinations including those found in similar questions but none of them worked.

Try this :
public virtual int UserId { get; set; }
[ForeignKey("UserId")]
public virtual UserProfile User { get; set; }
This way, you pair foreign key property with navigation property.
Edit : you can also write it like this :
[ForeignKey("UserProfile")]
public virtual int UserId { get; set; }
public virtual UserProfile UserProfile { get; set; }
Those two snippets gives the same result. Your error message says that "UserProfile" property is missing, you just have to add it.

Related

Create navigation property without foreign key

I have two classes like so:
[Table("GameLevels", Schema = "ref")]
public class GameLevel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public double PointsMin { get; set; }
public double PointsMax { get; set; }
}
[Table("GameProfiles", Schema = "usr")]
public class UserGameProfile
{
[Key]
[ForeignKey("ApplicationUser")]
public string Id { get; set; }
public int GamesPlayed { get; set; }
public double Points { get; set; }
public int WinCount { get; set; }
public int LossCount { get; set; }
public int DrawCount { get; set; }
public int ForfeitCount { get; set; }
public int GameLevelId { get; set; }
public virtual GameLevel Level { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
}
Entity framework builds this so that UserGameProfile has a foreign key pointing to GameLevel. I guess this is because of the GameLevelId property.
Is there any way I can get this to generate the tables and navigation property without the foreign key?
I tried:
modelBuilder.Entity<UserGameProfile>().HasOptional<GameLevel>(x => x.Level).WithMany();
But then database fails to build. With this error:
One or more validation errors were detected during model generation:
Project.Domain.Data.UserGameProfile_Level: : Multiplicity
conflicts with the referential constraint in Role
'UserGameProfile_Level_Target' in relationship
'UserGameProfile_Level'. Because all of the properties in the
Dependent Role are non-nullable, multiplicity of the Principal Role
must be '1'.
Basically what I want is a zero-or-one to zero-or-many relationship.
How do I keep levels independent but have the ability to add a level to a profile?
You can't drop the foreign key completely, otherwise, how do you expect the two entities (i.e, tables) to be linked? What you can do instead is have a nullable FK, which will effectively make the relationship zero-or-one to many.
In your GameLevel class, add a navigation property as a collection of UserGameProfile:
public class GameLevel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public double PointsMin { get; set; }
public double PointsMax { get; set; }
public virtual ICollection<UserGameProfile> UserGameProfiles { get; set; }
}
Then in the UserGameProfile class, make the property GameLevelId nullable:
public class UserGameProfile
{
// ...
// ...
public int? GameLevelId { get; set; }
[ForeignKey("GameLevelId")]
public virtual GameLevel GameLevel { get; set; }
}
This should work without even having to use Fluent API.

Using Entity Framework, how can I add a foreign key on two models to reference each other

I have a ASP.NET MVC 5/C# project. In my project I have two models, Rule and MenuItem. MenuItem has a foreign key that references Rule. And Rule has a foreign key that references MenuItem.
Couple things worth mentioning, my model have a Prefix in the model name. Also, I am using database first approach.
I want to be able to get the MenuItem with the required rule using .Include(...) and also I want to be able to get the Rules with the MenuItem
Here are my models
[Table("Rules")]
public class PrefixRule
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
[ForeignKey("Item")]
public int ModuleId { get; set; }
public string Name { get; set; }
public virtual PrefixMenuItem Item { get; set; }
}
[Table("MenuItems")]
public class PrefixMenuItem
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
[ForeignKey("RequiredRule")]
public int? RequiredRuleId { get; set; }
public string Name { get; set; }
public virtual PrefixRule RequiredRule { get; set; }
}
However, when I try to pull the menu-items including the required-rule, I get the following error
One or more validation errors were detected during model
generation:MenuItem_RequiredRule_Target: : Multiplicity is not valid
in Role 'MenuItem_RequiredRule_Target' in relationship
'MenuItem_RequiredRule'. Because the Dependent Role properties are not
the key properties, the upper bound of the multiplicity of the
Dependent Role must be '*'.
I believe this error due to the circular references between my models. However, I need to be able to access both properties either way.
How can I fix this problem?
If you are going this route then you have to make public string Id in the both the Primary and Foreign Key in your Rules table by decorating it with [Key, ForeignKey("PrefixMenuItem")]
See this article for a full example: http://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx
Updated Example:
public partial class Rule
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key, ForeignKey("Item")]
public string Id { get; set; }
[ForeignKey("Module")]
public int ModuleId { get; set; }
public string Name { get; set; }
public virtual MenuItem Item { get; set; }
public virtual Module Module { get; set; }
}
public partial class MenuItem
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
public string Name { get; set; }
public virtual Rule RequiredRule { get; set; }
}
public partial class Module
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ModuleId { get; set; }
public string Name { get; set; }
}
Entity Framework should be smart enough to figure out that this is 1 to 0/1 relationship. Not tested but this should work?
public partial class Rule
{
[Key, ForeignKey("Item")]
public string ModuleId { get; set; }
public string Name { get; set; }
public virtual MenuItem Item { get; set; }
}
public partial class MenuItem
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
public string Name { get; set; }
public virtual Rule RequiredRule { get; set; }
}

Foreign keys with Code First in a Web API

Very simple question but it looks like I'm trying to implement a simple one-to-many relationship between two models.
So far, what I have is this :
A product class :
public class Products
{
public long Id { get; set; }
public long Code { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
public Boolean Reviewed { get; set; }
[ForeignKey("BundleId")]
public int BundleId { get; set; }
public virtual Bundles Bundle { get; set; }
}
And the Defects class looks like this:
public class Defects
{
public long Id { get; set; }
public String Description { get; set; }
public String Picture { get; set; }
public DateTime DateCreated { get; set; }
[ForeignKey("ProductId")]
public int ProductId { get; set; }
public Products Product { get; set; }
[ForeignKey("UserId")]
public int UserId { get; set; }
public virtual Users User { get; set; }
}
I thought that I did not need to add an ICollection of Defects to the Products class because it's a "simple" one-to-many relationship and this code would be enought to be able to get the ID of a Product in the Defects class (I don't need more).
But, of course I get an exception :
The property 'ProductId' 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
How may I solve that issue ?
I might be doing someting wrong with my two foreign keys but since I declared the name of the foreign keys, I assumed it would have been enought.
Thanks for your attention.
This is what your relationship can be distilled to.
Please note that ForeignKey annotation is applied to navigation property with the name of the key property.
If you build one-to-many relationship - then ICollection is absolutely necessary. Otherwise where's the "many"
public class Products
{
public int Id { get; set; }
public virtual List<Defects> Bundle { get; set; }
}
public class Defects
{
public long Id { get; set; }
public int ProductId { get; set; }
[ForeignKey("ProductId")]
public Products Product { get; set; }
}
FK can also be applied to the key property. But in that case you have to put the name of the instance of related class there
public class Defects
{
public long Id { get; set; }
[ForeignKey("Product")]
public int ProductId { get; set; }
public Products Product { get; set; }
}

Code First cascade issue

this is the error I'm getting:
"Introducing FOREIGN KEY constraint FK_dbo.RolePermissions_dbo.Permissions_Permission_ID on table RolePermissions may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint or index. See previous errors."
and here are my classes:
public class Permission
{
[Key]
public int ID { get; set; }
[Required]
public int PermissionObjectId { get; set; }
public PermissionObject PermissionObject { get; set; }
[Required]
public int CategoryId { get; set; }
public Category Category { get; set; }
[Required]
public int ReadWriteId { get; set; }
public ReadWrite ReadWrite { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
public class Role
{
[Key]
public int ID { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int CategoryId { get; set; }
public Category Category { get; set; }
public virtual ICollection<Permission> Permissions { get; set; }
}
public class Category
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public int OrderID { get; set; }
public override string ToString()
{
return ID.ToString();
}
}
what do I do wrong?
use fluent api for set CascadeOndelete = fasle .
See This Link May Be Help you : Link
It looks like EF is trying to create a relationship of some sort between Roles and Permissions (many-to-many?), but you also have one-to-many relationships for category-role and category-permission which also have cascade delete enabled.
For foreign key relationships when using non-nullable keys or [Required], (e.g. CategoryId in both Role and Permission), cascade delete is enabled by default.

Code First EF relationship duplicate

I have a working model, but have noticed that the relationship has been created twice in the database. Originally, it created two columns in the table, but with the addition of a specified foreign key attribute it has now just the one.
I have an Account class, which has many employers who can use the account. (one to many) Here are the classes:
public class Account
{
public int AccountId { get; set; }
[Required(ErrorMessage = Constants.ValidationMessages.FieldRequired)]
public string Name { get; set; }
public int? PrimaryUserId { get; set; }
[ForeignKey("PrimaryUserId")]
public Employer PrimaryUser { get; set; }
[ForeignKey("EmpAccountId")]
public ICollection<Employer> Employers { get; set; }
}
here is the inherited Employer class
public class Employer : User
{
public Employer()
{
DepartmentsToPost = new Collection<Department>();
Contacts = new Collection<Contact>();
}
[Display(Name = "Workplaces to advertise jobs")]
public virtual ICollection<Department> DepartmentsToPost { get; set; }
public int EmpAccountId { get; set; }
[ForeignKey("EmpAccountId")]
public virtual Account Account { get; set; }
public override string UserType
{
get { return "Employer"; }
}
}
User Table:
UserId
Username
FirstName
Surname
EmpAccountId
Discriminator
Account Table
AccountId
Name
PrimaryUserId
There is one link back to the User table - this is for the PrimaryUser field, and this is correct. There are two other relationships: Account -> Employers. EF has named them Account_Employers and Employer_Account. These are duplicates.
How can I prevent this occuring?
The Employers collection should be decorated with InversePropertyAttribute to point to the navigational property on the other side.
public class Account
{
public int AccountId { get; set; }
[Required(ErrorMessage = Constants.ValidationMessages.FieldRequired)]
public string Name { get; set; }
public int? PrimaryUserId { get; set; }
[ForeignKey("PrimaryUserId")]
public Employer PrimaryUser { get; set; }
[InverseProperty("Account")]
public ICollection<Employer> Employers { get; set; }
}

Categories