views:

2067

answers:

5

In .NET 2.0 (in this case VB), is there a standard API that'll serialize a DataSet object into a stream that can be saved as a tab-delimited file and opened directly in Excel? Or does one have to create the delimited file manually by iterating through the members of the table collection?

In this case, the DataSet's small, consisting of about 10 DataTables, each with between one and a few dozen rows. I'm just wondering whether there's a built-in mechanism for handling this scenario, since I imagine it's a relatively common one.

Ideally, I'd like to be able to return it all in a single click as well -- e.g., the client clicks a Generate Report button, I assemble the report, and return a Response object containing the formatted data, prompting to save or open, etc. (I'd rather not have them download a file and then import it, as that seems a unnecessarily cumbersome usability-wise.)

A: 

DataSet.writeXML(Stream) Then you can import the XML file into Excel

You can also look at this utility to do it for you.

Malfist
Why was I downvoted?
Malfist
@Malfist: According to the tooltip, this answer was apparently not helpful.
Geoffrey Chetwood
It answers the question.
Malfist
@Malfist: What part of the voting process do you not understand?
Geoffrey Chetwood
How was my answer not helpful?
Malfist
@Malfist: What does it matter? 2 people found it not useful, 0 did not. Do you think whining about it will fix anything?
Geoffrey Chetwood
I was asking why it was considered not helpful. It answers the question, and is far simpler than the one that got upvoted. If someone told me why it was downvoted I could improve my answer. I am not whining, just gathering information.
Malfist
I agree that the -1 deserves a comment as it answers the OQ. The OQ did not specify that the output need be a binary XLS, only that it may be opened in Excel.
Richard Szalay
+1 for easiest way by far, and would have been my answer as well
Jason
A: 

Serilize the Dataset to xml DataSet.WriteXML and the you can create an Xsl that transforms it to CSV (you can use XslTransform in order to transform the xml with the xsl)

EDIT: other option is to directly transform it to CSV

Sub DataTable2CSV(ByVal table As DataTable, ByVal filename As String)
    DataTable2CSV(table, filename, vbTab)
End Sub
Sub DataTable2CSV(ByVal table As DataTable, ByVal filename As String, _
    ByVal sepChar As String)
    Dim writer As System.IO.StreamWriter
    Try
        writer = New System.IO.StreamWriter(filename)

        ' first write a line with the columns name
        Dim sep As String = ""
        Dim builder As New System.Text.StringBuilder
        For Each col As DataColumn In table.Columns
            builder.Append(sep).Append(col.ColumnName)
            sep = sepChar
        Next
        writer.WriteLine(builder.ToString())

        ' then write all the rows
        For Each row As DataRow In table.Rows
            sep = ""
            builder = New System.Text.StringBuilder

            For Each col As DataColumn In table.Columns
                builder.Append(sep).Append(row(col.ColumnName))
                sep = sepChar
            Next
            writer.WriteLine(builder.ToString())
        Next
    Finally
        If Not writer Is Nothing Then writer.Close()
    End Try
End Sub

Unless you really want it in pure Excel format

pablito
This is far from the simplest, converting to XML is the simplest. XML can be opened directly in Excel
Malfist
That won't properly quote values with quotes / newlines... but very close ;-p
Marc Gravell
@Malfist: I'm not pretty sure but I believe that not every version of Excel can open xml, correct me if I'm wrong
pablito
the latest version can, I don't know about older one, and the open office equivalent can too
Malfist
+3  A: 

There is an ADO.NET provider for Excel. This means, if you have a dataset, you can employ two DataAdapters to move data from one place to another: from Oracle to Excel, from SQL to Excel, from Excel to Oracle, etc.

Fill a DataSet from the source with the first DA, then Update the destination with the second DA. The DataAdapters do not need to be the same type - you can use any of OleDbDataAdapter, SqlDataAdapter, OracleDataAdapter, etc for the read as well as for the update.

