EF - 在一对多内部的一对多关系(Facebook帖子/反应)

时间:2018-03-19 06:28:03

标签: c# .net entity-framework ado

我有以下实体:

public class User
{
    public User()
    {
        UserName = new Name();
        UserEmail = new Email();
    }

    [Key]
    public int Gid { get; set; }
    public Name UserName { get; set; }
    public Email UserEmail { get; set; }

    public virtual ICollection<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public int UserId { get; set; }
    public string Content { get; set; }
    public string ImageUri { get; set; }

    public virtual User Author { get; set; }
}

public class Reaction
{
    public int ReactionId { get; set; }
    public string Text { get; set; }
    public string IconUri { get; set; }
}

一个用户可以拥有多个帖子,一个帖子可以有多个个帖子。 问题是反应应该存储对其帖子的引用和响应的用户。我可以在用户和帖子之间建立一对多的关系。

如何使用Entity Framework映射此关系?

1 个答案:

答案 0 :(得分:3)

在最后评论后添加

如果您按照the entity framework code-first conventions获得一对多关系,则不必添加任何属性,也不必使用流畅的API来告诉实体框架您想要什么。

只有当您需要不同的表名,属性类型,列名或其他关于表之间关系的专业时,您才需要属性或流畅的API。

您的问题是由于您在类定义

中忽略了一些一对多定义而引起的

您的用户:

public class User
{
    public int Id { get; set; }

    // every user has zero or more Posts (one-to-many)
    public virtual ICollection<Post> Posts { get; set; }

    ...
}

邮报:

public class Post
{
    public int Id { get; set; }

    // every Post belongs to exactly one User using foreign key
    public int UserId { get; set; }
    public virtual Post Post {get; set;}

    // every Post has zero or more Reactins (one-to-many)
    public virtual IColleciton<Reaction> Reactions {get; set;}

    ...   
}

对这篇文章的反应:

public class Reaction
{
    public int Id { get; set; }

    // every Reaction belongs to exactly one Post using foreign Key:
    public int PostId {get; set;}
    public virtual Post Post {get; set; }

    ...
}

最后你的DbContext:

public MyDbContext : DbContext
{
    public DbSet<User> Users {get; set;}
    public DbSet<Post> Posts {get; set;}
    public DbSet<Reaction> Reactions {get; set;}
}

实际上,实际上只需要了解您希望一对多关系并找出哪些属性应该成为外键的实体框架。实体框架也理解你没有帖子就没有反应。如果您尝试删除帖子,其所有反应都将被删除。

我更改了一些项目,使其更符合代码优先修复。

  • 正确的多元化。一个Post,多个Posts
  • 所有ID都命名为Id(尽管您的ID也符合惯例)。我使用它,所以每个类总是清楚主键是什么,即使类改变名称。
  • 所有不会成为列的项目(如ICollections)都是虚拟的
  • 所有一对多都有一个根据约定具有属性名称的外键
  • 没有类具有实例化成员的构造函数。毕竟,如果你进行查询,成员将被实例化并立即被查询结果取代

ICollections的一个优点是,如果你想要一个User-with-his-Posts,你不需要在外键上使用相当困难的左外连接。

要让所有老用户拥有他们的全部或部分帖子,您可以使用ICollection。实体框架将在适当的左外连接中为您翻译:

var oldUsersWithManyReactions = myDbContext.Users
    .Where(user => user.BirthDay < new DateTime(2040, 1, 1))
    .Select(user => new 
    {
        // Select only the user properties you plan to use
        Id = user.Id,
        FullName = user.Name.First + User.Name.Last,

        // select the Posts of this User:
        RecentPosts = user.Posts
            .Where(post.PublicationDate > DateTime.UtcNow.AddDay(-7))
            .Select(post => new
            {
                // again select only the Properties you want to use:
                Title = post.Title,
                PublicationDate = post.PublicationDate,
                ReactionCount = post.Reactions.Count(),
            }),
        }),
    }),
});

评论后添加

如果您想要“使用所有反应的用户”,请使用SelectMany。这实际上是一个LINQ问题,与Entity-Framework

无关
var usersWithAllTheirReactions = myDbContext.Users
    .Where (user => ...)
    .Select(user => new
    {
        Id = user.Id,
        Name = ...,

        AllReactions = user.Posts
            .SelectMany(post => post.Reactions)
            .Where(reaction => ...)
            .Select(reaction => new
            {
                ReactionDate = reaction.Date,
                Text = reaction.Text,
            }),
        }),
    });