I am using Code First EF v6.0. I have a table MyTable, which should have 3 columns:
Id (the private key), Name and OtherTable_Name (the foreign key).
[Key]
public int Id { get; set; }
[Index(IsUnique = true)]
[MaxLength(400)]
public string Name { get; private set; }
public virtual OtherTable ARandomStringName { get; set; }
I was getting a weird bug where Name was populated with the value of OtherTable_Name, and no foreign key was generated.
I renamed the private key of OtherTable to OtherTableName. Now I get a database table which has Id, Name, and OtherTable_OtherTableName.
This solves my immediate problem - missing foreign key, incorrect Name value - but I don't understand why it was happening in the first place. (And I'd rather be able to refer to the field sensibly as OtherTable.Name, not OtherTable.OtherTableName.)
When does EF prefix foreign key column names with OtherTable_, and when does it not? This bug has not happened on any pair of tables where both have "Id" as the private key column - is it anything to do with the field being the private key in one table and not the other? What should I be doing to avoid this kind of bug happening elsewhere?
You can use DataAnnotations to override EF conventions. Make sure you have a reference to
using System.ComponentModel.DataAnnotations
then simply add the ForeignKey attribute to your NavigationProperty
public int OtherTableId { get; set; }
[ForeignKey("OtherTableId")]
public virtual OtherTable OtherTableItem { get; set; }
Related
The value of 'X' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known primary key.
The field it is complaining about is not a foreign key, but it is part of a composite primary key. Changing the value of this field from 0 to for example 1 solves this problem. The key is defined by the [Key] attribute:
[Key]
public int ClientId { get; set; }
[Key]
public int SubClientId { get; set; }
What is going on?
Here's my scenario:
public class Main
{
public Guid Id { get; set; }
public string Something { get; set; }
public MoreDetail OptionalDetail { get; set; }
}
public class MoreDetail
{
public Guid MainId { get; set; }
public Main Main { get; set; }
public string MoreInfo { get; set; }
}
// model building code:
mainBuilder.HasOne(m => m.OptionalDetail).WithOne(d => d.Main).IsRequired(false);
Intended:
MoreDetail is an optional 'child' table of Main
The primary key would be MainId; it doesn't need its own ID
Actual:
The entity type 'Main' requires a key to be defined.
Attempted:
Adding moreDetailBuilder.HasKey(d => d.MainId). Yields the same error.
Adding .HasForeignKey<MoreDetail>(d => d.MainId) to Main model builder code. Gives The foreign key {'MainId'} on entity type 'MoreDetail' cannot be marked as optional because it does not contain any property of a nullable type. Any foreign key can be marked as required, but only foreign keys with at least one property of a nullable type and which is not part of primary key can be marked as optional..
Using .IsRequired(true) instead. Key setup and inserting records works fine.. but at query time, EF Core generates an INNER JOIN which means nothing is returned if there are no records. :'(
The official docs example show the child/satellite table having its own primary key. It just seems unnecessary; the data is completely identified by its foreign key, isn't it?
In my Code First for this application I have defined a foreign key as nullable. However, when I try to add a record without that key, I still get a Foreign Key constraint error:
The INSERT statement conflicted with the FOREIGN KEY constraint \"FK_dbo.RequestReview_dbo.CustomForm_ReviewFormId\". The conflict occurred in database \"Mkp\", table \"dbo.CustomForm\", column 'CustomFormId'.\r\nThe statement has been terminated.
How should I be defining the relationship so that the key constraint is not enforced?
My code first model defines the field like this:
[Key, ForeignKey("Resource"), DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid RequestReviewId { get; set; } // My Primary Key
public virtual Resource Resource { get; set; }
public Guid? ReviewFormId { get; set; } // Foreign Key
[ForeignKey("ReviewFormId")]
public CustomForm ReviewForm { get; set; }
(I did try searching, but I'm not sure I searched with the right terminology.)
Edit/Update:
If I remove the ForeignKey tag, I still get migration trying to create a relationship, but this time called ReviewForm_CustomFormId. How can I avoid this?
Updated version of the model:
[Key, ForeignKey("Resource"), DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid RequestReviewId { get; set; } // My Primary Key
public virtual Resource Resource { get; set; }
public Guid? ReviewFormId { get; set; } // Foreign Key
public CustomForm ReviewForm { get; set; }
Give it a separate primary key field as well as your foreign key:
public int ID { get; set; }
public Guid? ReviewFormId { get; set; }
[ForeignKey("ReviewFormId")]
public CustomForm ReviewForm { get; set; }
Doing this I was able to insert records that have a null ReviewFormId.
One solution i see is that you could use this colunm ReviewFormId as an implicite foreign key. What i mean is : don't define it as a foreign key, just a regular data instead, and only YOU will know that the data inside it represent a foreign key, but don't tell entity that it is a foreign key because GUID just dosen't accept nullable foreign key.
How to implement fluent mapping for the below scenario, I tried but it ends in vain.
I have two table Product and State, Product have column name State which hold StateCode like "WA", "NJ" etc which of string type. So i need to populate the State column into StateCode and the related State object into State property of the product entity.
Below is the classes i am using. I don't want to change the columns of table
public class Product
{
public int ID { get; set; }
public State State { get; set; }
public string StateCode { get; set; }
public string Description { get; set; }
}
public class State
{
public int Id { get; set; }
public string Code{get;set;}
public string Description{get;set;}
}
I tried the below mapping for Product
this.Property(t => t.StateCode).HasColumnName("State");
HasRequired(t => t.State).WithMany().HasForeignKey(t => t.StateCode);
No, currently it's not possible to have a Foreign Key column that refers to non PK in entity framework. Check this feature suggestion.
If you really want to have that feature, you need to have custom Seed that execute.
alter table Products add constraint FK_Products_States foreign key(State) references States(Code)
But you will not be able to populate State object. Putting public State State { get; set; } property will automatically create a Foreign Key column State_ID that refers to States::ID.
Otherwise you need to change the StateCode to be StateId (integer) that refers to State::Id.
The type of ForeignKey and PrimaryKey of referenced table must be the same. So you need to set State class Id property type to string. In EF you can only use foreig keys pointing to primary keys.
I came up with following scenario today, where i find difficulty in configuring code first fluent mapping
public class Employee
{
public int Id { get; set; }
public string ReferralCode { get; set; }
public string ReferedByCode{ get; set; }
public virtual ICollection<Employee> ReferedEmployee { get; set; }
public virtual Employee ReferedBy { get; set; }
}
Each employee will be referred by some other employee, like that employee will have many referred employees. The referral will be based on Employee Code not on ID.
How to configure fluent mapping for this?
I do not believe it is possible to configure a navigation property to have its foreign key related to a column/property other than the primary key of the related entity.
Your options are:
Change the primary key to ReferralCode
Keep the primary key as Id and do the following:
Add a ReferredById column and use this as the foreign key.
Enable migrations (if they aren't already enabled).
Add a migration for the addition of the ReferredById column and edit this so that it runs a SQL script in a call to the Sql() method to update the value in this new column on the basis of the existing ReferredByCode column.