I can't figure out why this is causing EF error: Invalid column name 'User_UserId' when saving in EF.
Here is my model:
[DataContract(IsReference = true)]
public class User
{
[Key]
[DataMember]
public virtual Guid UserId { get; set; }
[DataMember]
public virtual string Username { get; set; }
[DataMember]
public virtual string Password { get; set; }
[DataMember]
public virtual string Email { get; set; }
[DataMember]
public virtual ICollection<FriendList> FriendLists { get; set; }
}
[DataContract(IsReference = true)]
public class FriendList
{
[Key]
[DataMember]
public virtual Guid FriendListId { get; set; }
[DataMember]
[ForeignKey("User")]
public virtual Guid UserId { get; set; }
[DataMember]
public virtual User User { get; set; }
[DataMember]
[ForeignKey("FriendUser")]
public virtual Guid FriendUserId { get; set; }
[DataMember]
public virtual User FriendUser { get; set; }
}
basically, its one to many relationship with users having a friendlists.
You have two navigation properties of type User in your FriendList class. EF cannot figure out which of these belong to User.FriendLists and then creates for all three navigation properties a separate one-to-many relationship, one of them has the default foreign key name User_UserId.
You can overwrite this convention with the InverseProperty attribute:
public class FriendList
{
// ...
[DataMember]
[InverseProperty("FriendLists")]
public virtual User User { get; set; }
// ...
}
Now, User.FriendLists and FriendList.User are the endpoints of the same one-to-many relationship and FriendList.FriendUser defines a second one-to-many relationship (but without an endpoint in the User class).
I guess:
1) The attribute ForeignKey in your case must be set as [ForeignKey("UserId")] and not as [ForeignKey("User")]
2) Or If one of these classes are not mapped you must set the attribute [NotMapped] on it;
Your ForeignKey attribute is in the wrong place.
Try this:
[DataMember]
public virtual Guid UserId { get; set; }
[DataMember]
[ForeignKey("UserId")]
public virtual User User { get; set; }
[DataMember]
public virtual Guid FriendUserId { get; set; }
[DataMember]
[ForeignKey("FriendUserId")]
public virtual User FriendUser { get; set; }
At least it worked for me.
Related
Earlier I had the following classes with relationship
[Table("User")]
public class User
{
// Base properties
[Key]
public int UserId { get; set; }
public string Name { get; set; }
// Relationships
public ICollection<UserRole> UserRoles { get; set; }
}
[Table("UserRole")]
public class UserRole
{
// Base properties
[Key]
public int UserRoleId { get; set; }
public string Name { get; set; }
// Relationships
public int UserId { get; set; }
[ForeignKey("UserId")]
public User User { get; set; }
}
EF Core was able to map this to SQL as intended which gave two tables
User - UserId (PK), Name
UserRole - UserRoleId (PK), Name, UserId (FK)
Later I wanted to add a way to verify the records and the verifiers are coming from the User table itself. The below is how the verification implemented:
[Table("User")]
public class User
{
// Base properties
[Key]
public int UserId { get; set; }
public string Name { get; set; }
// Relationships
public ICollection<UserRole> UserRoles { get; set; }
// Verification
public int? VerifierId { get; set; }
[ForeignKey("VerifierId")]
public User Verifier { get; set; }
}
[Table("UserRole")]
public class UserRole
{
// Base properties
[Key]
public int UserRoleId { get; set; }
public string Name { get; set; }
// Relationships
public int UserId { get; set; }
[ForeignKey("UserId")]
public User User { get; set; }
// Verification
public int? VerifierId { get; set; }
[ForeignKey("VerifierId")]
public User Verifier { get; set; }
}
The above setup is giving the following exception while adding the migration: Unable to determine the relationship represented by navigation property 'User.UserRoles' of type 'ICollection<UserRole>'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
However removing the below property in the UserRole table makes the migration possible:
ForeignKey("VerifierId")]
public User Verifier { get; set; }
But it is not what I want. I want the foreign key kept as well. How to make this possible? and why this is not allowed at the first place?
The problem here is that EF does not know which FK (UserId or VerifierId) should be mapped to the UserRoles property of the User class.
You need to define which foreign key should be used
[InverseProperty(nameof(UserRole.User))]
public ICollection<UserRole> UserRoles { get; set; }
See the documentation here
https://learn.microsoft.com/en-us/ef/core/modeling/relationships
I am trying to create code first approach a user table which have different foreign keys,but I it gives me error with this message:
"The ForeignKeyAttribute on property 'discount_id' on type 'EFNetflixAssignment.User' is not valid. The foreign key name 'Discounts' was not found on the dependent type 'EFNetflixAssignment.Discount'. The Name value should be a comma separated list of foreign key property names."
Here is my code for the user table
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Required]
public virtual int Id { get; set; }
[Required]
public virtual bool Status { get; set; }
[Required]
[MaxLength(255)]
public virtual string Email { get; set; }
[Required]
[MaxLength(255)]
public virtual string Password { get; set; }
[Required]
public virtual List<Payment_type> Payment_Types { get; set; }
[Required]
public virtual bool Activated { get; set; }
[Required]
[ForeignKey("Discounts")]
public virtual List<Discount> discount_id { get; set; }
}
And here is the discount code
public class Discount
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Required]
public virtual int Id { get; set; }
[Required]
[MaxLength(255)]
public virtual string discount_type { get; set; }
[Required]
public virtual decimal discount_amount { get; set; }
}
Can somebody help me solve this issue?
The ForeignKey-Attribute won't work like this.
If you don't care about the name of the foreign key in the database, then you don't need this attribute. EF will automatically create a foreign key for the navigation properties.
If you want to specify the name of this key, then you need another property in the user class, that holds the foreign key and then you can connect these 2 properties in 2 possible ways:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Required]
public virtual int Id { get; set; }
[Required]
public virtual bool Status { get; set; }
[Required]
[MaxLength(255)]
public virtual string Email { get; set; }
[Required]
[MaxLength(255)]
public virtual string Password { get; set; }
[Required]
public virtual List<Payment_type> Payment_Types { get; set; }
[Required]
public virtual bool Activated { get; set; }
[Required]
[ForeignKey("Discounts")]
public List<int> Discount_Ids { get; set; }
[Required]
public virtual List<Discount> Discounts { get; set; }
Or like this:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Required]
public virtual int Id { get; set; }
[Required]
public virtual bool Status { get; set; }
[Required]
[MaxLength(255)]
public virtual string Email { get; set; }
[Required]
[MaxLength(255)]
public virtual string Password { get; set; }
[Required]
public virtual List<Payment_type> Payment_Types { get; set; }
[Required]
public virtual bool Activated { get; set; }
[Required]
public List<int> Discount_Ids { get; set; }
[Required]
[ForeignKey("Discount_Ids")]
public virtual List<Discount> Discounts { get; set; }
This is because whenever you want to set a specific name for a foreign key using Data Annotations you need to add a property for that key and connect it with the navigation property.
But be aware of the fact, that on your database the foreign key will be set in the discount table, because in a 1-to-many relationship the table on the many-side always takes the primary key of the 1-side as the foreign key for the relationship.
Hope this solves your issue, let me know if you have any further questions :)
I'm using Entity Framework to build my database. My model contain two entities: Entite and ApplicationUser (see code below).
There are two relations between these entities:
One-to-Many: an Entite could contain one or many users. And a user belongs to one Entite.
One-to-One: an Entite must have one user as a responsible and a user can be responsible for only one Entite.
Entite:
public class Entite : AuditableEntity<int>
{
[Required]
[MaxLength(10)]
public String code { get; set; }
[Required]
[MaxLength(50)]
public String Libelle { get; set; }
[Required]
[MaxLength(10)]
public String type { get; set; }
[Key, ForeignKey("ResponsableId")]
public int? ResponsableId { get; set; }
public virtual ApplicationUser responsable { get; set; }
public int? RattachementEntiteId { get; set; }
[Key, ForeignKey("RattachementEntiteId")]
public virtual Entite rattachement { get; set; }
public List<Entite> Children { get; set; }
}
ApplicationUser:
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Matricule { get; set; }
public DateTime? dateRecrutement { get; set; }
public int? entiteId { get; set; }
[ForeignKey("entiteId")]
public virtual Entite entite { get; set; }
}
When I tried to build the database using the Add-Migration command, I got this error :
Unable to determine the principal end of an association between the types
Any idea about this issue?
Thanks for your help
It looks like a small typo/error in your Entite model class.
The ForeignKey should be referencing your ApplicationUser, currently it is referencing itself, and a new Key will be generated for the responsable.
If we swap the ForeignKey reference to below, then this looks like it should solve your issue:
[Key, ForeignKey("responsable")]
public int? ResponsableId { get; set; }
public virtual ApplicationUser responsable { get; set; }
Or you can swap the reference like you have done on your rattachement.
public int? ResponsableId { get; set; }
[Key, ForeignKey("ResponsableId ")]
public virtual ApplicationUser responsable { get; set; }
I have two entities which I want to be connected 1:1 relationship. User is principal and UserActivation is dependent, but I have no idea how that works.
public class User
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
public string Lastname { get; set; }
public string Username { get; set; }
public virtual UserActivation UserActivation { get; set; }
}
public class UserActivation
{
[Key]
public Guid Id { get; set; }
public Guid UserId { get; set; }
public bool Active { get; set; }
public virtual User User { get; set; }
}
I have tried to remove 'virtual' keyword, have tried to add ForeignKey("UserId") or ForeignKey("User"), I've even tried to make [Key, ForeignKey("User") and none of them helped me. I want to make 1:1 relationship using only dataannotations. Any help is really appreciated. Also my both classes has their own PKs.
Foreign keys are not supported for 1:1 try:
public class User
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
public string Lastname { get; set; }
public string Username { get; set; }
public virtual UserActivation UserActivation { get; set; }
}
public class UserActivation
{
[Key]
[ForeignKey("User")]
public Guid Id { get; set; }
public bool Active { get; set; }
public virtual User User { get; set; }
}
Unable to determine the principal end of an association between the types ‘Model.PersonPhoto’ and ‘Model.Person’. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
Julie Lehrman discusses this in her Code First book:
"This problem is most easily solved by using a ForeignKey annotation
on the dependent class to identify that it contains the foreign key.
When configuring one-to-one relationships, Entity Framework requires
that the primary key of the dependent also be the foreign key. In our
case PersonPhoto is the dependent and its key, PersonPhoto.PersonId,
should also be the foreign key. Go ahead and add in the ForeignKey
annotation to the PersonPhoto.PersonId property, as shown in Example
4-21. Remember to specify the navigation property for the relationship
when adding the ForeignKey annotation."
This post is quite old so I thought I'd post the EF 6 solution
Try this...
public class User
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
public string Lastname { get; set; }
public string Username { get; set; }
public virtual UserActivation UserActivation { get; set; }
}
public class UserActivation
{
[ForeignKey("User")]
public Guid Id { get; set; }
public Guid UserId { get; set; }
public bool Active { get; set; }
public virtual User User { get; set; }
}
OK what am I missing here or is this just able to be done with data annotation?
I have a Document Entity Model which has a Foreign Key to a User that added the document (one-to-one relationship):
[Table("Documents", Schema = "Configuration")]
public class Document : IPrimaryKey {
[Key]
public long Id { get; set; }
[Required]
public string OrginalName { get; set; }
[Required]
public DocumentTypes DocumentType { get; set; }
[Required]
public MIMETypes MIMEType { get; set; }
[Required]
public byte[] Data { get; set; }
[DefaultValue(false)]
public bool IsPublic { get; set; }
[Required]
public DateTimeOffset DateTimeAdded { get; set; }
[Required]
public long AddedByUser { get; set; }
[ForeignKey("AddedByUser")]
public virtual Details Details { get; set; }
}
I then have a User (Details) Entity that can have an image file (which is stored in the document entities model (none|one-to-one relationship):
[Table("Details", Schema = "User")]
public class Details : IPrimaryKey {
[Key]
public long Id { get; set; }
[Required]
public string UserId { get; set; }
[ForeignKey("UserId")]
public AppUser User { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[CollectionRequired(MinimumCollectionCount = 1)]
public ICollection<Address> Addresses { get; set; }
[CollectionRequired(MinimumCollectionCount = 1)]
public ICollection<Email> Emails { get; set; }
[CollectionRequired(MinimumCollectionCount = 1)]
public ICollection<PhoneNumber> PhoneNumbers { get; set; }
public ICollection<NotificationHistory> NotificationHistory { get; set; }
public long TimeZoneId { get; set; }
public long? ImageId { get; set; }
[ForeignKey("ImageId")]
public virtual Document Document { get; set; }
[ForeignKey("TimeZoneId")]
public virtual TimeZone TimeZone { get; set; }
}
When I try to create a Migration I get this error:
Unable to determine the principal end of an association between the
types 'StACS.PeoplesVoice.DataAccessLayer.EntityModels.User.Details'
and
'StACS.PeoplesVoice.DataAccessLayer.EntityModels.Configuration.Document'.
The principal end of this association must be explicitly configured
using either the relationship fluent API or data annotations.
UPDATED:
While still researching this I made two changes and was able to get around the error but this created an unexpected result in my database.
In the Document Entity I added:
public virtual ICollection<Details> Details { get; set; }
In the Details (user) Entity I added:
puflic virtual ICollection<Document> Documents { get; set; }
In my DB Tables I now have the foreign key on the field I want but I have a secondary foreign key for each respectively.
I tried just removing the single virtual reference and left ONLY the ICollection Virtual reference, now I have no foreign key at all.
UPDATED (based on Akash Kava Suggestion):
I have made the following changes
[Table("Documents", Schema = "Configuration")]
public class Document : IPrimaryKey {
[Required]
public string OrginalName { get; set; }
[Required]
public DocumentTypes DocumentType { get; set; }
[Required]
public MIMETypes MIMEType { get; set; }
[Required]
public byte[] DocumentData { get; set; }
[DefaultValue(false)]
public bool IsPublic { get; set; }
[Required]
public DateTimeOffset DateTimeAdded { get; set; }
[Required]
public long AddedByUser { get; set; }
[Key]
public long Id { get; set; }
[ForeignKey("AddedByUser")]
[InverseProperty("Image")]
public virtual Details User { get; set; }
}
[Table("Details", Schema = "User")]
public class Details : IPrimaryKey {
[Required]
public string UserId { get; set; }
[ForeignKey("UserId")]
public AppUser User { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[CollectionRequired(MinimumCollectionCount = 1)]
public ICollection<Address> Addresses { get; set; }
[CollectionRequired(MinimumCollectionCount = 1)]
public ICollection<Email> Emails { get; set; }
[CollectionRequired(MinimumCollectionCount = 1)]
public ICollection<PhoneNumber> PhoneNumbers { get; set; }
public ICollection<NotificationHistory> NotificationHistory { get; set; }
public long TimeZoneId { get; set; }
public long? ImageId { get; set; }
[ForeignKey("ImageId")]
[InverseProperty("User")]
public Document Image { get; set; }
[ForeignKey("TimeZoneId")]
public virtual TimeZone TimeZone { get; set; }
[Key]
public long Id { get; set; }
}
I have commented out the Fluent API Code
Unable to determine the principal end of an association between the
types 'StACS.PeoplesVoice.DataAccessLayer.EntityModels.User.Details'
and
'StACS.PeoplesVoice.DataAccessLayer.EntityModels.Configuration.Document'.
The principal end of this association must be explicitly configured
using either the relationship fluent API or data annotations.
You can achieve same with Data Annotation as well, you are missing InverseProperty attribute, which resolves ambiguity in this case. Conceptually, every navigation property has Inverse Navigation property, EF automatically detects and assumes inverse property based on type, but if two entities are related to each other by multiple FK properties, you have to explicitly specify InverseProperty attribute on corresponding navigation properties.
I would recommend putting InverseProperty on every navigation property, which helps reduce startup time for EF as EF does not have to determine and validate the model.
Example,
public class AccountEmail {
public long AccountID {get;set;}
// Inverse property inside Account class
// which corresponds to other end of this
// relation
[InverseProperty("AccountEmails")]
[ForeignKey("AccountID")]
public Account Account {get;set;}
}
public class Account{
// Inverse property inside AccountEmail class
// which corresponds to other end of this
// relation
[InverseProperty("Account")]
public ICollection<AccountEmail> AccountEmails {get;set;}
}
I have written a text template which generates all these navigation properties based on current schema. Download all three files from https://github.com/neurospeech/atoms-mvc.net/tree/master/db-context-tt, you might have to customize this as it adds few more things based on our framework, but it does generate pure code model from your database directly.
OK I finally figured this out. Sadly this is not very straight forward as I think Data Annotation should work BUT it does not.
You HAVE to use Fluent API:
modelBuilder.Entity<Details>()
.HasOptional(x => x.Document)
.WithMany()
.HasForeignKey(x => x.ImageId);
modelBuilder.Entity<Document>()
.HasRequired(x => x.User)
.WithMany()
.HasForeignKey(x => x.AddedByUser);