4

I have this code, which compiles fine in VB.NET:

Imports System
Imports System.Data
Imports System.Data.Entity
Imports System.Data.SqlClient
Imports System.Linq
Imports System.Collections
Imports System.Collections.Generic

Friend Module MainModule
    Friend Sub Main(args As String())
        Dim ds = GetSqlDataSet("", "")
        Dim allRows = From row In ds.Tables(0) Select row
    End Sub

    Private Function GetSqlDataSet(ByVal forQuery As String,
                                   ByVal withConnectionString As String,
                                   ByVal ParamArray withParameters As SqlClient.SqlParameter()) As DataSet

        GetSqlDataSet = New DataSet()

        Using conn As New System.Data.SqlClient.SqlConnection(withConnectionString)
            Using command As New System.Data.SqlClient.SqlCommand(forQuery, conn)
                command.Parameters.AddRange(withParameters)

                Using dataAdaptor As New System.Data.SqlClient.SqlDataAdapter(command)
                    dataAdaptor.Fill(GetSqlDataSet)
                End Using
            End Using
        End Using
    End Function
End Module

Here are the references:

enter image description here

Now I have what looks like an exact equivalent in C#:

using System;
using System.Data;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    internal static class MainEntryPoint
    {
        internal static void Main(string[] args)
        {
            var ds = GetSqlServerDataSet("", "");
            var allRows = from row in ds.Tables[0] select row;
        }

        public static System.Data.DataSet GetSqlServerDataSet(string usingQuery, 
            string usingConnectionString, params System.Data.SqlClient.SqlParameter[] withParameters)

        {
            var ret = new System.Data.DataSet();

            using (var conn = new System.Data.SqlClient.SqlConnection(usingConnectionString))
            {
                using (var command = new System.Data.SqlClient.SqlCommand(usingQuery, conn))
                {
                    command.Parameters.AddRange(withParameters);

                    using (var adapter = new System.Data.SqlClient.SqlDataAdapter(command))
                    {
                        adapter.Fill(ret);
                    }
                }
            }

            return ret;
        }
    }
}

And here are the references:

enter image description here

But I'm getting this error:

enter image description here

I've found numerous resources that speak of adding a reference/using statements for System.Linq and also System.Data.Entity, but obviously I have those in both cases. Can someone please help me shed some light on this? Why is it working in VB.NET and not C#, and how do I get it to work in C#?

Community
  • 1
  • 1
rory.ap
  • 34,009
  • 10
  • 83
  • 174
  • @RahulSingh -- that doesn't help explain why it works in VB and not in C#. Why do I need to use `AsEnumerable`? – rory.ap Nov 18 '15 at 15:45
  • [This one](http://stackoverflow.com/a/1586023/2704659) says I should be able to use it as I've used it without `AsEnumerable()` – rory.ap Nov 18 '15 at 15:46
  • Hey sorry, completely got it wrong. – Rahul Singh Nov 18 '15 at 15:47
  • 2
    @RahulSingh: No, you didn't. That other question is talking about LINQ to SQL, not datatables. – Jon Skeet Nov 18 '15 at 15:49
  • DataTable is not emplementing Enumerable so You have to call AsEnumerable() - the link you provided doesn't operate on DataTable's it operates on POCO's. I also don't know why it worked in vb – MajkeloDev Nov 18 '15 at 15:49
  • 2
    You need `AsEnumerable()` because `DataTable` doesn't implement `IEnumerable` or `IQueryable`. I don't know why it's working in VB without that, but you *do* need it in C#. – Jon Skeet Nov 18 '15 at 15:50
  • @JonSkeet - Oops yes thanks! But I got more confused cz it is working in VB and I have no clue about it :) – Rahul Singh Nov 18 '15 at 15:50
  • As written, this `GetSqlServerDataSet()` method will force you to write horribly insecure code that leaves you wide open to sql injection attacks. You need a mechanism to accept parameter data for your sql separate from the sql command string. – Joel Coehoorn Nov 18 '15 at 15:51
  • @JonSkeet -- so `TableA` [here](http://stackoverflow.com/questions/1586013/how-to-do-select-all-in-linq-to-sql/1586023#1586023) is not a `DataTable`? – rory.ap Nov 18 '15 at 15:51
  • @JoelCoehoorn -- I've left out the parameters. Created as a [MCVE](http://stackoverflow.com/help/mcve) – rory.ap Nov 18 '15 at 15:53
  • 1
    @roryap: No, it's not. The question is about LINQ to SQL, which doesn't typically use DataTables. – Jon Skeet Nov 18 '15 at 15:54
  • @JoelCoehoorn -- In fact, I literally *deleted* everything related to parameters from the code I had when creating the example because this question isn't actually about the database side of things. Should I have left that in for posterity? – rory.ap Nov 18 '15 at 15:55
  • Good to know you're doing right. One of the nice things about Stack Overflow is that it's good at creating _artifacts_ that later turn into examples for other programmers. Artifacts from MCVE's that lead others into bad, insecure practices are a problem. There's no need to edit your question over this, but at a minimum comments about this kind of thing are important so others won't use emulate this without adding their own code of query parameters. – Joel Coehoorn Nov 18 '15 at 15:57
  • @JoelCoehoorn -- Thanks, I've edited my question anyway. – rory.ap Nov 18 '15 at 16:06

2 Answers2

9

It looks like VB has built-in support for DataTable. Here's a short but complete example:

Option Strict On

Imports System
Imports System.Data
Imports System.Linq

Public Class LinqTest

    Shared Sub Main()
        Dim table as DataTable = New DataTable
        Dim allRows = From row In table Select row
    End Sub

End Class

If you compile that and then use ildasm on it, you'll find it's calling DataTableExtensions.AsEnumerable() automatically. I wouldn't like to speculate about where that's specified in VB, but it's not part of what C# does automatically. Just do it explicitly in your C# code.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
1

You should be good if you just changed

var allRows = from row in ds.Tables[0] select row;

to:

var allRows = from row in ds.Tables[0].AsEnumerable() select row;

Evidently, VB is doing it implicitly but C# needs you to do it explicitly.

The reason is that DataSet.Tables is of type DataTableCollection which does not implement IEnumerable hence an explicit AsEnumerable() is needed.

Please let me know if it helped!!!

Manish Kumar
  • 362
  • 1
  • 9