Sql server EF Core错误的join语句

Sql server EF Core错误的join语句,sql-server,entity-framework,asp.net-core,ef-core-2.2,Sql Server,Entity Framework,Asp.net Core,Ef Core 2.2,我在EF Core 2.2中有以下模型类 public class User { [Key] public long Id { get; set; } [ForeignKey("Post")] public long? PostId { get; set; } public virtual Post Post { get; set; } public virtual ICollection<Post> Posts { get; set;

我在EF Core 2.2中有以下模型类

public class User
{
    [Key]
    public long Id { get; set; }
    [ForeignKey("Post")]
    public long? PostId { get; set; }
    public virtual Post Post { get; set; }
    public virtual ICollection<Post> Posts { get; set; }
}

public class Post
{
    [Key]
    public long Id { get; set; }
    [ForeignKey("User")]
    public long UserId { get; set; }
    public virtual User User { get; set; }
}
EF Core生成以下join语句

FROM Posts [p] 
LEFT JOIN Users [p.Users] ON [p].[Id] = [p.Users].[PostId]
我包括来自Post的用户,希望它如下所示

FROM Posts [p]   
LEFT JOIN Users [p.Users] ON [p].[UserId] = [p.Users].[Id]
模型有什么问题

假设我想在用户模型中保存最后一个
posted


是否有一个属性告诉ef core在加入模型时使用哪个属性?

用户和帖子之间的关系是错误的。这应该是您的模型:

public class User
{
    [Key]
    public long Id { get; set; }
    public virtual ICollection<Post> Posts { get; set; }
}

public class Post
{
    [Key]
    public long Id { get; set; }
    [ForeignKey("User")]
    public long UserId { get; set; }
    public virtual User User { get; set; }
}
公共类用户
{
[关键]
公共长Id{get;set;}
公共虚拟ICollection Posts{get;set;}
}
公营职位
{
[关键]
公共长Id{get;set;}
[外键(“用户”)]
公共长用户标识{get;set;}
公共虚拟用户用户{get;set;}
}

这是一对多关系:一个用户可以有许多帖子,而一篇帖子只能有一个用户。

用户和帖子之间的关系是错误的。这应该是您的模型:

public class User
{
    [Key]
    public long Id { get; set; }
    public virtual ICollection<Post> Posts { get; set; }
}

public class Post
{
    [Key]
    public long Id { get; set; }
    [ForeignKey("User")]
    public long UserId { get; set; }
    public virtual User User { get; set; }
}
公共类用户
{
[关键]
公共长Id{get;set;}
公共虚拟ICollection Posts{get;set;}
}
公营职位
{
[关键]
公共长Id{get;set;}
[外键(“用户”)]
公共长用户标识{get;set;}
公共虚拟用户用户{get;set;}
}

这是一对多关系:一个用户可以有许多帖子,而一篇帖子只能有一个用户。

从另一个回复的讨论中,您似乎希望用户包含帖子,但同时也让用户跟踪对最新帖子的引用。EF可以映射这一点,但是您可能需要明确一些关系

例如:

[Table("Users")]
public class User
{
    [Key]
    public int UserId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Post> Posts { get; set; } = new List<Post>();
    public virtual Post LatestPost { get; set; }
}

[Table("Posts")]
public class Post
{
    [Key]
    public int PostId { get; set; }
    public string PostText { get; set; }
    public DateTime PostedAt { get; set; }
    public virtual User User { get; set; }
} 
您可以通过加载用户并将LatestPost引用设置为所需的post来更新“latest”post引用

这个结构存在风险,但是你应该考虑。问题在于,无法可靠地强制(在数据级别)用户中最新的post引用实际引用与该用户关联的post。例如,如果我有一篇指向特定帖子的最新帖子,那么我会从用户的帖子集合中删除该帖子引用,这可能会导致FK约束错误,或者干脆取消帖子与用户的关联,但用户的最新帖子仍然指向该记录。我还可以将其他用户的帖子分配给该用户的最新帖子引用。即

using (var context = new SomethingDbContext())
{
    var user1 = context.Users.Include(x => x.Posts).Include(x => x.LatestPost)
        .Single(x => x.UserId == 1);
    var user1 = context.Users.Include(x => x.Posts).Include(x => x.LatestPost)
        .Single(x => x.UserId == 2);

    var newPost = new Post { PostText = "Test", User = user1 };
    user1.Posts.Add(newPost);
    user1.LatestPost = newPost;
    user2.LatestPost = newPost;
    context.SaveChanges();
}
那就太好了。用户2的“LatestPostId”将被设置为这个新帖子,即使这个帖子的UserId只引用User1

在处理诸如最新帖子之类的内容时,更好的解决方案是不去规范化模式以适应它。相反,在实体中为最新帖子使用未映射属性,或者更好,在需要时依靠投影来检索此数据。在这两种情况下,您都将从用户表中删除LatestPostId

未映射属性:

[Table("Users")]
public class User
{
    [Key]
    public int UserId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Post> Posts { get; set; } = new List<Post>();
    [NotMapped]
    public Post LatestPost 
    {
        get { return Posts.OrderByDescending(x => x.PostedAt).FirstOrDefault(); }
    }
}

使用
Select
进行投影可以检索感兴趣的实体,或者更好,只需将这些实体中的字段返回到展开视图模型或DTO中,以发送到UI或类似的界面。这将导致对数据库进行更高效的查询。使用
Select
检索您不必担心通过
Include
快速加载的详细信息,如果操作正确,将避免延迟加载的陷阱。

从另一个响应的讨论中,您似乎希望用户包含帖子,但也希望用户跟踪对最新帖子的引用。EF可以映射这一点,但是您可能需要明确一些关系

例如:

[Table("Users")]
public class User
{
    [Key]
    public int UserId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Post> Posts { get; set; } = new List<Post>();
    public virtual Post LatestPost { get; set; }
}

[Table("Posts")]
public class Post
{
    [Key]
    public int PostId { get; set; }
    public string PostText { get; set; }
    public DateTime PostedAt { get; set; }
    public virtual User User { get; set; }
} 
您可以通过加载用户并将LatestPost引用设置为所需的post来更新“latest”post引用

这个结构存在风险,但是你应该考虑。问题在于,无法可靠地强制(在数据级别)用户中最新的post引用实际引用与该用户关联的post。例如,如果我有一篇指向特定帖子的最新帖子,那么我会从用户的帖子集合中删除该帖子引用,这可能会导致FK约束错误,或者干脆取消帖子与用户的关联,但用户的最新帖子仍然指向该记录。我还可以将其他用户的帖子分配给该用户的最新帖子引用。即

using (var context = new SomethingDbContext())
{
    var user1 = context.Users.Include(x => x.Posts).Include(x => x.LatestPost)
        .Single(x => x.UserId == 1);
    var user1 = context.Users.Include(x => x.Posts).Include(x => x.LatestPost)
        .Single(x => x.UserId == 2);

    var newPost = new Post { PostText = "Test", User = user1 };
    user1.Posts.Add(newPost);
    user1.LatestPost = newPost;
    user2.LatestPost = newPost;
    context.SaveChanges();
}
那就太好了。用户2的“LatestPostId”将被设置为这个新帖子,即使这个帖子的UserId只引用User1

在处理诸如最新帖子之类的内容时,更好的解决方案是不去规范化模式以适应它。相反,在实体中为最新帖子使用未映射属性,或者更好,在需要时依靠投影来检索此数据。在这两种情况下,您都将从用户表中删除LatestPostId

未映射属性:

[Table("Users")]
public class User
{
    [Key]
    public int UserId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Post> Posts { get; set; } = new List<Post>();
    [NotMapped]
    public Post LatestPost 
    {
        get { return Posts.OrderByDescending(x => x.PostedAt).FirstOrDefault(); }
    }
}

使用
Select
进行投影可以检索感兴趣的实体,或者更好,只需将这些实体中的字段返回到展开视图模型或DTO中,以发送到UI或类似的界面。这将导致对数据库进行更高效的查询。使用
Select
检索您不必担心通过
Include
快速加载的详细信息,如果操作正确,将避免延迟加载带来的陷阱。

关于如何创建模型的这个问题,您已经有了足够的答案,我只想强调一下您班上的错误


你在用户模型中把POSITD当成FK,因此它总是把它看作是用户和帖子之间的关系,你必须删除它,并设计它类似于史提夫所说的类似的东西:P >你在这个问题上有足够的答案来创建模型,我只会强调你的课堂

中的错误。

用户模型中的POSITE作为FK,因此它总是将它视为用户和邮件之间的关系,你必须删除它并设计类似于史提夫

所说的东西:邮政和用户之间的关系是什么?
var userAndPost = context.Users.Where(x => x.UserId == userId)
    .Select(x => new { User = x, LatestPost = x.Posts.OrderByDescending(PostedAt).FirstOrDefault()} ).Single();