WebMethod failure - c#

I have the following webmethod on a asmx page that will not connect to my database. Can anyone shed any light on where I have gone wrong.
[WebMethod]
public int[] getEmployeeIDs()
{
Connection conn = new Connection();
Recordset rs = new Recordset();
conn.ConnectionString = "Data Source=MyWebBasedServer;Initial Catalog=MyDatabase;Persist Security Info=False;User ID=MyLogin;Password=MyPassword";
rs.Open("SELECT ID from MyTable", conn, CursorTypeEnum.adOpenStatic);
int[] ID = new int[rs.RecordCount];
int i = 0;
while (!rs.EOF)
{
ID[i++] = rs.Fields["ID"].Value;
rs.MoveNext();
}
rs.Close();
conn.Close();
return ID;
}
Error message I get is
The connection cannot be used to perform this operation. It is either
closed or invalid in this context. (Pointing to "int[] ID = new
int[rs.RecordCount];")
Thanks.

The code below shows two common ways to retrieve a result set from a SELECT statement in ADO.Net.
There's a website called ConnectionStrings.com that shows all the various ways to connect to SQL Server, along with many other kinds of databases.
If you're new to C# programming, the using statement is a great way to avoid resource leaks when handling objects that implement IDisposable.
Returning complex types from a WebMethod might result in an error. The method's underlying XML serializer might not know how to handle certain types. In that case, XmlIncludeAttribute can be used to provide explicit type information. Here's an MSDN thread discussing how to go about that.
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web.Services;
namespace ConsoleApplication19
{
public class Program
{
public static void Main(String[] args)
{
var connectionString = "Data Source=MyWebBasedServer;Initial Catalog=MyDatabase;Persist Security Info=False;User ID=MyLogin;Password=MyPassword;";
var a = GetEmployeeIDs_Version1(connectionString);
var b = GetEmployeeIDs_Version2(connectionString);
}
/* Version 1
Use a "while" loop to fill a WebData list and return it as an array. */
[WebMethod]
private static WebData[] GetEmployeeIDs_Version1(String connectionString)
{
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var commandText = "SELECT ID, SurName from MyTable";
using (var command = new SqlCommand() { Connection = connection, CommandType = CommandType.Text, CommandText = commandText })
{
using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
var result = new List<WebData>();
while (reader.Read())
result.Add(new WebData() { ID = Convert.ToInt32(reader["ID"]), Surname = reader["Surname"].ToString() });
return result.ToArray();
}
}
}
}
/* Version 2
Fill a DataSet with the result set.
Because there's only one SELECT statement, ADO.Net will
populate a DataTable with that result set and put the
DataTable in the dataset's Tables collection.
Use LINQ to convert that table into a WebData array. */
[WebMethod]
private static WebData[] GetEmployeeIDs_Version2(String connectionString)
{
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var commandText = "SELECT ID, SurName from MyTable";
using (var command = new SqlCommand() { Connection = connection, CommandType = CommandType.Text, CommandText = commandText })
{
using (var adapter = new SqlDataAdapter())
{
var dataSet = new DataSet();
adapter.SelectCommand = command;
adapter.Fill(dataSet);
return
dataSet
// There should only be one table in the dataSet's Table's collection.
.Tables[0]
.Rows
// DataTable isn't LINQ-aware. An explicit cast is needed
// to allow the use of LINQ methods on the DataTable.Rows collection.
.Cast<DataRow>()
// The rows in a DataTable filled by an SqlDataAdapter
// aren't strongly typed. All of a row's columns are
// just plain old System.Object. Explicit casts are necessary.
.Select(row => new WebData() { ID = Convert.ToInt32(row["ID"]), Surname = row["Surname"].ToString() })
// Use LINQ to convert the IEnumerable<WebData> returned by
// the .Select() method to an WebData[].
.ToArray();
}
}
}
}
}
public class WebData
{
public Int32 ID { get; set; }
public String Surname { get; set; }
}
}