No need to fiddle with CSV or XML formatting. No need to use Office Automation, so no PIAs and it works on Servers. It's just ADO.NET.

To connect to Excel, use the Microsoft.Jet.OLEDB oledb provider.

Full Example source.

Excerpt:

System.Data.DataSet ds1;

const string ConnStringSql= "Provider=sqloledb;Data Source=dinoch-8;Initial Catalog=Northwind;Integrated Security=SSPI;" ;
const string OutputFilename= "ExtractToExcel.xls";

const string ConnStringExcel= 
"Provider=Microsoft.Jet.OLEDB.4.0;" + 
"Data Source=" + OutputFilename + ";" + 
"Extended Properties=\"Excel 8.0;HDR=yes;\"";  // FIRSTROWHASNAMES=1;READONLY=false\"

const string sqlSelect="SELECT top 10 ProductId, ProductName, QuantityPerUnit, UnitPrice, UnitsInStock, GETDATE() as Extracted  from Products order by UnitPrice";
const string sqlInsert="INSERT INTO Extracto (ProductId, ProductName, QuantityPerUnit, UnitPrice, UnitsInStock, Extracted) VALUES (@ProductId, @ProductName, @QuantityPerUnit, @UnitPrice, @UnitsInStock, @Extracted)"; 

private void ReadFromSql()
{
    var ConnSql= new System.Data.OleDb.OleDbConnection(ConnStringSql);

    var da1 = new System.Data.OleDb.OleDbDataAdapter();
    da1.SelectCommand=  new System.Data.OleDb.OleDbCommand(sqlSelect);
    da1.SelectCommand.Connection= ConnSql;

    ds1= new System.Data.DataSet();
    da1.Fill(ds1, "Extracto");
}



private void InsertIntoExcel()
{
    // need to update the row so the DA does the insert...
    foreach (System.Data.DataRow r in ds1.Tables[0].Rows)
    { 
      r["Extracted"]= System.DateTime.Now; // update the row
    }

    var da2 = new System.Data.OleDb.OleDbDataAdapter();

    da2.UpdateCommand= new System.Data.OleDb.OleDbCommand(sqlInsert);
    da2.UpdateCommand.Connection= ConnExcel;

    da2.UpdateCommand.Parameters.Add("@ProductId", System.Data.OleDb.OleDbType.Integer, 4, "ProductId");
    da2.UpdateCommand.Parameters.Add("@ProductName", System.Data.OleDb.OleDbType.VarWChar, 40, "ProductName");
    da2.UpdateCommand.Parameters.Add("@QuantityPerUnit", System.Data.OleDb.OleDbType.VarWChar, 20, "QuantityPerUnit");
    da2.UpdateCommand.Parameters.Add("@UnitPrice", System.Data.OleDb.OleDbType.Currency, 8, "UnitPrice");
    da2.UpdateCommand.Parameters.Add("@UnitsInStock", System.Data.OleDb.OleDbType.SmallInt, 2, "UnitsInStock");
    da2.UpdateCommand.Parameters.Add("@Extracted", System.Data.OleDb.OleDbType.Date, 8, "Extracted");

    da2.Update(ds1, "Extracto");
}

This is not Excel automation, so the caveats that apply to using Excel Automation on the server do not apply.

You can start with a existing XLS file (or XLSX), and just fill in a named range. This gives you the opportunity to apply formatting and so on, prior to inserting the ilve data. In essence the existing XLS file is a template.
Or, you can start from nothing and create the XLS file, and the table/range within the XLS file, completely dynamically, at runtime. In this case the XLS file will be pretty vanilla / plain. No formatting, colors, formulas, and so on.

Cheeso
A: 

You can also create a table in your HTML on your .aspx page using simple HTML table tags (or a gridview) and then in your codebehind include this line in your page.load:

Response.ContentType = "application/vnd.ms-excel"

enjoy :)

Jason
A: 

You could try it with GemBox.Spreadsheet .NET component for reading and writing Excel files.

Here is a great example of importing and exporting DataSet to Excel file.