EF 5.0 code first navigation property - entity-framework

I have got a User entity there are my users are stored in. For some users (admins) I would like to add additional details.
I have written following code.
public partial class UserProfile
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
[Display(Name = "EMail")]
[Required]
public string UserName { get; set; }
[ForeignKey("AdminDetailID")]
public virtual AdminDetail AdminDetail { get; set; }
public int? AdminDetailID { get; set; }
}
public class AdminDetail
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int AdminDetailID { get; set; }
[ForeignKey("UserId")]
public virtual UserProfile UserProfile { get; set; }
public int UserId { get; set; }
}
I like to navigate from my AdminDetail table back to my User Profile table by writing eg. admin.UserProfile.UserName. However, when I run Database-Update I receive:
The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
When I delete the UserProfile property everything works great.. How can I create a "back" navigation within my AdminDetail class?

Entity Framework Code-First allows for polymorphic classes to be stored in the same table. Have you considered using a relationship like this instead?
public partial class UserProfile
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
[Display(Name = "EMail")]
[Required]
public string UserName { get; set; }
}
public class AdminProfile : UserProfile
{
// AdminProfile members.
}
This results in a UserProfile table with an additional column called Discriminator that EF creates and manages for you. This column indicates whether each row in the table is a UserProfile or an AdminProfile. Rows which are of type UserProfile ignore the columns that are specific to AdminProfile when accessed by EF.
Entity framework handles all of the type discrimination for you so you don't need to worry about that directly. Your DbContext will simply have a DbSet which can also store entities of type AdminProfile.

You don't need to have a FK in your UserProfile class. To set up a proper 1:1 only the AdminDetail class would actually need to have the foreign key to the UserProfile class. You can still keep the virtual property to be able to navigate back and forth, and EF will know what it is that you're doing. Similar to this:
public partial class UserProfile
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
[Display(Name = "EMail")]
[Required]
public string UserName { get; set; }
public virtual AdminDetail AdminDetail { get; set; }
}

Related

How to change a one-to-many relationship to a many-to-many relationship in Entity Framework Code First

I have two tables: Place, and MenuSection, that currently have a one-to-many relationship defined like so:
public class Place
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int PlaceID { get; set; }
public virtual ICollection<MenuSection> MenuSections { get; set; }
}
public class MenuSection
{
[Key]
public int MenuSectionID { get; set; }
public int PlaceID { get; set; }
}
However, I now need a many-to-many relationship. If I was just starting out then this would be achieved by changing the MenuSection class to look like this:
public class MenuSection
{
[Key]
public int MenuSectionID { get; set; }
public virtual ICollection<Place> Places { get; set; }
}
The problem is I already have vast amounts of data and business logic associated with the current relationship. So I figure I'll have to leave the PlaceID property in for now and add the places collection.
My question then is: how do I then tell EF the relationship is now many-to-many and to populate the auto-generated joining table with the existing relationships so that I can then remove the PlaceID property from the MenuSection class?
Alternatively I suppose I could manually create a joining table and rewrite all the business logic, manually move the existing relationships over and rewrite all the business logic like so:
public class Place
{
[Key]
[ForeignKey("Place")]
public int PlaceID { get; set; }
[Key]
[ForeignKey("MenuSection")]
public int MenuSectionID { get; set; }
public virtual Place Place { get; set; }
public virtual MenuSection MenuSection { get; set; }
}
I'm surprised this question hasn't been asked before so I just wanted to check I haven't missed a trick?

Entity Framework one-to-one relationship - Unable to determine the principal

I have 2 models:
public class TransactionHistory : IDbEntity {
[Key]
public int ID { get; set; }
public ItemHistory ItemHistory { get; set; }
}
public class ItemHistory : IDbEntity {
[Key]
public int ID { get; set; }
public int TransactionHistoryID { get; set; }
public TransactionHistory TransactionHistory { get; set; }
}
There's a one to one relationship between TransactionHistory and ItemHistory, ItemHistory MUST have a TransactionHistory but TransactionHistory may or may not have an ItemHistory.
I want to be able to do this in code:
var test = db.ItemHistory.Include(x => x.TransactionHistory).ToList();
As well as:
var test2 = db.TransactionHistory.Include(x => x.ItemHistory).ToList();
But I only want a single FK on the ItemHistory table.
With the code I've listed I get this error:
Unable to determine the principal end of an association between the types 'InventoryLibrary.DomainModels.TransactionHistory' and 'InventoryLibrary.DomainModels.ItemHistory'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
How is this achieved in Entity Framework code first data annotations?
Firstly, you have to mark foreign keys by virtual keyword to enable overrides.
public class TransactionHistory : IDbEntity
{
[Key]
public int ID { get; set; }
public virtual ItemHistory ItemHistory { get; set; }
}
public class ItemHistory : IDbEntity
{
[Key]
public int ID { get; set; }
public int TransactionHistoryID { get; set; }
[Required]
public virtual TransactionHistory TransactionHistory { get; set; }
}
If HistoryItem must have Transaction History, add DataAnnotation [Required], which makes it non-nullable.
Finally, wonder, if you want to have one-to-one relationship. I imagine you'd like to have many transaction history entries. Am I right? If not - let me know.
To create one-to-many relationship, use IEnumerable<> type.