Related

Loop on field change C#

I'm trying to write some code to loop through a data range and add new documents to SAP based on a query input. I need the values to be added to the documents based on the supplier field and when the supplier changes create a new document. Currently I am only able to loop through adding items to the document and rather than moving to the next supplier it just loops the items again. I'm pretty new to C# so looping is pretty new to me but hoping someone can help?
int recordCount = oRecordset.RecordCount;
string Supplier = oRecordset.Fields.Item(1).Value.ToString();
string Item = oRecordset.Fields.Item(0).Value.ToString();
Qty = Convert.ToInt32(oRecordset.Fields.Item(3).Value.ToString());
if(recordCount>0)
application.MessageBox("Adding PQ");
System.Threading.Thread.Sleep(2);
{
for(int i = 0; i < recordCount; i++)
{
OPQT.CardCode = Supplier ;
OPQT.DocDate = DateTime.Now;
OPQT.DocDueDate = DateTime.Now;
OPQT.RequriedDate = DateTime.Now;
OPQT.Lines.ItemCode = Item;
OPQT.Lines.RequiredQuantity = Qty;
OPQT.Lines.Add();
oRecordset.MoveNext();
}
OPQT.Add();
application.MessageBox("PQ Added");
}
You'd be much better of starting to learn with SqlDataReader, IMO.
Adapting to your business case you'd get something like this, this is not working code, I don't have enough info for that. However this should help you progress in the right direction.
using System;
using System.Data;
using System.Data.SqlClient;
class Program
{
static void Main()
{
string connectionString = "Data Source=(local);Initial Catalog=...";
ReadOData( connectionString);
}
private static IEnumerable<OPQT> ReadOrderData(string connectionString)
{
string queryString =
#"
SELECT
T0.[ItemCode],
T0.[CardCode],
'10' [Qty]
FROM
[OSCN] T0
JOIN
[OCRD] T1
ON T0.[CardCode] = T1.[CardCode]
WHERE
T1.[CardType] ='S'";
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlCommand command =
new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
try
{
// Call Read before accessing data.
while (reader.Read())
{
yield return ReadSingleRow((IDataRecord)reader);
}
}
finally
{
// Call Close when done reading.
reader.Close();
}
}
}
private static OPQT ReadSingleRow(IDataRecord dataRecord)
{
return new OPQT
{
Lines.ItemCode = dataRecord[0],
CardCode = dataRecord[1],
Lines.RequiredQuantity = dataRecord[2]
};
}
}

How to return results from SQL SELECT raw Query?

I have a method in my controller class that is supposed to return the results from a raw SQL query inside the method. The problem is I can't pull return more than one column result to the list in a query that is supposed to return multiple column results.
I know that the problem has to do with how I am adding to the results list during the Read, but I am unsure how to structure this properly to return multiple values.
Here is my current method:
public IActionResult Search ([FromRoute]string input)
{
string sqlcon = _iconfiguration.GetSection("ConnectionStrings").GetSection("StringName").Value;
List<string> results = new List<string>();
using (var con = new SqlConnection(sqlcon))
{
using (var cmd = new SqlCommand()
{
CommandText = "SELECT u.UserID, u.User FROM [dbo].[Users] u WHERE User = 'Value';",
CommandType = CommandType.Text,
Connection = con
})
{
con.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
results.Add(reader.GetString(0));
}
con.Close();
return Ok(new Search(results));
}
}
}
}
The SQL query is supposed to return the UserID and User based on the entered User, however, only the User gets returned here.
Does anyone know what I am missing to return multiple column names for this SQL query and method? Any advice would be greatly appreciated.
FYI, I can't use a stored procedure here, I do not have permission to create an SP on this database.
You can create a class for the results of the Query
public class ClassForResults(){
public int UserID { get; set; };
public string User { get; set; }
}
public IActionResult Search ([FromRoute]string input)
{
string sqlcon = _iconfiguration.GetSection("ConnectionStrings").GetSection("StringName").Value;
List<ClassForResults> results = new List<ClassForResults>();
using (var con = new SqlConnection(sqlcon))
{
using (var cmd = new SqlCommand()
{
CommandText = "SELECT u.UserID, u.User FROM [dbo].[Users] u WHERE User = 'Value';",
CommandType = CommandType.Text,
Connection = con
})
{
con.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
ClassForResults result = new ClassForResults();
result.UserID = reader.GetInt(0);
result.User = reader.GetString(1);
results.Add(result);
}
con.Close();
return Ok(new Search(results));
}
}
}
}

