How to create composite primary key on multiple accessor properties in Entity Framework 6 - entity-framework-6

I'm trying to create a composite key based on three navigation properties in Entity Framework 6 : ManufacturingBundle_Id, Part_Id and Process_Id
Here is my PartProcess class I use at the moment with Id being the Primary key:
public class PartProcess
{
public int Id { get; set; }
public virtual ManufacturingBundle ManufacturingBundle { get; set; }
public virtual Part Part { get; set; }
public virtual Process Process { get; set; }
}
At the moment I get the automatically generated database table that has the following Columns:
Id | ManufacturingBundle_Id | Part_Id | Process_Id
where Id is the Primary key. I would like to get rid of the Id Column and make a composite Primary key based on ManufacturingBundle_Id, Part_Id and Process_Id
So I tried overloading the OnModelCreating method but this doesn't seem to work on typed objects, the debuggers says the properties need to be ints.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// create a composite primary key for PartProcess https://www.learnentityframeworkcore.com/configuration/fluent-api/haskey-method
modelBuilder.Entity<PartProcess>()
.HasKey(o => new { o.ManufacturingBundle, o.Part, o.Process });
base.OnModelCreating(modelBuilder);
}
How must I declare this composite primary key because I use navigation properties and the ManufacturingBundle_Id, Part_Id and Process_Id properties are autogenerated by Entity Framework?
Thanks for your help,
Ephie

Assuming ManufacturingBundle has a ManufacturingBundleId field for instance, you'd need to configure your model as follows:
public class PartProcess
{
public int ManufacturingBundleId { get; set; }
public virtual ManufacturingBundle ManufacturingBundle { get; set; }
public int PartId { get; set; }
public virtual Part Part { get; set; }
public int ProcessId { get; set; }
public virtual Process Process { get; set; }
}
Then it should let you create the composite key on the model creation, as you outlined above.

Related

EDMX/ EF Remove Existing primary key column and add new column with primary key