EF 4.1 code first with one-to-many relationship creates duplicate foreign keys

I am using entity framework code first. I have 2 entities (Users and Profile) and the relationship between them is one-to-many, that is, one user can only have one profile, but one profile can be assigned to many users. Below the entities:
[Table("Users")]
public class User
{
[Key(), Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public virtual string Name { get; set; }
[Required]
[ForeignKey("Profile")]
public virtual int ProfileId { get; set; }
public virtual Profile Profile { get; set; }
public virtual ICollection<AnotherEntityB> anotherEntityB { get; set; }
}
[Table("Profiles")]
public class Profile
{
[Key(), Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public virtual string Name { get; set; }
// Below the user that performs the discharge of the profile. Only 1 user can do it.
[ForeignKey("User")]
public virtual int? UserId { get; set; }
public virtual User User { get; set; }
public virtual DateTime? dischargeDate { get; set; } <-- this is the date that user performs the discharge of the profile
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<AnotherEntityC> anotherEntityC { get; set; }
}
also I have removed some conventions in the OnModelCreating method:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
The problem is that EF is creating two foreign keys in user entity:
ProfileId (FK, int, No NULL)
Profile_Id (FK, int, NULL)
and only one foreign key should be in Users entity:
ProfileId (FK, int, No NULL)
What's wrong?
Because there are two navigation properties User and Users in Profile that refer to the User entity EF cannot decide by a convention which of the two belongs to the inverse property Profile in entity User. You must EF give a hint using the [InverseProperty] attribute:
[InverseProperty("Users")]
public virtual Profile Profile { get; set; }
Now, it defines that User.Profile is the inverse navigation property of Profile.Users and that both are ends of the same relationship. Without the attribute EF assumes that the two navigation properties are ends of two different relationships and one of them is responsible for the additional foreign key Profile_Id.
Here is a bit more background.

Database Generated by EF5 Not Creating Join Table When There are Multiple Relationships

I have a User and an Organization class. They look like this
public class User
{
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<Organization> Organizations { get; set; }
}
public class Organization : EntityBase
{
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<User> Users { get; set; }
}
And both inherit from an EntityBase class to get common fields like Id and created/updated tracking.
public abstract class EntityBase
{
public int Id { get; set; }
public DateTime Created { get; set; }
public virtual User CreatedBy { get; set; }
public DateTime Updated { get; set; }
public virtual User UpdatedBy { get; set; }
}
As denoted by the ICollection properties on both, there should be a many-to-many relation. However when my database is autogenerated I get incorrect foreign keys added to my tables
If I change the CreatedBy and UpdatedBy to be strings instead of User properties I get a join table, which is what I was looking for.
Is this a matter of Entity Framework simply being confused and I need to supply many-to-many configuration in the using fluent mappings, or have I done something wrong?
If you have multiple relationships you need to configure them manually by fluent API or using attributes,
Note:If you have multiple relationships between the same types (for
example, suppose you define the Person and Book classes, where the
Person class contains the ReviewedBooks and AuthoredBooks navigation
properties and the Book class contains the Author and Reviewer
navigation properties) you need to manually configure the
relationships by using Data Annotations or the fluent API
Here is the article from Microsoft.

One to One Relationship on Primary Key with Entity Framework Code First

I'm currently getting the following error when trying to create an one to one relationship using Code First:
System.Data.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'C001_Holding_Teste_C001_Holding_Source' in relationship 'C001_Holding_Teste_C001_Holding'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be 1.
My entity definitions are the following:
[Table("C001_Holding", Schema = "Cad")]
public partial class C001_Holding
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int C001_Id { get; set; }
[MaxLength(16)]
public string C001_Codigo { get; set; }
[MaxLength(100)]
public string C001_Descricao { get; set; }
}
public class C001_Holding_Test
{
[Key]
public int C001_Id { get; set; }
[MaxLength(100)]
public string C001_TestInfo { get; set; }
[ForeignKey("C001_Id")]
public virtual C001_Holding C001_Holding { get; set; }
}
I didn't want to use Fluent to create these relationships, does anyone knows why this is happening?
Tks.
It is possible to place the ForeignKey attribute either on a navigation property and then specify the name of the property you want to have as the foreign key (that's what you did). Or you can place it on the foreign key property and then specify the name of the navigation property which represents the relationship. This would look like:
public class C001_Holding_Test
{
[Key]
[ForeignKey("C001_Holding")]
public int C001_Id { get; set; }
[MaxLength(100)]
public string C001_TestInfo { get; set; }
public virtual C001_Holding C001_Holding { get; set; }
}
For some reason this second option works while the first throws an error. (It feels like a bug to me because both options should represent the same relationship. Or there is actually a semantic difference which I don't see...)