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; }
}
Related
Is it possible to build two optional one-to-one relationship in SQL?
I'd like to have:
public class EventInvoice
{
[Key]
public int ID { get; set; }
[ForeignKey("SZ_Event")]
public Nullable<int> SZ_EventID { get; set; }
public virtual SzopbudkaEvent SZ_Event { get; set; }
[ForeignKey("UP_Event")]
public Nullable<int> UP_EventID { get; set; }
public virtual Event UP_Event { get; set; }
}
public class Event
{
[Key]
public int EventID { get; set; }
public virtual EventInvoice EventInvoice { get; set; }
}
public class SzopbudkaEvent
{
[Key]
public int ID { get; set; }
public virtual EventInvoice EventInvoice { get; set; }
}
My invoice can be combined only with one of those objects (Event or SzopbudkaEvent). Is it possible to use it like this or I have to write something different?
You can do this but there are two things to bear in mond.
If the constraint is only one of the FK's can exist, then in the database the FK columns on the EventInvoice tale must be nullable. You've got this but I thought I'd emphasise it.
If there is also a constraint that there must be one of them (missing both is not allowed) then you have to work out how to validate that constraint. In the DB I'd use a trigger fir insert, update that raises an exception if both are null. I'd match that in code with a pre-save check: this describes implementing interface IValidatableObject with a Validate method which EF will call when the object is affected by SaveChanges.
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
I'm trying to create a model that can optionally refer to a parent of the same type, for example:
public class Category
{
public virtual long CategoryID { get; set; }
public virtual Category? ParentCategory { get; set; }
public virtual int UserID { get; set; }
public virtual string Name { get; set; }
}
As you can see there is an optional member called ParentCategory that is optional and refers to a class of type Category (i.e. the same type). As I'm sure you can guess, I'm trying to create a simple Category tree, where the root node(s) will not have a parent.
This results in the following error when the Entity Framework tries to create the database:
"The ForeignKeyAttribute on property 'ParentCategoryID' on type 'MyProject.Models.Category' is not valid. The navigation property 'Category' was not found on the dependent type 'MyProject.Models.Category'. The Name value should be a valid navigation property name."
I also tried this:
public class Category
{
public virtual long CategoryID { get; set; }
[ForeignKey("Category")]
public virtual long? ParentCategoryID { get; set; }
public virtual int UserID { get; set; }
public virtual string Name { get; set; }
}
But again this resulted in the same error.
Is it possible to model this using EF Code First? Its easy to model it int he database if I were to create the database manually.
Thanks in advance
Ben
Your first example wouldn't even compile because T?, a shortcut for Nullable<T> can only be applied to value types.
The following works fine here:
public class Category
{
public virtual long CategoryID { get; set; }
public virtual Category ParentCategory { get; set; }
}
Now, this will use an ugly name by default for the FK, ParentCategory_CategoryID.
This is a way to get a nicer name, plus some flexibility when using it:
public class Category
{
public virtual long CategoryID { get; set; }
[ForeignKey("ParentCategoryID")]
public virtual Category ParentCategory { get; set; }
public virtual long? ParentCategoryID { get; set; }
}
I'm very new to ASP.NET and could use some help.
For this scenario, I have 2 classes. One is a "project" class and the other is a "company" class. Essentially, what I need is one single "company directory" of all the companies we have relationships with, but I need to be able to freely slot them into 3 different slots within a project. It is possible that the same company could occupy all 3 slots, but it's equally likely that a different company will be placed in each slot.
Here are my classes:
public class Project
{
public int ID { get; set; }
public string Name { get; set; }
public int ClientID { get; set; }
public int PublisherID { get; set; }
public int DeveloperID { get; set; }
public Company Client { get; set; }
public Company Publisher { get; set; }
public Company Developer { get; set; }
}
public class Company
{
public int ID { get; set; }
public string Name { get; set; }
}
When I have used this basic outline in the past, the complex types I specify in the bottom half of the model definition will be auto generated based on the matching int ID properties specified earlier. For example, If I had a complex type "User" that was drawing it's data from a user table in my database, specifying (int UserID) within my class followed by (User User), the UserID field would be the actual field in my project table and the User object I specify will automatically be an object containing all the User information from the user table.
Using this method as I did in the classes specified above, however, does not work in the way I expected and instead creates not only ClientID, PublisherID, and DeveloperID but also creates CompanyID, CompanyID1, and CompanyID2 which are the fields that will actually be used when attempting to instantiate the Company objects I specified (even though those fields will contain null always).
Is there any way around this?
You just need to specify that your int properties are the foreign keys to your navigation properties.
public class Project
{
public int ID { get; set; }
public string Name { get; set; }
public int ClientID { get; set; }
public int PublisherID { get; set; }
public int DeveloperID { get; set; }
[ForeignKey("ClientID")]
public Company Client { get; set; }
[ForeignKey("PublisherID")]
public Company Publisher { get; set; }
[ForeignKey("DeveloperID")]
public Company Developer { get; set; }
}
I feel like this should have a simple answer, but I can't find it.
I have 2 POCOs:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Product
{
public int Id { get; set; }
public int CategoryId { get; set; }
}
Notice that there are no object references on either POCO. With Code-First, how do I make EF4 CTP5 define a relationship between the two database tables?
(I know this is an unusual scenario, but I am exploring what's possible and what's not with Code-First)
No, this is not possible. As you can see below, all of the fluent API methods for setting up associations require specifying the Navigation Property as their parameter.
HasMany<TTargetEntity>(Expression<Func<TEntityType, ICollection<TTargetEntity>>> navigationPropertyExpression)
HasOptional<TTargetEntity>(Expression<Func<TEntityType, TTargetEntity>> navigationPropertyExpression)
HasRequired<TTargetEntity>(Expression<Func<TEntityType, TTargetEntity>> navigationPropertyExpression)
Is there any particular reason you don't want to use object references? It looks very elegant to use them:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public int Id { get; set; }
public Category Category { get; set; }
}
And you can still access the Category Id via your product as product.Category.Id.