Entity Framework one to many relationship, migration - c#

Hi I have following entities:
public class EntityOne
{
public int EntityOneID { get; set; }
public string Smth { get; set; }
public string User1Id { get; set; }
public string User2Id { get; set; }
public virtual ApplicationUser User1 { get; set; }
public virtual ApplicationUser User2 { get; set; }
}
public class ApplicationUser : IdentityUser
{
public virtual ICollection<EntityOne> EntityOnes { get; set; }
}
I configured Relationships
modelBuilder.Entity<EntityOne>()
.HasRequired<ApplicationUser>(s => s.User1)
.WithMany(s => s.EntityOnes)
.HasForeignKey(s => s.User1Id).WillCascadeOnDelete(false);
modelBuilder.Entity<EntityOne>()
.HasRequired<ApplicationUser>(s => s.User2)
.WithMany(s => s.EntityOnes)
.HasForeignKey(s => s.User2Id).WillCascadeOnDelete(false);
When I delete one of ApplcationUser from my entity everything is OK, but if I have 2 Application users, it gives me following error:
Schema specified is not valid. Errors: The relationship 'SomeProject.Models.EntityOne_User1' was not loaded because the type 'SomeProject.Models.ApplicationUser' is not available.
I want to 2 different users having relation with "EntityOne"
EDIT: Propably answer:
public class ApplicationUser : IdentityUser
{
public virtual ICollection<EntityOne> EntityOnes1 { get; set; }
public virtual ICollection<EntityOne> EntityOnes2 { get; set; }
}
When I created 2 Collections in ApplicationUser everything works.

You can't have two different relationships associated with same property.
Navigation properties provide a way to navigate an association between two entity types. Every object can have a navigation property for every relationship in which it participates.
https://msdn.microsoft.com/en-us/data/jj713564.aspx

Related

C# Entity Framework - Social Network - Friendship, Chat Entity

I am trying to do a database model for my social network school project. I am using Entity Framework 6. The problem is how should I model my Friendship and Chat entity.
I get this error:
Unhandled Exception:
System.Data.Entity.ModelConfiguration.ModelValidationException: One or more validation errors were detected during model generation:
Friendship_Chat_Source: : Multiplicity is not valid in Role 'Friendship_Chat_Source' in relationship 'Friendship_Chat'. Because the dependent role properties are not the key properties, the upper bound of the multiplicity of the dependent role must be '*'.
It has probably something to do with this: EF Code-First One-to-one relationship: Multiplicity is not valid in Role * in relationship
I don't really get it how should I do it here. Even if I get rid off this error somehow (different db model), entity framework in Friendship table creates User_Id column as a foreign key, and I dont really know why it does it (I don't want it there). But I really feel that my model should look like this, not different. So I want to really figure out, how should I edit this model. However if you have different model idea I would also appreciate it.
User entity:
public class User
{
public int Id { get; set; }
[Required, MinLength(1), MaxLength(50)]
public string NickName { get; set; }
[Required, MinLength(6), MaxLength(50)]
public string PasswordHash { get; set; }
#region Settings
//true if anyone can see user posts
public Visibility PostVisibilityPreference { get; set; } = Visibility.Visible;
#endregion
#region Navigation properties
public virtual HashSet<Friendship> Friendships { get; set; }
public virtual HashSet<Post> Posts { get; set; }
public virtual HashSet<GroupUser> GroupUsers { get; set; }
public virtual HashSet<Comment> Comments { get; set; }
#endregion
}
Friendship entity:
public class Friendship
{
#region Primary keys
public int User1Id { get; set; }
public int User2Id { get; set; }
#endregion
[Required]
public DateTime FriendshipStart { get; set; }
#region Foreign keys
//defined using fluent api in MyDbContext:
//User1Id
//User2Id
//and
[ForeignKey("Chat")]
public int? ChatId { get; set; }
#endregion
#region Navigation properties
public virtual User User1 { get; set; }
public virtual User User2 { get; set; }
public virtual Chat Chat { get; set; }
#endregion
}
With this overrided function OnModelCreating in MyDbContext:
protected override void OnModelCreating(DbModelBuilder builder)
{
builder.Entity<Friendship>()
.HasKey(k => new { k.User1Id, k.User2Id });
builder.Entity<Friendship>()
.HasRequired(u => u.User1)
.WithMany()
.HasForeignKey(u => u.User1Id);
builder.Entity<Friendship>()
.HasRequired(u => u.User2)
.WithMany()
.HasForeignKey(u => u.User2Id)
.WillCascadeOnDelete(false);
}
Chat entity:
public class Chat
{
public int Id { get; set; }
#region Foreign keys
public int? FriendshipUser1Id { get; set; }
public int? FriendshipUser2Id { get; set; }
#endregion
#region Navigation properties
public virtual HashSet<Message> Messagges { get; set; }
[ForeignKey("FriendshipUser1Id, FriendshipUser2Id")]
public virtual Friendship Friendship { get; set; }
#endregion
}
If I understand your model right. 1 friendship has 1 user1 and 1 user2. Your settings are excluded.
builder.Entity<Friendship>()
.HasRequired(u => u.User1)
.WithMany()
.HasForeignKey(u => u.User1Id);
It means user1 has many... (many what?). Model doesn't have any list that could accept these settings. Your model has only single objects.
If you want it one to one/zero:
builder.Entity<Friendship>()
.HasRequired(u => u.User1)
.WithRequiredDependant(u => u.User2)
or
.WithRequiredPrincipal(u => u.User2)
or
.WithOptional(u => u.User2)
You can also try composite key for example: Creating Composite Key Entity Framework
Also I suggest you to use or Fluent API or Data Annotation convention. It will make your code more readable.

