How do I specify a foreign key that references a specific property instead of the primary key?
For example the Stock class has a uuid property. And I want to create a foreign key in the Valuation class that references it using this property.
In the following example the line [ForeignKey(typeof(Stock))] references the ID property of the Stock class, but I need it to reference the UUID property.
How would I do that?
public class Stock
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string UUID { get; set; }
[MaxLength(8)]
public string Symbol { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)] // One to many relationship with Valuation
public List<Valuation> Valuations { get; set; }
}
public class Valuation
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[ForeignKey(typeof(Stock))] // Specify the foreign key
public string StockUUID { get; set; }
public DateTime Time { get; set; }
public decimal Price { get; set; }
[ManyToOne] // Many to one relationship with Stock
public Stock Stock { get; set; }
}
A ForeignKey always references the PrimaryKey of another class. In this case, your PrimaryKey is an integer, but you are trying to reference another property of type string. This is not supported, so you either reference the primary key, or you make the UUID property primary key.
public class Stock
{
[PrimaryKey]
public string UUID { get; set; }
[MaxLength(8)]
public string Symbol { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)] // One to many relationship with Valuation
public List<Valuation> Valuations { get; set; }
}
Related
I am using Entity Framework Core 5 and I am testing the table relationships.
Using these 2 classes as entities
public class Absenta
{
public int id { get; set; }
public DateTime dataAbsemta { get; set; }
public bool Motivata { get; set; }
public string UserID { get; set; }
public ApplicationUser User { get; set; }
public int TrainingID { get; set; }
public Training Training { get; set; }
}
public class Training
{
public int TrainingID { get; set; }
[DisplayName("Training")]
public string Name { get; set; }
public string FilePath { get; set; }
[DisplayName("Clasa")]
public string NumeClasa { get; set; }
[DisplayName("Sala")]
public string NumeSala { get; set; }
[DisplayName("Data incepere : ")]
[DataType(DataType.Date)]
public DateTime DataInceput { get; set; }
[DisplayName("Data sfarsit : ")]
[DataType(DataType.Date)]
public DateTime DataSfarsit { get; set; }
public ICollection<Absenta> absente { get; set; }
}
This is the generated query :
CONSTRAINT [PK_Absente]
PRIMARY KEY CLUSTERED ([id] ASC),
CONSTRAINT [FK_Absente_AspNetUsers_UserID]
FOREIGN KEY ([UserID]) REFERENCES [dbo].[AspNetUsers] ([Id]),
CONSTRAINT [FK_Absente_Traininguri_TrainingID]
FOREIGN KEY ([TrainingID]) REFERENCES [dbo].[Traininguri] ([TrainingID])
ON DELETE CASCADE
Migration works perfectly, creating the tables and foreign keys, but for the UserID foreign key it does not apply ON DELETE CASCADE behavior by default.
Is there a way I can set it as default from the class? I am trying to avoid setting it manually for every table.
Figured out the solution.
All you have to do is use the [Required] data annotation :
[Required]
public string UserID { get; set; }
public ApplicationUser User { get; set; }
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.
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.
Hello I have table in the database which consist only of foreign keys. This table structure is like below:
Code is generated by VS in Database first :
public partial class DeviceUsage
{
public int StorageId { get; set; }
public int UserId { get; set; }
public int DeviceInstanceId { get; set; }
public virtual DeviceInstance DeviceInstance { get; set; }
public virtual Storage Storage { get; set; }
public virtual User User { get; set; }
}
As You can see all keys are foreign from 3 other tables.
I'm aware that EntityFramework don't like tables without primary keys.
But even that I need to ask you if there is any possibility to make it work or I am forced to add new column Id to my table?
You have to set your primary key.You don't need to add extra Id column, you can set one of those properties as primary key with [Key] attribute. For example:
[Key]
public int StorageId { get; set; }
Looking at this article about Entity Framework and Code First Data Annotations it seems that your answer is
public partial class DeviceUsage
{
[Key]
[Column(Order=1)]
public int StorageId { get; set; }
[Key]
[Column(Order=2)]
public int UserId { get; set; }
[Key]
[Column(Order=3)]
public int DeviceInstanceId { get; set; }
public virtual DeviceInstance DeviceInstance { get; set; }
public virtual Storage Storage { get; set; }
public virtual User User { get; set; }
}
I think that inserting is not possible without primary key.
Just add
[Require]
public int DeviceUsageId {get;set}
and let it be, you dont have to use this PK
I have the following model:
public class Task
{
public int Id { get; set; }
public int UseraccountId { get; set; }
public virtual Useraccount Useraccount { get; set; }
}
The useraccountId is my foreign key showing to my useraccount entity/model.
The entity framework can map this foreign key to the virtual property because it removes the "Id", so "useraccountId" becomes "useraccount" -> mapping to "Useraccount".
What if I want to rename the foreign key "useraccountId" to "creatorId"? How can I now tell the Entity framework to map this foreign key to the virtual Useraccount property?
Use the ForeignKey attribute.
public class Task
{
public int Id { get; set; }
public int CreatorId { get; set; }
[ForeignKey("CreatorId")]
public virtual Useraccount Useraccount { get; set; }
}