1

I have two tables that I want to create 1-n relation from User to Contact and reverse in EF. It means I need 2 way relation to 2 destination that they are base table too. Contact table in user class should introduce as ICollection so my relation go wrong and both of them are one side.check this picture But if i remove ICollection every things is right.

How should I fix this problem?

  public class User
  {
    [Key]
    public Guid Id {get; set;}       
    [ForeignKey("ContactId")]
    public virtual ICollection<Contact> Contacts {get; set;}        
    public Guid? ContactId {get;set;}
  }

  public class Contact
  {
    [Key]
    public Guid Id {get; set;}
    [ForeignKey("UserId")]
    public virtual User User {get; set;}
    public Guid? UserId {get; set;}
  }

if i remove foreign key of contact check this picture:

i want one more relation between these table but with different direction. check this picture

6
  • 1
    Remove the public Guid? ContactId {get;set;} and [ForeignKey("ContactId")]. You want to 1-n relation for User to Contact so Contact should be defined as collection; i.e. public virtual ICollection<Contact> Contacts {get; set;} Commented May 15, 2018 at 6:18
  • thank you...i tested as you wrote.. but i have one 1-n relation from "contact" to "user" . i need one more relation with reverse side direction too. from "user" to "contact" Commented May 15, 2018 at 6:36
  • Why do (you think) you need that extra relation? How would you use it? Commented May 15, 2018 at 10:23
  • let me say an example: my user table is for my boss and contact table is for his employees so every boss can have multi employees... so in contact table should insert user id that means who is your boss? then i want the name of one contacts that is for boss 1 that have another conditions too (for other tables that have relation with user table) so i should have contact id and virtual in my user table to take data from this. i hope that i explained clearly. Commented May 15, 2018 at 11:05
  • Again, how would you use it? Use more C# (and maybe SQL) to calrify your problem. Commented May 16, 2018 at 7:26

4 Answers 4

2

There are a lot of ways to achieve this. You can do this as follows

  public class User
  {
    [Key]
    public Guid Id {get; set;}
    public virtual ICollection<Contact> Contacts { get; set; }
  }

  public class Contact
  {
    [Key]
    public Guid Id {get; set;}
    public virtual User User {get; set;}
  }

OR

You can also try this way

  public class User
  {
    [Key]
    public Guid UserId {get; set;}
    public virtual ICollection<Contact> Contacts { get; set; }
  }

  public class Contact
  {
    [Key]
    public Guid Id {get; set;}
    public Guid UserId {get; set;}
    public virtual User User {get; set;}
  }

It includes foreign key property UserId

For more information, you can go to this link

Sign up to request clarification or add additional context in comments.

4 Comments

thank you for your answer.. i removed foreign key as you said but i have one 1-n relation from "contact" to "user" . i need one more relation with reverse side direction too.
In this solution, you have ICollection<Contact> Contacts navigational property from User and also User User navigational property from Contact. Doesn't it fulfill your requirements?
@MarzieKeshavarz Please see the modified answer.
no i need 2 relation but this code that you suggested create 1 relation i need 1 more with different direction
1
  public class User
  {
    [Key]
    public Guid Id {get; set;}       
   // [ForeignKey("ContactId")]
    public virtual ICollection<Contact> Contacts {get; set;}        
   // public Guid? ContactId {get;set;}
  }

The 1-side of a 1-n relation doesn't have a foreign key.

7 Comments

thank you...i tested as you wrote.. but i have one 1-n relation from "contact" to "user" . i need one more relation with reverse side direction too. from "user" to "contact"
You already have Contacts, that's the n. When you also need a special Contact, ie HomeAddress then name it appropriately. Right now it's not clear what the problem is.
some times i need to create 2 way relation... on other table it is OK and works but when i use "icollection" it is go wrong and create relation with opposite direction and if i remove "icollection" it will be right.
You are still not clear. In C# the relations are the navigation (virtual) properties and that is clearly a 2 way street here. What gets generated in SQL depends on 'conventions', there should be 2 primary keys and 1 foreign key in this model.
you are right they can communicate but in my DB if i don't create 2-side relation i can not rich some data ... this is because of some of my foreign keys that can be null and some that can't be null... i just need 2-side relation that one of them is icollection.. if i create this relation every things is well. can i have 2-side 1-n relation with icollection?
|
0

If you need a 1-n relation from User to Contact you need an additional navigation property. To be sure about EF behaviour you can also configure the model. This is an example.

[Table("User78")]
public class User
{
    [Key]
    public int Id { get; set; }
    public virtual ICollection<Contact> Contacts { get; set; }
    public virtual User MyPreferredUser { get; set; }
}