Entity Framework Core: Multiple Relationships between Users and Organizations

I have 2 model classes for Users and Organizations.
public class User : IdentityUser
{
[Required]
public string Name { get; set; }
[Required]
public string Surname { get; set; }
public int? OrganizationID { get; set; }
public virtual OrgList org { get; set; }
}
public class OrgList
{
public OrgList()
{
employees = new HashSet<User>();
}
public int id { get; set; }
public String name { get; set; }
public String ownerId { get; set; }
public virtual ICollection<User> employees { get; set; }
public virtual User ownerUser { get; set; }
}
User can be owner of some organization and also he is employee of the same organization (But other employees can't be owners of the organization).
First i've created a relationship for employees and it works OK
modelBuilder.Entity<OrgList>(entity =>
{
entity.HasMany(e => e.employees)
.WithOne(e => e.org)
.HasForeignKey(e => e.OrganizationID)
.OnDelete(DeleteBehavior.SetNull);
}
but when i try to add another relationship for owner
entity.HasOne(e => e.ownerUser)
.WithOne(e => e.org)
.HasForeignKey<OrgList>(e => e.ownerId)
.OnDelete(DeleteBehavior.Cascade);
i have an error on migration:
Cannot create a relationship between 'User.org' and
'OrgList.ownerUser', because there already is a relationship between
'OrgList.employees' and 'User.org'. Navigation properties can only
participate in a single relationship.
How can i fix it? I've found an answers for EF6 (not EF Core) with HasOptional() and WithOptionalPrincipal() methods that not exist in EF Core.
Can i do it without creating additional table for employees or without creating additional virtual OrgList on User class?
You're trying to create the owner relationship with the same property on the user that you are using for the employee relationship. Entity framework wouldn't know which relationship to assign the property. If you created another property on the user like
public int? OwnedOrganizationID { get; set; }
public virtual OrgList OwnedOrg { get; set; }
and change the statement to
entity.HasOne(e => e.ownerUser)
.WithOne(e => e.OwnedOrg)
.HasForeignKey<OrgList>(e => e.ownerId)
.OnDelete(DeleteBehavior.Cascade);
I imagine it should work.

EntityFramework 1 to 0, 1 or many relationship

I am struggling to create a relationship in Entity framework between three tables..
I am developing WPF application using C#, Sqlite 3.0 and Entity Framework 6.
I have Following tables(classes):
Investor
Investment
ImageStore
I want to create a model so that Investor and Investment (and future other classes) can store either 0, 1 or Many images.. (as it is obvious from class names that Investor can have only one profile image and Investment class can have multiple images)
My ImageStore class looks something like this:
public class ImageStore : PropertyChangedNotification
{
[Key]
public int ImageStoreId { get; set; }
[Required]
public string ImageFile { get; set; }
[Required]
public Byte[] ImageBlob { get; set; }
public string FileName { get; set; }
[Required]
public int FileSize { get; set; }
//public virtual ImageData ImageData { get; set; }
}
In order to create 1 to 0,1 or Many relationship, I created one more intermediate table called: ImageData as seen below (I don't know whether it is really a good approach but that is only what I can think of right now..)
public class ImageData : PropertyChangedNotification
{
[Key]
public int ImageDataId { get; set; }
[ForeignKey("Investment")]
public long? InvestmentId { get; set; }
[ForeignKey("Investor")]
public long? InvestorId { get; set; }
[ForeignKey("ImageStore")]
public int ImageStoreId { get; set; }
public virtual ImageStore ImageStore { get; set; }
public virtual Investment Investment { get; set; }
public virtual Investor Investor { get; set; }
}
My Investor class looks like this:
public class Investor : PropertyChangedNotification
{
[Key]
public long InvestorId { get; set; }
[NotMapped]
[ForeignKey("ImageData")]
public List<int> ImageDataList { get; set; }
public virtual ICollection<ImageData> ImageDataCollection { get; set; }
public virtual ICollection<Investment> Investments { get; set; }
}
My Investment Class Looks like this:
public class Investment : PropertyChangedNotification
{
[Key]
public long InvestmentId { get; set; }
[ForeignKey("Investor")]
[Required]
public long FirstInvestorId { get; set; }
[NotMapped]
[ForeignKey("ImageData")]
public List<int> ImageDataList { get; set; }
public virtual ICollection<ImageData> ImageDataCollection { get; set; }
public virtual Investor Investor { get; set; }
[NotMapped]
[Required (ErrorMessage = "First Investor is Required")]
public Investor FirstInvestor { get; set; }
}
This is my related fluent configuration:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// MyData Database does not pluralize table names
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Investor>().HasOptional(s => s.ImageDataCollection);
modelBuilder.Entity<Investment>().HasOptional(s => s.ImageDataCollection);
//modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
}
When I start debugging the application, I get the following error:
ImageData_Investment_Source: : Multiplicity is not valid in Role 'ImageData_Investment_Source' in relationship 'ImageData_Investment'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'
ImageData_Investor_Source: : Multiplicity is not valid in Role 'ImageData_Investor_Source' in relationship 'ImageData_Investor'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'
Can someone please suggest me either a solution to this problem and/or optimal approach to achieve what I need, I really will appreciate.
Thanks
The fluent configuration
modelBuilder.Entity<Investor>().HasOptional(s => s.ImageDataCollection);
modelBuilder.Entity<Investment>().HasOptional(s => s.ImageDataCollection);
is incomplete.
Since the you already have the necessary data annotations and navigation / FK properties, you can simply remove it. Or if you want to provide fluent configuration (which I personally prefer because it allows you to specify everything explicitly and not rely on conventions and specifically for relationships, not so intuitive ForegnKey and InverseProperty data annotations), then you should make sure it reflects exactly the presense/absence of the navigation and FK properties in the involved entities.
The correct fluent configuration reflecting your model so far is like this:
modelBuilder.Entity<Investor>()
.HasMany(e => e.ImageDataCollection)
.WithOptional(e => e.Investor)
.HasForeignKey(e => e.InvestorId);
modelBuilder.Entity<Investment>()
.HasMany(e => e.ImageDataCollection)
.WithOptional(e => e.Investment)
.HasForeignKey(e => e.InvestmentId);

Multiple zero or one to one relationships EF 6 Code First

I have a contact table
public class Contact : EntityBase
{
public int TrivialContactProperty { get; set; }
...
public virtual FiContact FiContact { get; set; }
public virtual PuContact PuContact { get; set; }
public virtual TrContact TrContact { get; set; }
}
and then a FiContact, PuContact, and TrContact table.
public class FiContact : EntityBase
{
public int TrivialFiProperty { get; set; }
...
public virtual Contact Contact { get; set; }
}
public class PuContact : EntityBase
{
public int TrivialPuProperty { get; set; }
...
public virtual Contact Contact { get; set; }
}
public class TrContact : EntityBase
{
public int TrivialTRProperty { get; set; }
...
public virtual Contact Contact { get; set; }
}
The contact table should have a zero or one relationship with all three other tables. So a contact can exist without any of the other three, or it can be related to one or two or all three of them.
Using fluent API I tried to configure this, after doing some research, and I came up with:
modelBuilder.Entity<FiContact>()
.HasRequired(r => r.Contact)
.WithOptional(o => o.FiContact);
modelBuilder.Entity<PuContact>()
.HasRequired(r => r.Contact)
.WithOptional(o => o.PuContact);
modelBuilder.Entity<TrContact>()
.HasRequired(r => r.Contact)
.WithOptional(o => o.TrContact);
But I am still getting the following error when I try to add a migration for this change:
FiContact_Contact_Source: : Multiplicity is not valid in Role 'FiContact_Contact_Source' in relationship 'FiContact_Contact'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '(asterisk symbol here)'.
PuContact_Contact_Source: : Multiplicity is not valid in Role 'PuContact_Contact_Source' in relationship 'PuContact_Contact'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '(asterisk symbol here)'.
TrContact_Contact_Source: : Multiplicity is not valid in Role 'TrContact_Contact_Source' in relationship 'TrContact_Contact'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '(asterisk symbol here)'.
From more research I saw that the primary key on the dependent entity is supposed to also be the foreign key? The only problem is that all of my entities inherit from a class "EntityBase" which defines common fields in all entities, including the primary key:
public abstract class EntityBase : IEntity
{
[Key]
public int Id { get; set;}
public bool IsActive { get; set; }
public DateTime CreatedOnDate { get; set; }
public int? CreatedByUserId { get; set; }
[ForeignKey("CreatedByUserId")]
public User CreatedByUser { get; set; }
public DateTime LastUpdatedOnDate { get; set; }
public int? LastUpdatedByUserId { get; set; }
[ForeignKey("LastUpdatedByUserId")]
public User LastUpdatedByUser { get; set; }
}
Is there a way to make this kind of table/entity relationship work with EF 6 Code First? Any help getting this type of relationship to work would be much appreciated.

How to configure the EF model when 1-0..1 and 1-many are both necessary

I have two entity model, OptionWidget and OptionWidgetValue, OptionWidget have many OptionWidgetValue like a option list, and sometimes one of those values will be a default one. I know that I can add one more field in OptionWidgetValue like Default to implement this relationship. But when I try to make another way, that is define the default in OptionWidget as the code below, I encounter some errors:
The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
The following is my model definition:
public class OptionWidget : ModelBase
{
[MaxLength(100)]
public string Name { get; set; }
public int? DefaultValueId { get; set; }
[ForeignKey("DefaultValueId")]
public virtual OptionWidgetValue DefaultValue { get; set; }
[Required]
public int ProductId { get; set; }
public virtual Product Product { get; set; }
public virtual ICollection<OptionWidgetValue> OptionWidgetValues { get; set; }
}
public class OptionWidgetValue : ModelBase
{
public string Value { get; set; }
public decimal UnitPrice { get; set; }
public virtual ICollection<ValueDependency> Dependencies { get; set; }
[Required]
public int OptionWidgetId { get; set; }
[ForeignKey("OptionWidgetId")]
public virtual OptionWidget OptionWidget { get; set; }
}
For the 1-many relationship, I define them with fluent API like this and it works fine. But how should I define the 1-0..1 relationship for the default value. Please help me if you know, thank you very much.
builder.Entity<OptionWidget>()
.HasMany(e => e.OptionWidgetValues)
.WithRequired()
.HasForeignKey(e => e.OptionWidgetId)
.WillCascadeOnDelete(false);
You could use following Fluent API configuration:
modelBuilder.Entity<OptionWidget>()
.HasOptional(e => e.DefaultValue)
.WithOptionalPrincipal();
This code makes to side of relation optional but if you want make OptionWidget required for OptionWidgetValue use this:
modelBuilder.Entity<OptionWidget>()
.HasOptional(e => e.DefaultValue)
.WithRequired();

Categories

Resources