如何在Entity FrameWork中创建两个表之间的双向关系

问题描述 投票:0回答:4

我有两个表,我想在 EF 中创建从

User
Contact
的 1-n 关系并反转。这意味着我需要与 2 个目的地建立 2 种关系,它们也是基表。 用户类中的
Contact
表应该引入为
ICollection
,所以我的关系出了问题,它们都是一侧。check this picture但是如果我删除
ICollection
,一切都是正确的。

我该如何解决这个问题?

  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;}
  }

如果我删除联系人的外键check this picture

我想要这些表之间再有一种关系,但方向不同。 check this picture

c# entity-framework entity icollection
4个回答
2
投票

有很多方法可以实现这一目标。您可以按照以下方式进行操作

  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;}
  }

你也可以尝试这个方法

  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;}
  }

它包括外键属性

UserId

欲了解更多信息,您可以前往此链接


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

1-n 关系的 1 边没有外键。


0
投票

如果您需要从用户到联系人的 1-n 关系,您需要额外的导航属性。要确定 EF 行为,您还可以配置模型。 这是一个例子。

[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()
    { }

这是上下文配置

    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"));
    }
}

在此示例中,您无法使用 MyPreferredUser 关系从联系人导航到用户。如果需要,您需要添加从联系人到用户(ICollection 类型)的新导航。

这是迁移时EF生成的DML

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])

0
投票

在这里查看我正在添加 BlogPost 和类别表之间的关系

 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; }
    }

控制器动作方法

[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);

 }
© www.soinside.com 2019 - 2024. All rights reserved.