避免Linq Select方法中的重复代码

c3frrgcw  于 2023-05-20  发布在  其他
关注(0)|答案(2)|浏览(200)

我有一些愚蠢的情况下,我不能找到简单而优雅的解决恼人的问题。
我写的asp.net应用程序与简单的用户界面查询数据库的基础上用户的选择。用于使用实体框架查询DB I。
在我的场景中,其中一个 * 可选 * 用户选择是自由文本,为此我使用了SQL Server FTS功能(使用CONTAINSTABLE函数,因为我需要按相关性对结果进行排序)。
现在,我有以下情况:
如果用户没有提供自由文本条件,我创建简单的Linq查询,结果类型为IQueriable<Result>(其中'Result'是一个实体,数据来自表)
但是,如果userdid提供了自由文本条件,我将创建CONTAINSTABLE查询,其类型为IQueriable<ResultWithRank>(其中'ResultWithRank'是一个包含两个实体的对象:'Result'和'Rank',因为CONTAINSTABLE导致内部连接)。
在这个阶段,在我构建了我的queriable之后,我需要对它执行“Select”方法,以便将它转换为有用的东西。
问题是:
在第一种情况下,我的select语句看起来像这样:

var result = queryable.Select(entity => /*.. about 20 lines of reshapying code .. */

在第二种情况下,它看起来像这样:

var result = queryable.Select(entity.Result => /*.. about 20 lines of exactly the same reshapying code .. */

我想避免重复的“选择”代码,因为它相同的两种情况。我试图将其移动到外部方法,但这无法执行,因为Linq试图将我的方法转换为SQL,显然失败了。
我怎样才能以某种优雅的方式解决这个问题,而不重复“选择”代码?

kxeu7u2r

kxeu7u2r1#

我会用途:

Expression<Func<Result, Foo>> conversion = result => { ... };

第一例:

var result = queryable.Select(conversion);

第二种情况:

var result = queryable.Select(entity => entity.Result)
                      .Select(conversion);

基本上利用你可以同时执行两个投影的事实,这样你的第一个投影(在第二种情况下)会让你进入你已经处理过的情况。

kx7yvsdv

kx7yvsdv2#

@JonSkeet是正确的,但我为让一切工作做了很多努力。关键是在生成Select之前使用AsQueryable()。你当然可以让它在没有它的情况下工作,但是很有可能你会获取比你实际需要的更多的列。
示例:

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

using var context = new MyDbContext();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();

var blogPostIds = context.Blogs
    .Select(b => new
    {
        BlogId = b.Id,
        PostIds = b.Posts.AsQueryable().Select(Helper.Selector).ToList()
    })
    .ToList();

public static class Helper
{
    public static Expression<Func<Post, int>> Selector
        => x => x.Id;
}

public class MyDbContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer("Data Source=(LocalDb)\\MSSQLLocalDB;Initial Catalog=Selector;Integrated Security=SSPI;")
            .LogTo(Console.WriteLine, LogLevel.Information);
}

public class Blog
{
    public int Id { get; set; }
    public string Title { get; set; }
    public IEnumerable<Post> Posts { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

来源:https://stackoverflow.com/a/76047514/3850405

相关问题