How to copy MySqlDataReader into an array and then loop throught the array?

I am new to C# so yes this should be a faily easy question but I can't seem to find the answer to it.
I have a method that query a database.
What I am trying to do here is handle the loop though the data outside the method.
public MySqlDataReader getDataSet(string query)
{
MySqlDataReader dataset = null;
MySqlConnection conn = new MySqlConnection(conn_string);
if (startConnection(conn) == true)
{
MySqlCommand cmd = new MySqlCommand(query, conn);
dataset = cmd.ExecuteReader();
closeConnection(conn);
}
return dataset;
}
what I could do is write a while loop just before the closeConnection(conn); line and handle the data. But, I don't want to do it inside this method and I want to do it somewhere else in my code.
In one of my forms I want to read the database on the load so here is what I tried to do
public newDepartment()
{
InitializeComponent();
inputDepartmentName.Text = "Hi";
dbConnetion db = new dbConnetion();
MySqlDataReader ds = db.getDataSet("SELECT name FROM test;");
while (ds.Read())
{
//Do Something
}
}
The problem that I am having is that I get an error Invalid attempt to Read when reader is closed
Which I belive I get this issue because I close the connection and then I am trying to read it. so What I need to do is read the data from the query and put it in an array and then loop through the array and deal with the data in a different form.
How can I workaround this issue? if my idea is good then how can I copy the data into an array and how do I loop though the array?
Here is the full class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;
using System.Windows.Forms;
namespace POS
{
public class dbConnetion
{
//private OdbcConnection conn;
private readonly string mServer;
private readonly string mDatabase;
private readonly string mUid;
private readonly string mPassword;
private readonly string mPort;
private readonly string conn_string;
public dbConnetion()
{
mServer = "localhost";
mDatabase = "pos";
mUid = "root";
mPassword = "";
mPort = "3306";
conn_string = String.Format("server={0};user={1};database={2};port={3};password={4};", mServer, mUid, mDatabase, mPort, mPassword);
}
//Start connection to database
private bool startConnection(MySqlConnection mConnection)
{
try
{
mConnection.Open();
return true;
}
catch (MySqlException ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK);
return false;
}
}
//Close connection
private bool closeConnection(MySqlConnection mConnection)
{
try
{
mConnection.Close();
return true;
}
catch (MySqlException ex)
{
MessageBox.Show(ex.Message);
return false;
}
}
public MySqlDataReader getDataSet(string query)
{
MySqlDataReader dataset = null;
MySqlConnection conn = new MySqlConnection(conn_string);
if (startConnection(conn) == true)
{
MySqlCommand cmd = new MySqlCommand(query, conn);
dataset = cmd.ExecuteReader();
closeConnection(conn);
}
return dataset;
}
public void processQuery(string strSQL, List<MySqlParameter> pars)
{
MySqlConnection conn = new MySqlConnection(conn_string);
if (startConnection(conn) == true)
{
MySqlCommand cmd = new MySqlCommand(strSQL, conn);
foreach (MySqlParameter param in pars)
{
cmd.Parameters.Add(param);
}
cmd.ExecuteNonQuery();
closeConnection(conn);
}
}
}
}
Putting the records into an array would destroy the best feature of a using a datareader: that you only need to allocate memory for one record at a time. Try doing something like this:
public IEnumerable<T> getData<T>(string query, Func<IDataRecord, T> transform)
{
using (var conn = new MySqlConnection(conn_string))
using (var cmd = new MySqlCommand(query, conn))
{
conn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return transform(rdr);
}
}
}
}
While I'm here, there's a very serious security flaw with this code and the original. A method like this that only accepts a query string, with no separate mechanism for parameters, forces you to write code that will be horribly horribly vulnerable to sql injection attacks. The processQuery() method already accounts for this, so let's extend getDataset() to avoid that security issue as well:
public IEnumerable<T> getData<T>(string query, List<MySqlParameter> pars, Func<IDataRecord, T> transform)
{
using (var conn = new MySqlConnection(conn_string))
using (var cmd = new MySqlCommand(query, conn))
{
if (pars != null)
{
foreach(MySqlParameter p in pars) cmd.Parameters.Add(p);
}
conn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return transform(rdr);
}
}
}
}
Much better. Now we don't have to write code that's just asking to get hacked anymore. Here's how your newDepartment() method will look now:
public newDepartment()
{
InitializeComponent();
inputDepartmentName.Text = "Hi";
dbConnetion db = new dbConnetion();
foreach(string name in db.getDataSet("SELECT name FROM test;", null, r => r["name"].ToString() ))
{
//Do Something
}
}
One thing about this code is that is uses a delegate to have you provide a method to create a strongly-typed object. It does this because of the way the datareaders work: if you don't create a new object at each iteration, you're working on the same object, which can have undesirable results. In this case, I don't know what kind of object you're working with, so I just used a string based on what your SELECT query was doing.
Based on a separate discussion, here's an example of calling this for a more complicated result set:
foreach(var item in db.getDataSet(" long query here ", null, r =>
new columnClass()
{
firstname = r["firstname"].ToString(),
lastname = r["lastname"].ToString(),
//...
}
) )
{
//Do something
}
Since you are new to .Net I thought I point out that there are two layers of database access in ADO.Net. There are the data reader way that you are using and all of that is online only forward reading of queries. This is the lowest level access and will give you the best performance but it is more work. For most connection types you can only execute one command or have one active data reader per connection (And you can't close the connection before you have read the query as you are doing).
The other form is the offline data adapter and requires just a little bit different code, but is generally easier to use.
public DataTable getDataSet(string query)
{
MySqlConnection conn = new MySqlConnection(conn_string);
if (startConnection(conn) == true)
{
MySqlDataAdapter adapter = new MySqlDataAdapter(query, conn);
DataTable table = new DataTable();
adapter.Fill(table);
closeConnection(conn);
return table;
}
return null;
}
This will result in you getting a DataTable with columns and rows corresponding to the result of your query (Also look into command builders if you want to post changes back to the database later on from it, but for that you will need to keep the connection open).
One nice thing with using the data adapter is that it will figure out what the correct data types should be so you don't have to worry about invalid cast exceptions while reading the data from the data reader.
As somebody pointed out though you will need to read all the data into memory which could be a problem if you are dealing with a lot of memory. Also the DataTable class is really slow when you start dealing with a lot of records. Finally DataTable and DataSet classes also generally hook well into UI components in .Net so that their contents can easily be displayed to users.

Avoid enabling MSDTC when using TransactionScope

[Using: C# 3.5 + SQL Server 2005]
I have some code in the Business Layer that wraps in a TransactionScope the creation of an order and its details:
DAL.DAL_OrdenDeCompra dalOrdenDeCompra = new GOA.DAL.DAL_OrdenDeCompra();
DAL.DAL_ItemDeUnaOrden dalItemDeUnaOrden = new GOA.DAL.DAL_ItemDeUnaOrden();
using (TransactionScope transaccion = new TransactionScope())
{
//Insertion of the order
orden.Id = dalOrdenDeCompra.InsertarOrdenDeCompra(orden.NumeroOrden, orden.PuntoDeEntregaParaLaOrden.Id, (int)orden.TipoDeCompra, orden.FechaOrden, orden.Observaciones);
foreach (ItemDeUnaOrden item in orden.Items)
{
//Insertion of each one of its items.
dalItemDeUnaOrden.InsertarItemDeUnaOrden(orden.Id, item.CodigoProductoAudifarma, item.CodigoProductoJanssen, item.CodigoEAN13, item.Descripcion, item.CantidadOriginal, item.ValorUnitario);
}
transaccion.Complete();
}
return true;
And here is the DAL code that perform the inserts:
public int InsertarOrdenDeCompra(string pNumeroOrden, int pPuntoEntregaId, int pTipoDeCompra, DateTime pFechaOrden, string pObservaciones)
{
try
{
DataTable dataTable = new DataTable();
using (SqlConnection conexion = new SqlConnection())
{
using (SqlCommand comando = new SqlCommand())
{
ConnectionStringSettings conString = ConfigurationManager.ConnectionStrings["CSMARTDB"];
conexion.ConnectionString = conString.ConnectionString;
conexion.Open();
comando.Connection = conexion;
comando.CommandType = CommandType.StoredProcedure;
comando.CommandText = "GOA_InsertarOrdenDeCompra";
//...parameters setting
return (int)comando.ExecuteScalar();
...
public int InsertarItemDeUnaOrden(int pOrdenDeCompraId, string pCodigoProductoAudifarma, string pCodigoProductoJanssen, string pCodigoEAN13, string pDescripcion, int pCantidadOriginal, decimal pValorUnitario)
{
try
{
DataTable dataTable = new DataTable();
using (SqlConnection conexion = new SqlConnection())
{
using (SqlCommand comando = new SqlCommand())
{
ConnectionStringSettings conString = ConfigurationManager.ConnectionStrings["CSMARTDB"];
conexion.ConnectionString = conString.ConnectionString;
conexion.Open();
comando.Connection = conexion;
comando.CommandType = CommandType.StoredProcedure;
comando.CommandText = "GOA_InsertarItemDeUnaOrden";
//... parameters setting
return comando.ExecuteNonQuery();
Now, my problem is in the items insertion; when the InsertarItemDeUnaOrden tries to open a new connection an exception is rised because that would cause the TransactionScope to try promoting to MSDTC, wich I don't have enabled and I would prefer not to enable.
My doubts:
Understandig that the method tht starts the transaction is in the business layer and I don't want there any SqlConnection, ¿can I use another design for my data access so I'm able to reuse the same connection?
Should I enable MSDTC and forget about it?
Thanks.
EDIT: solution
I created a new class in the DAL to hold transactions like this:
namespace GOA.DAL
{
public class DAL_Management
{
public SqlConnection ConexionTransaccional { get; set; }
public bool TransaccionAbierta { get; set; }
public DAL_Management(bool pIniciarTransaccion)
{
if (pIniciarTransaccion)
{
this.IniciarTransaccion();
}
else
{
TransaccionAbierta = false;
}
}
private void IniciarTransaccion()
{
this.TransaccionAbierta = true;
this.ConexionTransaccional = new SqlConnection();
ConnectionStringSettings conString = ConfigurationManager.ConnectionStrings["CSMARTDB"];
this.ConexionTransaccional.ConnectionString = conString.ConnectionString;
this.ConexionTransaccional.Open();
}
public void FinalizarTransaccion()
{
this.ConexionTransaccional.Close();
this.ConexionTransaccional = null;
this.TransaccionAbierta = false;
}
}
}
I modified the DAL execution methods to receive a parameter of that new class, and use it like this:
public int InsertarItemDeUnaOrden(int pOrdenDeCompraId, string pCodigoProductoAudifarma, string pCodigoProductoJanssen, string pCodigoEAN13, string pDescripcion, int pCantidadOriginal, decimal pValorUnitario, DAL_Management pManejadorDAL)
{
try
{
DataTable dataTable = new DataTable();
using (SqlConnection conexion = new SqlConnection())
{
using (SqlCommand comando = new SqlCommand())
{
if (pManejadorDAL.TransaccionAbierta == true)
{
comando.Connection = pManejadorDAL.ConexionTransaccional;
}
else
{
ConnectionStringSettings conString = ConfigurationManager.ConnectionStrings["CSMARTDB"];
conexion.ConnectionString = conString.ConnectionString;
conexion.Open();
comando.Connection = conexion;
}
comando.CommandType = CommandType.StoredProcedure;
comando.CommandText = "GOA_InsertarItemDeUnaOrden";
And finally, modified the calling class:
DAL.DAL_OrdenDeCompra dalOrdenDeCompra = new GOA.DAL.DAL_OrdenDeCompra();
DAL.DAL_ItemDeUnaOrden dalItemDeUnaOrden = new GOA.DAL.DAL_ItemDeUnaOrden();
using (TransactionScope transaccion = new TransactionScope())
{
DAL.DAL_Management dalManagement = new GOA.DAL.DAL_Management(true);
orden.Id = dalOrdenDeCompra.InsertarOrdenDeCompra(orden.NumeroOrden, orden.PuntoDeEntregaParaLaOrden.Id, (int)orden.TipoDeCompra, orden.FechaOrden, orden.Observaciones, dalManagement);
foreach (ItemDeUnaOrden item in orden.Items)
{
dalItemDeUnaOrden.InsertarItemDeUnaOrden(orden.Id, item.CodigoProductoAudifarma, item.CodigoProductoJanssen, item.CodigoEAN13, item.Descripcion, item.CantidadOriginal, item.ValorUnitario, dalManagement);
}
transaccion.Complete();
}
dalManagement.FinalizarTransaccion();
With this changes I'm inserting orders and items without enabling MSDTC.
When using TransactionScope with multiple connections against SQL Server 2005, the transaction will always escalate to a distributed one (meaning MSDTC will be used).
This is a known issue, fixed in SQL Server 2008.
One option you have is to write a single stored procedure that does all the required operations (folding up GOA_InsertarOrdenDeCompra and all calls GOA_InsertarItemDeUnaOrden). With SQL Server 2005 this can be accomplished with an XML parameter, though SQL Server 2008 (apart from not having this issue) has table-valued parameters.
Can't you create the connection outside the methods and pass the same connection to both methods through the parameters?
That way you use the same connection avoiding the promotion.
My good solution would be to rethink the architecture of the DAL.
Something like having an central DAL, that stores an connection object, and have an reference to your DAL_OrdenDeCompra and DAL_ItemDeUnaOrden objects, and passing the reference of the DAL to this objects so they can interact with the connection stored in the DAL.
And then the DAL could have an Open and Close method with reference count, open increments, close decrements and it should only dispose the connection when it reaches zero and create a new one when incrementing to one. Also the DAL should implement the IDisposable to clean the resources of the connection. Then in your Business Layer you do something like this:
using(DAL dal = new DAL())
{
DAL.DAL_OrdenDeCompra dalOrdenDeCompra = dal.OrdenDeCompra;
DAL.DAL_ItemDeUnaOrden dalItemDeUnaOrden = dal.ItemDeUnaOrden;
using (TransactionScope transaccion = new TransactionScope())
{
dal.Open();
//Insertion of the order
orden.Id = dalOrdenDeCompra.InsertarOrdenDeCompra(orden.NumeroOrden, orden.PuntoDeEntregaParaLaOrden.Id, (int)orden.TipoDeCompra, orden.FechaOrden, orden.Observaciones);
foreach (ItemDeUnaOrden item in orden.Items)
{
//Insertion of each one of its items.
dalItemDeUnaOrden.InsertarItemDeUnaOrden(orden.Id, item.CodigoProductoAudifarma, item.CodigoProductoJanssen, item.CodigoEAN13, item.Descripcion, item.CantidadOriginal, item.ValorUnitario);
}
transaccion.Complete();
}
return true;
}
You could have a method in DAL.DAL_ItemDeUnaOrden which receives a collection of ItemDeUnaOrden instead of a single item, that way you can use a SqlTransaction (or TransactionScope) and iterate over the items within the DA method.
orden.Id = dalOrdenDeCompra.InsertarOrdenDeCompra(...);
dalItemDeUnaOrden.InsertarVariosItemsDeUnaOrden(orden.Items);
Depending on your code, you might not have access to your busiess objects (ItemDeUnaOrden) within you DAL, so you might need to pass the values some other way, maybe DTOs or a DataTable.

C# sqlite query results to list<string>

I'm struggling. I have query against my db that returns a single column of data and I need to set it as List. Here is what I am working with and I am getting an error about converting void to string.
public static void GetImportedFileList()
{
using (SQLiteConnection connect = new SQLiteConnection(#"Data Source=C:\Documents and Settings\js91162\Desktop\CMMData.db3"))
{
connect.Open();
using (SQLiteCommand fmd = connect.CreateCommand())
{
SQLiteCommand sqlComm = new SQLiteCommand(#"SELECT DISTINCT FileName FROM Import");
SQLiteDataReader r = sqlComm.ExecuteReader();
while (r.Read())
{
string FileNames = (string)r["FileName"];
List<string> ImportedFiles = new List<string>();
}
connect.Close();
}
}
}
Then later in application
List<string> ImportedFiles = GetImportedFileList() // Method that gets the list of files from the db
foreach (string file in files.Where(fl => !ImportedFiles.Contains(fl)))
public static List<string> GetImportedFileList(){
List<string> ImportedFiles = new List<string>();
using (SQLiteConnection connect = new SQLiteConnection(#"Data Source=C:\Documents and Settings\js91162\Desktop\CMMData.db3")){
connect.Open();
using (SQLiteCommand fmd = connect.CreateCommand()){
fmd.CommandText = #"SELECT DISTINCT FileName FROM Import";
fmd.CommandType = CommandType.Text;
SQLiteDataReader r = fmd.ExecuteReader();
while (r.Read()){
ImportedFiles.Add(Convert.ToString(r["FileName"]));
}
}
}
return ImportedFiles;
}
Things i've amended in your code:
Put ImportedFiles in scope of the entire method.
No need to call connect.Close(); since the connection object is wrapped in a using block.
Use Convert.ToString rather then (String) as the former will handle all datatype conversions to string. I came across this Here
Edit:
You were creating a new command object sqlComm instead of using fmd that was created by the connection object.
First of all your return type is void. You need to return a List. Another problem is that you initialize the list inside the loop, so in each pass of the loop you have a new list, and whatsmore, you do not add the string in the list. Your code should probably be more like:
public static List<string> GetImportedFileList()
{
List<string> ImportedFiles = new List<string>();
using (SQLiteConnection connect = new SQLiteConnection(#"Data Source=C:\Documents and Settings\js91162\Desktop\CMMData.db3"))
{
connect.Open();
using (SQLiteCommand fmd = connect.CreateCommand())
{
fmd.CommandText = #"SELECT DISTINCT FileName FROM Import";
SQLiteDataReader r = fmd.ExecuteReader();
while (r.Read())
{
string FileNames = (string)r["FileName"];
ImportedFiles.Add(FileNames);
}
connect.Close();
}
}
return ImportedFiles;
}
The error is about the return type of your method. You are returning void (public staticvoid) but then use it later as if it were returning a List<string>.
I think you intended the following method signature:
public static List<string> GetImportedFileList()
You already have a way to get the individual results, so to me it looks like you just need to:
Move the List<string> ImportedFiles = new List<string>(); outside the while loop.
Call ImportedFiles.Add(FileNames); inside the loop (after that string gets assigned).
return ImportedFiles at the end.
Change the return type to List<string>.

Categories