Sql server EF Core错误的join语句
我在EF Core 2.2中有以下模型类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;
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();