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
Related
I am creating a MVC application and want to generate the database using the Code First approach. I've done this with simple tables, but now that I am introducing Foreign Key relationships, things are getting muddled for me.
I have three classes, each of which will have their own table in the DataBase:
public class Device
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int InternalDeviceID { get; set; }
public int DeviceID { get; set; }
public string DeviceName { get; set; }
public virtual EquipmentDevice EquipmentDevice { get; set; }
}
public class Equipment
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int InternalEquipmentID { get; set; }
public int EquipmentID { get; set; }
public string EquipmentName { get; set; }
public virtual EquipmentDevice EquipmentDevice { get; set; }
}
public class EquipmentDevice
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int InternalEquipmentDeviceID { get; set; }
public virtual ICollection<Equipment> EquipmentID { get; set; }
public virtual ICollection<Device> DeviceID { get; set; }
}
The relationship is that a Equipment may have many Devices, and a Device may belong to many Equipments (a many to many if I'm not mistaken). To organize which Equipments have what Devices associated with them, I am using the EquipmentDevice table, which will just pair their IDs together along with an internal ID for that table.
Based on other examples I have found, I had believed this to be the way in which to code such a situation, where the Many side of a relationship will have an ICollection<> object of the Single side, and the Single side of a relationship will have a virtual object of the Many side (both classes having a ICollection<> of the other for a N:N, or both having a virtual for 1:1)
However, when I create the database, my tables look like this:
Device Table
Equipment Table
EquipmentDevice Table
Am I simply backwards in the way in which I am setting up foreign keys for my tables, or is there another problem I am missing altogether for this type of situation? I couldn't find an exceptionally helpful source of info on this subject. I'm also attaching what the diagram of these tables would look like as well, just to help be more clear.
You're close- the properties on Equipment and Device need to be ICollections. You don't need to define a class for the join table, EF will take care of that for you. Here's what your classes should look like (here's a good reference:)
http://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx
public class Device
{
public Device()
{ this.Equipments = new HashSet<Equipment>();}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int InternalDeviceID { get; set; }
public int DeviceID { get; set; }
public string DeviceName { get; set; }
public virtual ICollection<Equipment> Equipments { get; set; }
}
public class Equipment
{
public Equipment()
{ this.Devices = new HashSet<Device>(); }
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int InternalEquipmentID { get; set; }
public int EquipmentID { get; set; }
public string EquipmentName { get; set; }
public virtual ICollection<Devices> Devices { get; set; }
}
To generate foreign keys, the first thing to do is to create the models.
public class Device
{
[Key]
public int DeviceID { get; set; }
public string DeviceName { get; set; }
public virtual ICollection<Equipment> Equipments { get; set; }
}
public class Equipment
{
[Key]
public int EquipmentID { get; set; }
public string EquipmentName { get; set; }
public virtual ICollection<Device> Devices { get; set; }
}
Then you generate and compile the driver for each of the models.
By generating the first model, creates the "Context".
After loading the project and check if you have access to the drivers created.
Now checks the database. The table has two foreign keys in the new table is automatically created.
I don't like to use the fluent api in an entity framework, instead, I would prefer to use a manual way such as the following:
[Key]
public int id { get; set; }
but, how can I make a foreign key using this manual way above?
You can use [ForeignKey("[Name of column]")] anntribute. For examle:
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public int StandardRefId { get; set; }
[ForeignKey("StandardRefId")]
public Standard Standard { get; set; }
}
public class Standard
{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<Student> Students { get; set; }
}
For more information see for examle EF Code Firs Foreign keys
I have three models, User, Room, and PlayerRoom defined as such:
public class User
{
public int id { get; set; }
public string UserName { get; set; }
//flags user to be deleted when room is no longer available
public bool temporaryUser { get; set; }
[JsonIgnore]
public bool permanent { get; set; }
}
public class Room
{
public int id { get; set; }
public string RoomName { get; set; }
[JsonIgnore]
public int CreatedById { get; set; }
public virtual User CreatedBy { get; set; }
}
public class PlayerRoom
{
public int id { get; set; }
[JsonIgnore]
public int RoomId { get; set; }
public virtual Room Room { get; set; }
[JsonIgnore]
public int UserId { get; set; }
public virtual User User { get; set; }
}
What i'm trying to accomplish is setting up the models so that when a User is deleted or when a Room is deleted, all associated PlayerRoom get deleted.
Currently when I generate the migration and run update-database I get the error:
Introducing FOREIGN KEY constraint 'FK_dbo.Rooms_dbo.Users_CreatedById' on table 'Rooms' 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. See previous errors.
From what research I've done it is because PlayerRoom can be deleted in multiple ways from a cascade however, this is the intended behavior.
How can I get the migration tool to generate a migration that will not throw this error?
Thanks!
I ended up altering my classes to make them a bit more restrictive, which in this case actually works out better. I removed the PlayerRoom object and moved the Room reference onto the user object.
public class User
{
public int id { get; set; }
public string UserName { get; set; }
//flags user to be deleted when room is no longer available
public bool temporaryUser { get; set; }
public bool? isHost { get; set; }
[JsonIgnore]
public int? RoomId { get; set; }
public virtual Room Room { get; set; }
[JsonIgnore]
public bool permanent { get; set; }
}
public class Room
{
public int id { get; set; }
public string RoomName { get; set; }
}
By moving Room to the User instead of on a separate object it restricts users to only be in one Room and gets rid of my cascading delete issue
gets rid of my cascading delete issue
EF using Code First sets up cascading by default to be on. To turn it off from the model one can either strategically place 'WillCascadeOnDelete` off the entity in question:
.WillCascadeOnDelete(false);
or globally
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
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.
I'm having a similar problem to existing questions with teh same title, but its slightly different.
I get the error:
A dependent property in a ReferentialConstraint is mapped to a store-generated column. Column: 'SpecificationID'.
When I try to save to database:
var doc = new Specification();
doc.ProjectComponentID = spec.ProjectComponentID;
doc.Description = spec.Description;
db.Specifications.Add(doc);
db.SaveChanges();
When I created the database I used the seed method to map a 1 to 1 or none relationship:
modelBuilder.Entity<Specification>()
.HasRequired(pc => pc.ProjectComponent)
.WithOptional(s => s.Specification);
My 2 relevant entities are:
public class ProjectComponent
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ProjectComponentID { get; set; }
public int ProjectID { get; set; }
public virtual Project Project { get; set; }
public int ProjectPhaseID { get; set; }
public virtual ProjectPhase Phase { get; set; }
... other properties ...
public Nullable<int> SpecificationID { get; set; }
public virtual Specification Specification { get; set; }
}
public class Specification
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int SpecificationID { get; set; }
public int ProjectComponentID { get; set; }
public virtual ProjectComponent ProjectComponent { get; set; }
public string Description { get; set; }
}
I need to be able to add a specification to a PRojectComponent. providing the specification with the ProjectComponentID but auto generating the SpecificationID
I don't get any error on creating the DB, only when trying to save the Specification.
So I found "A" solution. But I'm not convinced its the "best" solution.
Apparently code-first EF requires the primary keys to be shared in a one to zero or one relationship.
So to solve this issue I have removed the foreign keys on each entity:
public class ProjectComponent
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ProjectComponentID { get; set; }
public int ProjectID { get; set; }
public virtual Project Project { get; set; }
public int ProjectPhaseID { get; set; }
public virtual ProjectPhase Phase { get; set; }
... other properties ...
public virtual Specification Specification { get; set; }
}
public class Specification
{
public int SpecificationID { get; set; }
public virtual ProjectComponent ProjectComponent { get; set; }
public string Description { get; set; }
}
and I modified the Fluent API to an inverse of the previous:
modelBuilder.Entity<ProjectComponent>()
.HasOptional(pc => pc.Specification)
.WithRequired(s => s.ProjectComponent);
now when saving to the database, I have no issues and it usses the ProjectComponentID foreign key as the SpecificationID primary key:
var comp = db.ProjectComponents.Find(spec.SpecificationID);
comp.Specification = new Specification {Description = spec.Description};
db.SaveChanges();
Please comment if anyone has a better solution... but this is the only way I could find to solve it as a pure code-first managed DB