I've two tables both with composite primary keys. Both have in common one of the primary key's with a foreign key to another table.
The problem is that when i create the migrations, it messes up the foreign keys.
I must use data annotations.
Example:
public class City
{
[Key, Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string CityCode { get; set; }
[Key, Column(Order = 2)]
public string CompanyCode { get; set; }
public string Description { get; set; }
[ForeignKey("CompanyCode")]
public virtual Company Company { get; set; }
}
public class PostCode
{
[Key, Column(Order = 0)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Code { get; set; }
[Key, Column(Order = 1)]
public string CompanyCode { get; set; }
public string Description { get; set; }
public string CityCode { get; set; }
[ForeignKey("CompanyCode")]
public virtual Company Company { get; set; }
[ForeignKey("CityCode, CompanyCode")]
public virtual City City { get; set; }
}
PostCode and City have a composite primary key (Code, CompanyCode).
PostCode has a foreign key to the table City (CityCode, CompanyCode).
The problem is that the CompanyCode is part of the primary key and at the same time is part of the composite foreign key to City.
When i say that it messes up the foreign keys i mean the following:
CONSTRAINT [FK_dbo.PostCodes_dbo.Companies_CompanyCode] FOREIGN KEY ([CompanyCode]) REFERENCES [dbo].[Companies] ([CompanyCode]) ON DELETE CASCADE,
CONSTRAINT [FK_dbo.PostCodes_dbo.Cities_CompanyCode_CityCode] FOREIGN KEY ([CompanyCode], [CityCode]) REFERENCES [dbo].[Cities] ([CityCode], [CompanyCode])
In the second constraint, it references CompanyCode with CityCode and CityCode with CompanyCode.
I can't find any example in the internet with any scenario like this.
Where am i wrong?
Thanks in advance.
Edit 1
Between City and Company there is a simples primar key CompanyCode.
The same for PostCodes and Company.
If between City and Company you want to create a one-to-one relationship I'm afraid that is not possible following your model. When you are configuring a one-to-one relationship, Entity Framework requires that the primary key of the dependent end also be the foreign key, otherwise EF doesn't see it as one-to-one relationship. The dependend end in your case es City, but you have a problem, you want to add another PK, that is CityCode, that breaks what it means a one to one relationship because, for example, the below records could happen:
Company City
Id CityCode CompanyId
1 ee33a 1
2 aa23b 1
That's way, if you want to achieve your escenario, I guess that you have to create a one-to-many relationship between Company and City. Using Data Annotations could be this way:
public class City
{
[Key, Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string CityCode { get; set; }
[Key, ForeignKey("Company"),Column(Order = 2)]
public string CompanyCode { get; set; }
public string Description { get; set; }
public virtual Company Company { get; set; }
}
public class Company
{
public string Id { get; set; }
public virtual ICollection<City> Cities { get; set; }
}
You can omit the Cities navigation property in Company if you don't want have reference to the cities related to a Company.
The same applies to the PostCode Entity.
Update:
To achieve what you want in the PostCode entity, you have to map the FKs this way:
public class PostCode
{
[Key, Column(Order = 0)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Code { get; set; }
[Key,ForeignKey("City"), Column(Order = 2)]
public string CityCompanyCode { get; set; }
public string Description { get; set; }
[ForeignKey("City"), Column(Order = 1)]
public string CityCode { get; set; }
public virtual City City { get; set; }
[ForeignKey("Company")]
public string CompanyCode { get; set; }
public virtual Company Company { get; set; }
}
Here is a good example of how you should treat the composite FKs
I always add a primary key to my tables, por example: CityId int, PostCode int. with this i resolve relations.
public class PostCode
{
[Key, Column(Order = 0)]
public string PostCodeId { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Code { get; set; }
public string CompanyCode { get; set; }
public string Description { get; set; }
public string CityCode { get; set; }
[ForeignKey("CompanyCode")]
public virtual Company Company { get; set; }
[ForeignKey("CityCode, CompanyCode")]
public virtual City City { get; set; }
}
thanks
Related
I have a model class:
public class UserProfile
{
public string UserID { get; set; }
public string Name{ get; set; }
public ICollection<AddressMaster> AddressMaster { get; set; }
}
The above class have a 1 to many relationship with AddressMaster model class given below:
public class AddressMaster
{
public string AddrID{ get; set; }
public string AddressLine1{ get; set; }
public UserProfile UserProfile { get; set; }
public TheatreLocation TheatreLocation { get; set; }
}
The problem is, there is one other model also that has a 1 to many relationship with addressmaster, which is:
public class TheatreLocation
{
public string LocationID { get; set; }
public string Name{ get; set; }
public ICollection<AddressMaster> AddressMaster { get; set; }
}
So instead of having foreign key at the addressmaster, how can we have a intermediate table between addressmaster and the userprofile & another such table b/w addressmaster and theatre?
Or am i getting the whole concept wrong?
Thanks.
So instead of having foreign key at the addressmaster, how can we have
a intermediate table between addressmaster and the userprofile &
another such table b/w addressmaster and theatre?
If you do not want to set any foreign key and add a intermediate table.Design like below:
public class UserProfile
{
[Key]
public string UserID { get; set; }
public string Name { get; set; }
}
public class AddressMaster
{
[Key]
public string AddrID { get; set; }
public string AddressLine1 { get; set; }
}
public class UserAddress
{
[Key]
public string AddrID { get; set; }
public string UserID { get; set; }
}
Add the primary key to the intermediate table UserAddress.The AddrId could only has one value,but the UserID could have many value which is like one-to-many relationship.
Or am i getting the whole concept wrong?
Nothing wrong.Using navigation property like what you did is also good.
Your table definitions would probably wind up something like this:
UserProfile
UserId PK
Theather
TheatreId PK
Address
AddrID PK
AddressLine1
UserAddress
UserId PK & FK
AddressId FK
TheatreAddress
TheatreID PK & FK
AddressId FK
This is just good normalisation - i.e. you have a generic 'address' table in the database. Several entities may have an address and have either one-many or many-many relationships with addresses, but a specific address only needs to be recorded once.
The PK on the intermediate table only on the UserId (for example) ensures that this is one-many and not many-many.
I have created 3 tables using Code First Approach. I get the following Model Validation Exception when i execute a Find on student table.
Student_courses_Target_Student_courses_Source: : The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical.
public class University
{
[Key]
public string Uni_ID { get; set; }
public virtual List<Course> Courses { get; set; }
}
public class Course
{
[Key]
[Column(Order = 1)]
public string Course_ID { get; set; }
[Key,ForeignKey("uni")]
[Column(Order = 2)]
public string Uni_ID { get; set; }
public virtual ICollection<Student> Students { get; set; }
public virtual University uni { get; set; }
}
public class Student
{
[Key,ForeignKey("course"), Column(Order = 1)]
public string Course_ID { get; set; }
[ForeignKey("course"),Column(Order = 2)]
public string Uni_ID { get; set; }
[Key]
[Column(Order = 3)]
public string Student_ID { get; set; }
public virtual Course course { get; set; }
}
By my understanding , the exception means that i have not mapped my foreign keys in student table to the primary keys in course table. But i have done it . Is there an issue as to how the 'Uni_ID' occurs as Primary key in both University and Course Tables and perhaps i have gone wrong in referencing it as foreign key in the Student table ?
I am trying to create a relationship between two tables but keep getting the following error:
The ForeignKeyAttribute on property 'CallLogId' on type
'Ylp.Web.ParkingApi.DataLayer.Entities.ApiCallLogDetailEntity' is not
valid. The navigation property 'ApiCallLog' was not found on the
dependent type
'Ylp.Web.ParkingApi.DataLayer.Entities.ApiCallLogDetailEntity'. The
Name value should be a valid navigation property name.
DbContextMapping:
modelBuilder.Entity<ApiCallLogDetailEntity>()
.HasRequired<ApiCallLogEntity>(p => p.ApiCallLog);
Primary table:
[Table("ApiCallLog")]
public class ApiCallLogEntity
{
[Key, Column(Order = 0)]
public string CallLogId { get; set; }
[Key, Column(Order = 1)]
public string UserId { get; set; }
[Required]
public string CallFilterId { get; set; }
[Required]
public DateTime LastUpdated { get; set; }
[Required]
public int Count { get; set; }
public virtual ICollection<ApiCallLogDetailEntity> Details { get; set; }
}
foreign table:
[Table("ApiCallLogDetail")]
public class ApiCallLogDetailEntity
{
[ForeignKey("ApiCallLog")]
public string CallLogId { get; set; }
[Required]
public string PrametersHashCode { get; set; }
[Required]
public DateTime LastUpdated { get; set; }
public ApiCallLogEntity ApiCallLog { get;}
}
The foreign key must refer to the whole primary key of the parent table. In your parent table you have a composite primary key which includes CallLogId and UserId. The message is confusing, but this can be part of the error. Is it really necessary to include the UserId in the PK?
Another error is that you have not defined the PK in the dependent table. If the UserId is also necessary on the PK, include it in the dependent table, and make it part of the FK.
I've the following situation I try to solve : I've 2 tables, a Course table with some fields and a CourseDescription table which is optional (so Course may have a CourseDescription but CourseDescription must have a Course). I'm trying to set this up. So far, here's what I have :
public class Course
{
[Key, Column("Key_Course")]
public int ID { get; set; }
public string Name { get; set; }
public virtual CourseDescription CourseDescription { get; set; }
}
public class CourseDescription
{
[Key, ForeignKey("Course")]
public int ID { get; set; }
public string Description { get; set; }
public string PreRequis { get; set; }
public int CoursesID { get; set; }
[ForeignKey("CoursesID")]
public Course Course { get; set; }
}
This "works" meaning that EF doesn't complains about my model but the relation is not properly done because EF associate the PK of CourseDescription with the PK of Course. In my database, this is not the case (ex : CourseDescription.ID=1 is associated with CourseDescription.CoursesID=3, not 1).
Is there a way to fix that with data annotation ? I know I can use the fluent API but I don't want to override the model building just for that (unless there's no other way).
Thanks
Well, I think you have two choices:
Configure an one to many relationship
If you want to map the FK of the relationship between Course and CourseDescription, and you don't want to declare that FK property as Key of the CourseDescription entity, then, you don't have other choice that configure an one-to-many relationship. In that case your model would be like this:
public class Course
{
[Key, Column("Key_Course")]
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<CourseDescription> CourseDescriptions { get; set;}
}
public class CourseDescription
{
[Key]
public int ID { get; set; }
public string Description { get; set; }
public string PreRequis { get; set; }
[ForeignKey("Course")]
public int CourseID { get; set; }
public Course Course { get; set; }
}
Configure an one-to-one relationship but not map the FK of the
relationship
The only way that EF lets you map the FK in an one-to-one relationship is when the FK is declared as a PK too, so if you want to have diferent Ids in both entities and you want to stablish an one-to-one relationship, then you could do something like this:
public class Course
{
[Key, Column("Key_Course")]
public int ID { get; set; }
public string Name { get; set; }
public CourseDescription CourseDescription { get; set;}
}
public class CourseDescription
{
[Key]
public int ID { get; set; }
public string Description { get; set; }
public string PreRequis { get; set; }
[Required]
public Course Course { get; set; }
}
And work with the navigations properties.
It looks like you should not use ForeignKey attribute for ID property of CourseDescription class as you don't want to have an association between primary keys. Try to remove it.
Edit: It looks like I misunderstood the question previous time.
You can have your CourseDescription this way.
public class CourseDescription
{
[Key, ForeignKey("Course")]
public int ID { get; set; }
public string Description { get; set; }
public string PreRequis { get; set; }
public Course Course { get; set; }
}
In this case you don't need to have CoursesID field. Entities will be connected by primary keys.
Is it possible to map an Entity with one identity index that auto increments and a foreign key linking it to another table?
public class Item
{
public int ItemID { get; set; }
[StringLength(20)]
public string Barcode { get; set; }
[StringLength(50)]
public string Name { get; set; }
[StringLength(50)]
public string Description { get; set; }
public decimal Price { get; set; }
[ForeignKey("ItemCategory")]
public string CatID { get; set; }
public virtual ItemCategory ItemCategory { get; set; }
}
public class ItemCategory
{
// This should be the identity index
public int ItemCategoryID { get; set; }
// This should be the foreign key
public string CatID { get; set; }
public string Name { get; set; }
public virtual ICollection<Item> Items { get; set; }
}
I saw this answer - should I configure my tables with modelbuilder?
Foreign key in Item must point to primary key in ItemCategory. FKs in EF behave in exactly same way as in databases. It means that FK must point to property with unique values in the principal entity. The problem is that EF doesn't support unique index / constraint so the only way to achieve uniqueness is primary key.
Because of that you cannot point your FK to CatID unless it is part of primary key but in such case you will have composite key containing both ItemCategoryID and CatID and your Item class will have to contain both of them to form correct FK.