C# 将带有 Case 语句的 SQL 查询转换为 LINQ

Posted

技术标签:

【中文标题】C# 将带有 Case 语句的 SQL 查询转换为 LINQ【英文标题】:C# Convert SQL query with Case statement to LINQ 【发布时间】:2021-07-17 17:34:02 【问题描述】:

我在其中一个表中添加了一个新列,该列的结果取决于其他 2 个列的结果。我进行了更新,以便可以用信息填充现有行,但我还想将 case 语句转换为我的代码的 LINQ 查询。

UPDATE depotProjet.Projets
        SET IdPlateformeSecteur =
            CASE
                WHEN (IdPlateforme = 1 AND IdSecteur = 1) then 1
                WHEN (IdPlateforme = 1 AND IdSecteur = 2) then 2
                WHEN (IdPlateforme = 1 AND IdSecteur = 4) then 3
                WHEN (IdPlateforme = 3 AND IdSecteur = 1) then 4
                WHEN (IdPlateforme = 3 AND IdSecteur = 2) then 5
                WHEN (IdPlateforme = 3 AND IdSecteur = 4) then 6
                WHEN (IdPlateforme = 2 AND IdSecteur = 1) then 7
                WHEN (IdPlateforme = 2 AND IdSecteur = 2) then 8
                WHEN (IdPlateforme = 2 AND IdSecteur = 4) then 9
            
            End
        
        WHERE IdPlateformeSecteur is NULL;  

这就是我想出的:

if (projet.IdPlateforme == 1 && projet.IdSecteur == 1)
            
                projet.IdPlateformeSecteur = 1;
            
            else if (projet.IdPlateforme == 1 && projet.IdSecteur == 2)
            
                projet.IdPlateformeSecteur = 2;
            
            else if (projet.IdPlateforme == 1 && projet.IdSecteur == 4)
            
                projet.IdPlateformeSecteur = 3;
            
            else if (projet.IdPlateforme == 3 && projet.IdSecteur == 1)
            
                projet.IdPlateformeSecteur = 4;
            
            else if (projet.IdPlateforme == 3 && projet.IdSecteur == 2)
            
                projet.IdPlateformeSecteur = 5;
            
            else if (projet.IdPlateforme == 3 && projet.IdSecteur == 4)
            
                projet.IdPlateformeSecteur = 6;
            
            else if (projet.IdPlateforme == 2 && projet.IdSecteur == 1)
            
                projet.IdPlateformeSecteur = 7;
            
            else if (projet.IdPlateforme == 2 && projet.IdSecteur == 2)
            
                projet.IdPlateformeSecteur = 8;
            
            else if (projet.IdPlateforme == 2 && projet.IdSecteur == 4)
            
                projet.IdPlateformeSecteur = 9;
            

我的搜索给了我选择的例子,但我没有选择。它正在工作,但我想以正确的方式做到这一点。谢谢

【问题讨论】:

到目前为止,您发布的只是一堆 If 语句。没有什么关于它的LINQ。您尝试过使用 LINQ 做什么? LINQ 也主要用于选择数据,而不是更新数据,所以你确定你说的是你真正想要的吗?跨度> 我知道我这样做的目的绝不是、塑造或形成 LINQ。我想知道在使用 LINQ 时是否有更雄辩的方式来做我所做的事情?对不起,如果我不清楚。 不是没有看到 if 语句周围的相关代码来获取数据并“更新”它。 对不起,英语不是我的母语,我不确定我理解正确。你还在寻找什么其他代码? 【参考方案1】:

我根据您的 depotProjet.Projet 模型和以下类做了一些假设,但应该足够接近以完成您想要的:

(工作 DotNet Fiddle 的链接:https://dotnetfiddle.net/i2RAx3)

您可以使用Func<int, int, int> 传入IdPlatformeIdSecteurif 语句移出查询(以下使用递归模式匹配并且需要C# 8.0 或更高版本,否则您可以替换它与case 声明):

Func<int, int, int> SetIdPlatformeSecteur = (p, s) =>
    
        int r = (p, s) switch
        

            _ when p == 1 && s == 1 => 1,
            _ when p == 1 && s == 2 => 2,
            _ when p == 1 && s == 4 => 3,
            _ when p == 3 && s == 1 => 4,
            _ when p == 3 && s == 2 => 5,
            _ when p == 3 && s == 4 => 6,
            _ when p == 2 && s == 1 => 7,
            _ when p == 2 && s == 2 => 8,
            _ when p == 2 && s == 4 => 9,
            _ => throw new ArgumentException(message: "Id combination not recognized", paramName: $"p s")

        ;

        return r;
    ;

然后您可以查询您的项目数据库并返回一个匿名类型,其中包括您添加的项目模型中的字段IdPlateformeSecteur,如下所示:

new 
       x.Id, 
       x.IdPlateforme, 
       x.IdSecteur, 
       //...any other properties your model has and want returned
       IdPlateformeSecteur = SetIdPlatformeSecteur(x.IdPlateforme, x.IdSecteur)
    );

下面的完整 LINQPad 示例:

// Demo data to represent what would be in your databaseContext.Projects
List<Project> Projects = 
                        new List<Project> 
                                new Project  Id = 1, IdPlateforme = 1, IdSecteur = 1,
                                new Project  Id = 2, IdPlateforme = 1, IdSecteur = 2,
                                new Project  Id = 3, IdPlateforme = 1, IdSecteur = 4,
                                new Project  Id = 4, IdPlateforme = 3, IdSecteur = 1,
                                new Project  Id = 5, IdPlateforme = 3, IdSecteur = 2,
                                new Project  Id = 6, IdPlateforme = 3, IdSecteur = 4,
                                new Project  Id = 7, IdPlateforme = 2, IdSecteur = 1,
                                new Project  Id = 8, IdPlateforme = 2, IdSecteur = 2,
                                new Project  Id = 9, IdPlateforme = 2, IdSecteur = 4,
                            ;

void Main()
           
                        
    var results = Projects.Select(x => new x.Id, x.IdPlateforme, x.IdSecteur, IdPlateformeSecteur = SetIdPlatformeSecteur(x.IdPlateforme, x.IdSecteur));
    
    results.Dump();


Func<int, int, int> SetIdPlatformeSecteur = (p, s) =>
    
        int r = (p, s) switch
        

            _ when p == 1 && s == 1 => 1,
            _ when p == 1 && s == 2 => 2,
            _ when p == 1 && s == 4 => 3,
            _ when p == 3 && s == 1 => 4,
            _ when p == 3 && s == 2 => 5,
            _ when p == 3 && s == 4 => 6,
            _ when p == 2 && s == 1 => 7,
            _ when p == 2 && s == 2 => 8,
            _ when p == 2 && s == 4 => 9,
            _ => throw new ArgumentException(message: "Id combination not recognized", paramName: $"p s")

        ;

        return r;
    ;

public class Project

    public int Id  get; set; 
    public int IdPlateforme  get; set; 
    public int IdSecteur   get; set; 


                                     

【讨论】:

【参考方案2】:

正如@gun2171 表示这里没有关于LINQ 的内容。

为了清楚起见,您当前的代码似乎很容易阅读和维护。如果使用 C# 8,您可以使用 switch 表达式。思考eloquent,不如想想在几天、几个月或几年后回到代码,你和其他人是否理解这段代码?

Mocked class

public class ProjectItem

    public int IdPlateforme  get; set; 
    public int IdSecteur  get; set; 
    public int IdPlateformeSecteur  get; set; 

Method 在名为 Operations.cs 的类中

private static int SetIdSecteur(ProjectItem sender) => sender.IdPlateforme switch
    
        1 when sender.IdSecteur == 1 => 1,
        1 when sender.IdSecteur == 2 => 2,
        1 when sender.IdSecteur == 4 => 3,
        3 when sender.IdSecteur == 1 => 4,
        3 when sender.IdSecteur == 2 => 5,
        3 when sender.IdSecteur == 4 => 6,
        2 when sender.IdSecteur == 1 => 7,
        2 when sender.IdSecteur == 2 => 8,
        2 when sender.IdSecteur == 4 => 9,
        _ => sender.IdPlateformeSecteur
    ;

用法

var projet = new ProjectItem()  IdPlateforme = 1, IdPlateformeSecteur = 2;

projet.IdSecteur = SetIdSecteur(projet);

编辑

碰巧与 Visual Studio 团队的一位 Microsoft PM 聊天,他们通过使用 C# 8 的元组提供了另一个想法。我对此不以为然,但提出这个替代解决方案似乎是谨慎的。

public static int SetIdSecteur3(ProjectItem sender)
    => (sender.IdPlateforme, sender.IdSecteur) switch
    
        (1, 1) => 1,
        (1, 2) => 2,
        (1, 4) => 3,
        (3, 1) => 4,
        (3, 2) => 5,
        (3, 4) => 6,
        (2, 1) => 7,
        (2, 2) => 8,
        (2, 4) => 9,
        _ => sender.IdPlateformeSecteur
    ;

【讨论】:

以上是关于C# 将带有 Case 语句的 SQL 查询转换为 LINQ的主要内容,如果未能解决你的问题,请参考以下文章

将 SQL CASE WHEN 语句转换为 C#

如何将带有内连接语句的 Sql 查询转换为带有 Where 语句的 sql 查询(语句中没有内连接)

CASE 语句将 NUMBER 转换为 CHAR,但在 Oracle SQL 中保留原始 NUMBER 的 ELSE

带有 CASE 条件和 SUM() 的 SELECT 查询

具有 CASE 和子查询的 sql to LINQ

带有表连接、case 语句、计数、group by 子句的 Linq 查询