I have folowwing scenario in ASP.net MVC - code first
[Table("api")]
public class Api
{
[Column("Id")]
public int Id { get; set; }
[Column("api_key")]
public string ApiKey { get; set; }
public virtual BookingPluginConfig BookingPluginConfig { get; set; }
}
public class BookingPluginConfig
{
[Key,ForeignKey("Api")]
public int ApiId { get; set; }
public virtual Api Api { get; set; }
}
Currently "Api" table to "BookingPluginConfig" have one to one relationship - I want to change it to one to many
'BookingPluginConfig' table has
[Key,ForeignKey("Api")]
public int ApiId { get; set; }
I want to remove this column which is the primary key, and I want to add new column as the primary key (auto increment)
Currently this 'ApiId ' is primary key as well foreign key. I want to remain ''ApiId '' is foreign key but not as primary key
I have already many data in existing table
How can I do this?
Your modified BookingPluginConfig class:
public class BookingPluginConfig
{
[Key(), Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[ForeignKey("Api")]
public int ApiId { get; set; }
public virtual Api Api { get; set; }
}
Navigation property, which is the only change, in the API class:
//one to many relation to BookingPluginConfig
public virtual ICollection<BookingPluginConfig> BookingPluginConfigs { get; set; }
That's all you need to add a new primary key and define relation. Take back up of database if you want, add migration and update database.

Are foreign key nullable by default in ASP.Net MVC 5 application

I am in a learning phase. And I want to know are foreign keys created by ASP.NET MVC-5 framework in Code First convention using entity framework nullable by default? I tried to create foreign key relationship and the foreign key column turns out to be nullable. I had a notion that if I mark a column as foreign key it should be marked as NOT NULLABLE by entity framework.
Below is the example:
One to Many: One "Standard" can have many "Children".
public class Children
{
public int Id { get; set; }
public string Name { get; set; }
public int StandardId { get; set; }
[ForeignKey("StandardId")]
public virtual Standard Standard { get; set; }
}
public class Standard
{
public Standard()
{
Children = new List<Children>();
}
public int Id { get; set; }
public string StandardName { get; set; }
public virtual ICollection<Children> Children { get; set; }
}
With just above configuration, the Foreign Key "StandardId" is coming out to be Nullable in database. I just want to know is this expected behaviour? Are foreign keys are suppose to be NULLABLE by DEFAULT or I have not wired up foreign key property properly?
You must tell EF explicitly, that you want this field to be not nullable:
public class YourContext : DbContext
{
public DbSet<Children> Childrens { get; set; }
public DbSet<Standard> Standards { get; set; }
protected override void OnModelCreating(DbModelBuilder dBModelBuilder)
{
modelBuilder.Entity<Children>().HasRequired(x => x.Standard);
}
}

ASP.NET MVC 5 Model Navigation Properties Error

So I have two models that I am trying to get working,
public class Contract
{
[Key]
public int Id { get; set; }
public string AwardId { get; set; }
[ForeignKey("Id")]
public virtual ICollection<ContractHistory> contractHistory { get; set; }
}
And
public class ContractHistory
{
[Key]
public int Id { get; set; }
public string AwardId { get; set; }
[ForeignKey("Id")]
public virtual Contract contract { get; set; }
}
There are many ContractHistory related to one Contract.
I keep getting a run-time InvalidCastException with that setup but when I remove the navigation property within the ContractHistory, and modify the Contract navigation property to:
public virtual ContractHistory contractHistory { get; set; }
It performs the join correctly without any errors.
I only have a year of experience working with .NET and at a lose as to what the issue could be. Ideally, I would like to navigate from Contract to a list of ContractHistory and from ContractHistory to one Contract. Worst case would be for me to create independent data repository methods to explicitly pull in these records but would prefer to figure out the solution to this problem for future reference.
Any advice or follow up questions are welcomed and thanks in advance!
Your ContractHistory class does not have a foreign key property.
Furthermore, you don't need to have the ForeignKeyAttribute overtop of public virtual ICollection<ContractHistory> contractHistory { get; set; } because you should be referencing the foreign key in the ContractHistory class.
The ForeignKeyAttribute constructor takes a string as a parameter.
Per MSDN
Parameters
name
Type: System.String
If you add the ForeigKey attribute to a foreign key property, you should specify the name of the associated navigation property. If you add the ForeigKey attribute to a navigation property, you should specify the name of the associated foreign key(s). If a navigation property has multiple foreign keys, use comma to separate the list of foreign key names.
So in your case:
[ForeignKey("Id")]
public virtual Contract contract { get; set; }
You are placing the ForeignKeyAttribute on the navigation property, contract. So essentially your class will search for a property called Id and identify that as the foreign key. But in your class, Id has the Key attribute which means you are declaring that as your primary key.
So in order to resolve this, you need to add another property to your ContractHistory class that will be the foreign key. And then change the string in your ForeignKeyAttribute to the name of that property.
Example:
public class ContractHistory
{
[Key]
public int Id { get; set; }
public string AwardId { get; set; }
public int contractID {get;set;}
[ForeignKey("contractID")]
public virtual Contract contract { get; set; }
}
Hope this helps!
As far as I see you want to implement one-to-many relationship, if so you have to remove the foreginkey attribute from the contract history collection in the contract class, and add contractId property as foreignkey in the contract history class as below:
public class Contract {
[Key]
public int Id { get; set; }
public string AwardId { get; set; }
public virtual ICollection<ContractHistory> contractHistory { get; set; }
}
public class ContractHistory {
[Key]
public int Id { get; set; }
public string AwardId { get; set; }
public int ContractId { get; set;}
[ForeignKey("ContractId")]
public virtual Contract contract { get; set; }
}

Fluent API mapping other side if a 1-1 relationship

I have a relationship set up between 2 tables using code first and Fluent API. This works and the schema is generated with the correct fields and key assignments. However, my problem is I need to be able to say SupplyPoint.SupplyPointPricing in my resultant Model. What I have below only gives me the other way around.
I figure there must be a way to keep the structure I have but just MAP SupplyPoint.
public partial class SupplyPoint
{
[Key]
public int SupplyPointId { get; set; }
public string SupplyPointName { get; set; }
}
public class SupplyPointPricing
{
public int SupplyPointPricingId { get; set; }
public int? SupplyPointId { get; set; }
[ForeignKey("SupplyPointId")]
public virtual SupplyPoint SupplyPoint { get; set; }
}
Then I use Fluent API and this gives me the 1-1 between the tables and the Schema I expect
modelBuilder.Entity<SupplyPointPricing>()
.HasOptional(a => a.SupplyPoint)
.WithMany()
.HasForeignKey(u => u.SupplyPointId);
Last time I had this problem I had to change the design around and have a foreign key in the SupplyPoint table. On that previous occasion that was OK since it was a 1-1 required where there are always a matching record. This time around I need to keep this structure since there is 1-0 between SupplyPoint and SupplyPointPricing.
This is how I have always done 1-to-1 relationships with my models, without using Fluent mapping:
public partial class SupplyPoint
{
[Key]
public int SupplyPointId { get; set; }
public virtual SupplyPointPricing SupplyPointPricing { get; set; }
}
public class SupplyPointPricing
{
[Key, ForeignKey("SupplyPoint")]
public int SupplyPointId { get; set; }
public virtual SupplyPoint SupplyPoint { get; set; }
}
As you can see, the SupplyPointPricing does not have an Id of its own, but only the Id of the SupplyPoint, which acts as a key in the 1-to-1 relatioship.
The only thing I'm not sure of is if the SupplyPointId can be a nullable int.
This will not create a foreign key on the SupplyPoint, so if you don't have a Pricing, the SupplyPoint.SupplyPointPricing property will be null.

EntityType 'Category' has no key defined. Define the key for this EntityType [duplicate]

This question already has answers here:
EntityType has no key defined error
(13 answers)
Closed 6 years ago.
Developing a basic ASP.net MVC 4 application. Its a simple product catalog application, where in I have 2 database tables ('Category' and 'Products')
There is a foreign key reference of 'Category id' (primary key in Category table) in 'Products' table.
When I run the application, I am getting error message (listed below).
System.Data.Entity.Edm.EdmEntityType: : EntityType 'Category' has no key defined. Define the key for this EntityType.
System.Data.Entity.Edm.EdmEntitySet: EntityType: EntitySet 'Category' is based on type 'Category' that has no keys defined
This looks like a common error for newbies,I did check all the related solutions to 'Entity key '' has no key defined.' but still my problem is not solved, Kindly help me in understanding this problem and what is the correct solution to this problem.
Below are my model classes
Category.cs
namespace ChemicalStore.Models
{
public partial class Category
{
public int CatId { get; set; }
public string CatName { get; set; }
public string CatDescription { get; set; }
public List<Product> Product { get; set; }
}
}
Products.cs
namespace ChemicalStore.Models
{
public class Product
{
public int ProductId { get; set; }
public int CatId { get; set; }
public string ProductTitle { get; set; }
public string ProductPrice { get; set; }
public string ProductDescription { get; set; }
public string ProductPackage { get; set; }
}
}
You should add attribute [Key] before property CatId:
using System.ComponentModel.DataAnnotations;
public partial class Category
{
[Key]
public int CatId { get; set; }
public string CatName { get; set; }
public string CatDescription { get; set; }
public List<Product> Product { get; set; }
}
The problem is that EF can work only when it knows primary key of table. By default EF recognize as primary key property with name Id. If your table has another primary key, you can mark it with attribute [Key] or set Key with fluent configuration.
Entity Framework uses a primary key field to create the primary key column on the generated table.
It uses convention to get this column with some variations:
If the field is called id or any casing variance;
If the field is called ClassNameId of any casing variance;
I may be missing some more conventions, but these are the most common cases.
If you don't have any field with this conventions you need to mark your desired primary key with the attribute [Key]:
[Key]
public int CatId { get; set; }
I was able to solve this by adding a setter to my key property; I only had a getter before.
public int Id { get; set; }
Just place [key] attribute on above id ..
[Table("employee")]
public class Employee
{
[Key]
public int Empno { set; get; }
public string Empname { set; get; }
}
Entity classes are auto generated..
Manual changes to those files will be overwritten if the code is regenerated.
You need to create a partial class with all your metadata
[MetadataType(typeof(Category.CategoryMetadata))]
public partial class Category
{
internal sealed class CategoryMetadata
{
[Key]
public int CatId { get; set; }
[Required]
public string CatName { get; set; }
public string CatDescription { get; set; }
public List<Product> Product { get; set; }
}
}
Read more on MSDN
Hi if you are getting below error.
""One or more validation errors were detected during model generation:
Checking.Models.Employee: : EntityType 'Employee' has no key defined. Define the key for this EntityType.""
just check your table column name and defined property name same or not .
if not then correct it proble resolved.
In my case I fixed this problem adding the right connectionString in the web.config/app.config file.
I had forgotten adding it and the DBContext was not able to communicate with the DB.
Hope it helps

Resources