c# - 如何在单个元素的表达式中使用表达式
问题描述
如何在另一个表达式中使用一个表达式。对于我可以使用的集合blog.Posts.Select(postMapper.ProjectPost)
。但是如何将它用于单个对象?我不想调用编译,我需要在 EF sql 翻译器中使用它。我尝试了一些技巧,new List<Blog>{post.Blog}.Select(blogMapper.ProjectBlog).First()
但它不起作用。
public class BloggingContext : DbContext
{
private readonly ILoggerFactory loggerFactory;
public BloggingContext(ILoggerFactory loggerFactory)
{
this.loggerFactory = loggerFactory;
}
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseLoggerFactory(loggerFactory).UseSqlServer(@"Server=(LocalDB)\MSSqlLocalDb;Database=EFExpressionMapper;Trusted_Connection=True");
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; } = new List<Post>();
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
class Program
{
static async Task Main(string[] args)
{
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddLogging(builder => builder
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)
);
var loggerFactory = serviceCollection.BuildServiceProvider().GetService<ILoggerFactory>();
await using var dbContext = new BloggingContext(loggerFactory);
dbContext.Add(new Blog
{
Url = "http://blogs.msdn.com/sample-blog",
Posts =
{
new Post {Title = "Post 1", Content = "Post 1 content"},
new Post {Title = "Post 2", Content = "Post 2 content"},
new Post {Title = "Post 3", Content = "Post 3 content"},
}
});
await dbContext.SaveChangesAsync();
var postMapper = new PostMapper(new BlogMapper());
var posts = await dbContext.Posts.Select(postMapper.ProjectPost).ToArrayAsync();
foreach (var post in posts)
{
Console.WriteLine($"{post.Title} {post.Blog.Url}");
}
}
}
public class PostMapper
{
public Expression<Func<Post, PostDto>> ProjectPost { get; }
public PostMapper(BlogMapper blogMapper)
{
//TODO USE blogMapper.ProjectBlogList WITHOUT COMPILE
ProjectPost = post => new PostDto(post.PostId, post.Title, post.Content, blogMapper.ProjectBlogList.Compile()(post.Blog));
}
}
public class BlogMapper
{
public Expression<Func<Blog, BlogListDto>> ProjectBlogList { get; } = blog => new BlogListDto(blog.BlogId, blog.Url);
}
public class BlogListDto
{
public int BlogId { get; }
public string Url { get; }
public BlogListDto(int blogId, string url)
{
BlogId = blogId;
Url = url;
}
}
public class PostDto
{
public int PostId { get; }
public string Title { get; }
public string Content { get; }
public BlogListDto Blog { get; }
public PostDto(int postId, string title, string content, BlogListDto blog)
{
PostId = postId;
Title = title;
Content = content;
Blog = blog;
}
}
查看 PostMapper 构造函数。我在那里使用了编译方法。但是对EF不好
解决方案
实际上LINQKit
可能会更正您的查询并使 EF 在使用Compile
. 只需添加AsExpandable()
到您的查询。
但我建议不要为每个 DTO 创建映射类,而是将它们收集在逻辑一个中:
public static class DtoMapper
{
[Expandable(nameof(AsDtoPost))]
public static PostDto AsDto(this Post post)
=> throw new NotImplementedException();
[Expandable(nameof(AsDtoBlogList))]
public static BlogListDto AsDto(this Blog blog)
=> throw new NotImplementedException();
static Expression<Func<Post, PostDto>> AsDtoPost()
=> post => new PostDto(post.PostId, post.Title, post.Content, post.Blog.AsDto()));
static Expression<Func<Blog, BlogListDto>> AsDtoBlogList()
=> blog => new BlogListDto(blog.BlogId, blog.Url);
}
所以你的样本可以重写
var posts = await dbContext.Posts
.AsExpandable()
.Select(p => p.AsDto()).ToArrayAsync();
类似但之前已经创建了答案,其中涵盖了执行相同 lambda 表达式扩展的其他库。https://stackoverflow.com/a/66386142/10646316 这个答案侧重于 LINQKit 实现。
推荐阅读
- html - 角度升级后 class="js-dropdown" 和 class="js-dropdown-menu" 坏了
- css - heroku 部署后的空 css
- reactjs - 升级到 Babel 7 后的错误
- python - 如何解析熊猫中不规则的日期格式?
- javascript - 带有时区的时刻 toDate 没有给出正确的时间
- javascript - 我有一个用于图像和 youtube 视频的 javascript 轮播,但在播放一个视频后它会中断。哪部分功能导致了这种情况?
- r - 附近观测值的总和
- r - Rcmd 检查:我从未使用过的“:::”调用导入的未导出对象
- ruby-on-rails - 将 Rails 推到 Heroku,找不到 Rake taks
- sql - 转义奇数个撇号?