问题 linq中的switch语句


我使用linq进行sql连接的代码是:

var query1 = from u in dc.Usage_Computers
          where u.DomainUser == s3
          select u; // selects all feilds from table

GridView1.DataSource = query1;
GridView1.DataBind();

我在“Domainuser”表中有一个名为“Operation”的字段,其值为“1,2,3”。当我将这些值填充到数据网格时,我想将它们转换为有意义的值,如果Operation的值为1,则在datagrid中显示为“logon”,如果为2,则“logoff”等...

从数据库中检索后如何为它们分配值?


5938
2017-10-16 19:28


起源

可能重复 linq案件陈述 - Ryan Gates


答案:


这种技术似乎并不特别适用于您的问题,但无论如何它都在这里。

您可以使用C#在LinqToSql中创建SQL case语句 ? : 运营商。

var query1 =
  from u in dc.Usage_Computers
  where u.DomainUser == s3
  select new {usage = u, 
    operation =
      u.DomainUser.Operation == 1 ? "login" :
      u.DomainUser.Operation == 2 ? "logoff" :
      "something else"
  };

13
2017-10-16 20:00



为什么人们希望数据库将int转换为标签字符串,我永远不会知道。看起来像是网络服务器的工作。 - Amy B
谢谢大卫!你的方法适合我!
虽然解决方案回答了这个问题,但我认为像这样撒上转换逻辑是一种不好的做法。这种转换逻辑应该集中到一个可重用的类中。 - Samuel Kim
大卫,如果有机会在Web服务器或数据库中执行这样的简单转换,您可以考虑哪个引擎已经负载最小,并在那里进行转换。通常,数据库服务器中有更多的CPU可用。 - DOK
这与CPU可用性无关。所有这些逻辑都必须通过一堆参数传输到数据库中。然后,数据库必须在它可以发送回的整数时发回字符串(请求和响应的网络占用空间较小)。这样做就像将刀片安装在自行车的辐条上,然后骑在草地上割草坪。这项工作的错误工具,即使它有效。 - Amy B


在gridview中使用模板字段:

<asp:GridView ID="gvDomain" runat="server" OnRowDataBound="gvDomain_RowDataBound">
    <Columns>
        <asp:TemplateField>
             <HeaderTemplate>
                 Operation
             </HeaderTemplate>
             <ItemTemplate>
                 <asp:Label id="lblLogon" runat="server" />
             </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

然后使用gridviews RowDataBound事件来发现标签并分配其文本:

Protected Sub gvDomain_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvStates.RowDataBound
    Dim lblLogon As Label = DirectCast(e.Row.FindControl("lblLogon"), Label)
    Dim drv As DataRowView = DirectCast(e.Row.DataItem, DataRowView)

    If lblLogon IsNot Nothing Then
        Select Case drv("Operation").ToString()
            Case "1" 
                lblLogon.Text = "Logon"
                Break
            Case "2"
                lblLogon.Text = "Logoff"
                Break
            //etc...
        End Select
    End If
End Sub

2
2017-10-16 19:50





static Func<int?, string> MapSqlIntToArbitraryLabel = (i =>
{
   // for performance, abstract this reference 
   //  dictionary out to a static property
   Dictionary<int, string> labels = new Dictionary<int, string>();
   labels.Add(1, "logon");
   labels.Add(2, "logoff");
   labels.Add(...);

   if (i == null) throw new ArgumentNullException();
   if (i < 1 || i > labels.Count) throw new ArgumentOutOfRangeException();

   return labels.Where(x => x.Key == i.Value)
                .Select(x.Value)
                .Single();
}

return语句也可以表示为:

return (from kvp in labels
        where kvp.Key == i.Value
        select kvp.Value).Single();

然后你可以使用你的linq查询中的函数调用,如下所示:

var query1 = from u in dc.Usage_Computers 
             where u.DomainUser == s3 
             select {
                 Operation = MapSqlIntToArbitraryLabel(u.Operation)
                 // add other properties to this anonymous type as needed
             };

我已经尝试了所有建议的方法来愚弄Linq2Sql来运行我的代码,这个方法是我发现的唯一一个允许我运行代码作为延迟执行投影的一部分。


1
2017-10-16 19:59



虽然我总体上同意这种方法(+1),但认为它有点矫枉过正。一个简单的字典就足够了(并提供更好的性能)。也应该只初始化一次。只有其他方面是考虑使翻译方法成为对象的扩展方法。 - Samuel Kim
对象的扩展方法是我的第一次尝试,但我发现这种方法很好地概括 - 即,从MapSqlIntToArbitraryLabel()中你可以调用一个Linq2Sql无法识别的方法,它似乎运行时没有窒息“没有翻译到sql“问题。 - David Alpert


我使用TemplateFields做了类似的事情。使用ASP:标签绑定到属性并为控件添加OnPreRender事件处理程序。在控件的事件处理程序中,我根据文本的当前值翻译文本并设置新值:

protected void label_OnPreRender( object sender, EventArgs e )
{
   Label l = (Label)sender;
   switch (l.Text) {
      case "1":
         l.Text = "Logon";
         break;
       ...
      default:
         break;
   }
}

如果表单处于编辑模式,则需要以不同方式处理它。您还可能需要将用于插入和更新的处理程序添加到用于将页面提供的数据转换为其数据库表示形式的View控件。


0
2017-10-16 19:33