[Table("Contact78")]
public class Contact
{
    [Key]
    public int Id { get; set; }
    public virtual User User { get; set; }
}

public class Context : DbContext
{
    public Context()
    { }

This is the context configuration

    public Context(DbConnection connection)
        : base(connection, true)
    { }

    public DbSet<User> Users { get; set; }
    public DbSet<Contact> Contacts { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .HasMany(_ => _.Contacts)
            .WithOptional(_ => _.User)
            .Map(_ => _.MapKey("UserId"));

        modelBuilder.Entity<User>()
            .HasOptional(_ => _.MyPreferredUser)
            .WithMany()
            .Map(_ => _.MapKey("ContactId"));
    }
}

in this example you cannot navigate from contact to user using the MyPreferredUser relation. If you need so you need to add a new navigation from contact to user (of type ICollection).

This is the DML generated by EF during migration

ExecuteNonQuery==========
CREATE TABLE [Contact78] (
 [Id] int not null identity(1,1)
, [UserId] int null
);
ALTER TABLE [Contact78] ADD CONSTRAINT [PK_Contact78_a31c6496] PRIMARY KEY ([Id])
ExecuteNonQuery==========
CREATE TABLE [User78] (
 [Id] int not null identity(1,1)
, [ContactId] int null
);
ALTER TABLE [User78] ADD CONSTRAINT [PK_User78_a31c6496] PRIMARY KEY ([Id])
ExecuteNonQuery==========
CREATE INDEX [IX_UserId] ON [Contact78] ([UserId])
ExecuteNonQuery==========
CREATE INDEX [IX_ContactId] ON [User78] ([ContactId])
ExecuteNonQuery==========
ALTER TABLE [Contact78] ADD CONSTRAINT [FK_Contact78_User78_UserId] FOREIGN KEY ([UserId]) REFERENCES [User78] ([Id])
ExecuteNonQuery==========
ALTER TABLE [User78] ADD CONSTRAINT [FK_User78_User78_ContactId] FOREIGN KEY ([ContactId]) REFERENCES [User78] ([Id])

Comments

0

Checkout this here i am adding relationship between BlogPost and Category Table

 public class BlogPost
    {
        public Guid Id { get; set; }
        public string Title { get; set; }
        public string ShortDescription { get; set; }
        public string Content { get; set; }
        public string FeaturedImageUrl { get; set; }
        public string UrlHandle { get; set; }
        public DateTime PublishedDate { get; set; }
        public string Author { get; set; }
        public bool IsVisible { get; set; }
        public ICollection<Category> Categories { get; set; }
    }

    public class Category
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
        public string UrlHandle { get; set; }
        public ICollection<BlogPost> BlogPosts { get; set; }
    }

Controller Action Method

[HttpPost]
 public async Task<IActionResult> CreateBlogPost([FromBody] CreateBlogPostRequestDTO createBlogPostRequestDTO)
 {
     var blogPost = new BlogPost
     {
         Title = createBlogPostRequestDTO.Title,
         Author = createBlogPostRequestDTO.Author,
         Content = createBlogPostRequestDTO.Content,
         FeaturedImageUrl = createBlogPostRequestDTO.FeaturedImageUrl,
         IsVisible = createBlogPostRequestDTO.IsVisible,
         PublishedDate = createBlogPostRequestDTO.PublishedDate,
         ShortDescription = createBlogPostRequestDTO.ShortDescription,
         UrlHandle = createBlogPostRequestDTO.UrlHandle,
         Categories = new List<Category>()
     };

     foreach(var item in createBlogPostRequestDTO.Categories)
     {
         var existingCategory = await iCategoryRepo.GetById(item);
         if(existingCategory is not null)
         {
             blogPost.Categories.Add(existingCategory);
         }
     }

     blogPost = await iBlogPostRepo.CreateAsync(blogPost);

     var blogPostDTO = new
     {
         Id = blogPost.Id,
         Title = blogPost.Title,
         Author = blogPost.Author,
         Content = blogPost.Content,
         FeaturedImageUrl = blogPost.FeaturedImageUrl,
         IsVisible = blogPost.IsVisible,
         PublishedDate = blogPost.PublishedDate,
         ShortDescription = blogPost.ShortDescription,
         UrlHandle = blogPost.UrlHandle,
         CategoryDtos = blogPost.Categories.Select(x=> new CategoryDto
         {
             Id = x.Id,
             Name = x.Name,
             UrlHandle = x.UrlHandle
         }).ToList()
     };

     return Ok(blogPostDTO);

 }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.