I have searched for a long time and tried different ways to solve this problem without any success.
My current program is as follows:
Web service: DAL, Controller and WebService(with web methods)
Windows form: Controller(receives the web service) and Form
I receive a string array in the DAL that I try to send through the web service to my Controller in the windows form program. But receive the error:
Cannot implicity convert type
'WindowsFormApplication.ServiceReference1.ArrayOfString' to
'System.Collections.Generic.List<string[]>'
Controller in form:
public List<string[]> GetAllEmployee()
{
return client.GetAllEmployee();
}
Webservice:
public List<string[]> GetAllEmployee()
{
return cont.GetAllEmployee();
}
DAL:
public List<string[]> GetAllEmployee()
{
GetConnection();
con.Open();
stmt = con.CreateCommand();
stmt.CommandText = "SELECT [No_],[First Name],[Last Name],[Initials],[Job Title],[E-Mail] FROM [CRONUS Sverige AB$Employee]";
OdbcDataReader reader = stmt.ExecuteReader();
List<string[]> allEmployee = new List<string[]>();
String[] cols = new string[5];
for (int i = 0; i < cols.Length; ++i)
{
cols[i] = reader.GetName(i);
}
allEmployee.Add(cols);
while (reader.Read())
{
string[] s = new string[cols.Length];
for (int i = 0; i < s.Length; ++i)
{
s[i] = reader.GetValue(i).ToString();
}
allEmployee.Add(s);
}
con.Close();
return allEmployee;
}
Controller:
public List<string[]> GetAllEmployee()
{
return dal.GetAllEmployee();
}
client:
ServiceReference1.WebService1SoapClient client = new ServiceReference1.WebService1SoapClient();
Your service returns the type WindowsFormApplication.ServiceReference1.ArrayOfString which needs to be explicitly converted to List<string> with ToList Method:
return dal.GetAllEmployee().ToList();
Related
I have these two classes:
public class Message
{
string Message;
string Code;
}
public class MessageInitializer
{
DataSet ds;
DataRow dr;
message[] ms;
}
I want to create a constructor in MessageInitializer like this:
MessageInitializer()
{
this.ms = new Message[ds.Tables[0].Rows.Count];
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
dr = ds.Tables[0].Rows[i];
ms[(string)dr.ItemArray[0]] = (string)dr.ItemArray[1];
}
}
But array's index must be int type. I have no idea how to work this out:
ms[(string)dr.ItemArray[0]] = (string)dr.ItemArray[1];
Update:
Code format is a string like this: [001-001-001], so I can't convert it to integer.
you don't need Message class any more. Using a dictionary as follows solves the problem :
public class MessageInitializer
{
DataSet ds;
DataRow dr;
Dictionary<string, string> ms;
public MessageInitializer()
{
this.ms = new Dictionary<string,string>(ds.Tables[0].Rows.Count);
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
dr = ds.Tables[0].Rows[i];
ms[(string)dr.ItemArray[0]] = (string)dr.ItemArray[1];
}
}
}
I hope this would be helpful.
If you just want to get a list of all the messages from the database, then you can use the code below. Note, List instead of Array. Easier to use and faster.
public class Message
{
string Message;
string Code;
}
public class MessageInitializer
{
DataSet ds;
DataRow dr;
List<Message> ms;
MessageInitializer()
{
this.ms = new List<Message>();
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
dr = ds.Tables[0].Rows[i];
ms.Add(new Message
{
Code = dr.ItemArray[0].ToString(),
Message = dr.ItemArray[1].ToString(),
});
}
}
}
You mentioned that you have couple million records. List will perform fine in case you want to access items sequestially. If you want to access items in a non-sequential manner, I suggest you use Dictionary instead (to improve search perfromance):
public class MessageInitializer
{
DataSet ds;
DataRow dr;
Dictionary<string, Message> ms;
MessageInitializer()
{
this.ms = new Dictionary<string, Message>();
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
dr = ds.Tables[0].Rows[i];
ms.Add(dr.ItemArray[0].ToString(), new Message
{
Code = dr.ItemArray[0].ToString(),
Message = dr.ItemArray[1].ToString(),
});
}
}
}
You can access message as follows:
var message = ms["001-001-001"];
It will be orders or magnitude faster than accessing a random List item:
var message - ms.First(x => x.Code == "001-001-001");
I think you just want build an array of messages from ds.Tables[0]
Code -
ms[i].Code = (string)dr.ItemArray[0];
Message -
ms[i].Message = (string)dr.ItemArray[1];
MessageInitializer()
{
this.ms = new Message[ds.Tables[0].Rows.Count];
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
dr = ds.Tables[0].Rows[i];
ms[i].Code= (string)dr.ItemArray[0];
ms[i].Message = (string)dr.ItemArray[1];
}
}
For better performance make use of Parallel.ForEach -
Parallel.ForEach(ds.Tables[0].AsEnumerable(), row => {
ms[i].Code= (string)row.ItemArray[0];
ms[i].Message = (string)row.ItemArray[1];
});
I think what you want to perform is the following:
public class Message
{
public string message { get; set; }
public string code { get; set; }
}
public class MessageInitializer
{
DataSet ds;
DataRow dr;
Message[] ms;
MessageInitializer()
{
this.ms = new Message[ds.Tables[0].Rows.Count];
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
dr = ds.Tables[0].Rows[i];
ms[i] = new Message
{
code = (string)dr.ItemArray[0],
message = (string)dr.ItemArray[1]
};
}
}
}
i have the following Function
public string StoredProcedure(string StoredProcedureName,List<List<string>> StoredProcedureParameter,string ReturnValue = null)
{
string functionReturnValue;
cmd = new SqlCommand(StoredProcedureName, conniction(true));
cmd.CommandType = CommandType.StoredProcedure;
for (int i = 0; i <= StoredProcedureParameter.Count; i++)
{
cmd.Parameters.AddWithValue(StoredProcedureParameter[0][i], StoredProcedureParameter[1][i]);
}
int exec_cmd = (int)cmd.ExecuteScalar();
if (ReturnValue != null)
{
SqlParameter prm = new SqlParameter(ReturnValue, SqlDbType.Int);
cmd.Parameters.Add(prm).Direction = ParameterDirection.ReturnValue;
functionReturnValue = prm.ToString();
}
else
{
functionReturnValue = exec_cmd.ToString();
}
return functionReturnValue;
}
and i need to pass 2D list Parameter to StoredProcedureParameter using delegate and maybe lambda expression
Do the following.
Change the signature of your method to accept delegates:
public string StoredProcedure(string StoredProcedureName, Func<List<List<string>>> StoredProcedureParameterFunc, string ReturnValue = null)
{
List<List<string>> StoredProcedureParameter = StoredProcedureParameterFunc();
... // your original code here
}
Invoke the method like this:
var result = StoredProcedure("SPName", GetLists, "returnID");
Where GetLists is a new method returning a "2D" list of strings, e.g.:
private List<List<string>> GetLists() {
var result = new List<List<string>>();
... // fill result here
return result;
}
Say, if what I have is only a server name obtained from this enumeration:
//Collect server names
List<string> arrServerNames = new List<string>();
try
{
// Perform the enumeration
DataTable dataTable = null;
try
{
dataTable = System.Data.Sql.SqlDataSourceEnumerator.Instance.GetDataSources();
}
catch
{
dataTable = new DataTable();
dataTable.Locale = System.Globalization.CultureInfo.InvariantCulture;
}
// Create the object array of server names (with instances appended)
for (int i = 0; i < dataTable.Rows.Count; i++)
{
string name = dataTable.Rows[i]["ServerName"].ToString();
string instance = dataTable.Rows[i]["InstanceName"].ToString();
if (instance.Length == 0)
{
arrServerNames.Add(name);
}
else
{
arrServerNames.Add(name + "\\" + instance);
}
}
}
catch
{
//Error
}
How can I know the SQL Server version installed on that server?
Checking the official MSDN documentation for GetDataSources() would have easily revealed that there is a Version column in the result set:
// Create the object array of server names (with instances appended)
for (int i = 0; i < dataTable.Rows.Count; i++)
{
string name = dataTable.Rows[i]["ServerName"].ToString();
string instance = dataTable.Rows[i]["InstanceName"].ToString();
string version = dataTable.Rows[i]["Version"].ToString(); // this gets the version!
..........
}
I have a web method in a c# web service which creates three lists, which are filled from xml input. I want to combine these three lists into one entity (a DataSet would be the best, as the iOS app that is consuming this web service is already programmed to accept and parse DataSets), and return them from the web method.
Here is currently what my code looks like:
[WebMethod]
public DataSet SelectObjects(string ExternalID, string Password)
{
DataSet ds = new DataSet();
MembershipAuthServiceReference.MembershipAuthenticationService objService = new MembershipAuthServiceReference.MembershipAuthenticationService();
MembershipAuthServiceReference.SoapHeaderCredentials objSoapHeader = new MembershipAuthServiceReference.SoapHeaderCredentials();
MembershipAuthServiceReference.MemberUserInfo objMemberInfo = new MembershipAuthServiceReference.MemberUserInfo();
try
{
objSoapHeader.UserName = ExternalID;
objSoapHeader.Password = Password;
objMemberInfo = objService.GetMembershipInfo();
List<Obj1> ListObj1 = new List<Obj1>();
for (int i = 0; i < objMemberInfo.Obj1.Length; i++)
{
Obj1 obj_Obj1 = new Obj1();
obj_Obj1.Stuff = objMemberInfo.Obj1[i].Stuff.ToString();
ListObj1.Add(obj_Obj1);
}
List<Obj2> ListObj2 = new List<Obj2>();
for (int i = 0; i < objMemberInfo.Obj2.Length; i++)
{
Obj2 obj_Obj2 = new Obj2();
obj_Obj2.Stuff = objMemberInfo.Obj2[i].Stuff.ToString();
ListObj2.Add(obj_Obj2);
}
List<Obj3> ListObj3 = new List<Obj3>();
for (int i = 0; i < objMemberInfo.Obj3.Length; i++)
{
Obj3 obj_Obj3 = new Obj3();
obj_Obj3.Stuff = objMemberInfo.Obj3[i].Stuff.ToString();
ListObj3.Add(obj_Obj3);
}
}
catch (Exception ex)
{
string sError;
sError = ex.Message.ToString();
}
return ds;
}
How do I combine these lists into a DataSet? I'm assuming it's possible? If not, is there a viable alternative that does the same thing?
First concatenate your lists as shown below and then use the link to generate the dataset
var combinedList= ListObj1.Concat(ListObj2).Concat(ListObj3);
How do I transform a List<T> into a DataSet?
I am trying to loop thru the elements of an Array[] for Parameter names and Object[] for object values using the AddWithValue().
Unfortunately it is saying "Procedure or function 'sp_add_Request' expects parameter '#RequestType', which was not supplied". When I run to cursor, I can see all the parameters are supplied, I do not understand where the problem is. Please help. See code below:
object[] myValues = new Object[] { txtID.Text, ddlAmissionType.Text };
string[] paramsNames = new string[] { "#CHI", "#RequestType"};
dbConn.addData("sp_add_Request", paramsNames, myValues, lbMsg.Text);
Parent method:
public static bool addData(string storedProcName, string[] dynamicParamName, object[] aramVals, string msg)
{
for (int i = 0; i < dynamicParamName.Length; i++)
{
cmd2.Parameters.AddWithValue(dynamicParamName[i], paramVals[i]);
//cmd2.Parameters.Add(dynamicParamName[i], dynamicParamValues[i]);
try
{
if (cmd2.Connection.State == ConnectionState.Closed)
{
cmd2.Connection.Open();
int stat = cmd2.ExecuteNonQuery();
if (stat > 0)
{
res = true;
msg = "Recorded Added successfully";
cmd2.Connection.Close();
cmd2.Dispose();
}
}
}
}
You are accessing the database in your loop because the command is executed within the for loop. So you're performing your command before the 2nd parameter is added. Move the try block outside the for loop and you should be fine.
public static bool addData(string storedProcName, string[] dynamicParamName, object[] paramVals, string msg)
{
for (int i = 0; i < dynamicParamName.Length; i++)
{
cmd2.Parameters.AddWithValue(dynamicParamName[i], paramVals[i]);
//cmd2.Parameters.Add(dynamicParamName[i], dynamicParamValues[i]);
}
try
{
if (cmd2.Connection.State == ConnectionState.Closed)
{
cmd2.Connection.Open();
}
int stat = cmd2.ExecuteNonQuery();
if (stat > 0)
{
res = true;
msg = "Recorded Added successfully";
cmd2.Connection.Close();
cmd2.Dispose();
}
}
}
You may want to just go ahead and put your connection object in a using statement that way it's automatically disposed. #abatishchev's answer below shows the proper way to handle your ado objects.
Create, use and dispose new connection/command objects each time method is being called. This will use connection pooling and other performance positive techniques.
public static bool addData(string storedProcName, string[] dynamicParamName, object[] paramVals, string msg)
{
SqlParameter[] paramArr = new SqlParameter[dynamicParamName.Length];
for(int i = 0; i < dynamicParamName.Length; i++)
{
paramArr[i] = new SqlParameter(dynamicParamName[i], paramVals[i]);
}
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = commandText;
//command.CommandType = CommandType.StoredProcedure ; // if needed
command.Parameters.AddRange(paramArr);
connection.Open();
return command.ExecuteNonQuery() > 0;
}
}
See MSDN: SqlParameterCollection.AddRange() method.
Also you can use LINQ:
SqlParameter[] paramArr = dynamicParamName
.Select((paramName,i) => new SqlParameter(paramName, paramVals[i]).ToArray();
or
SqlParameter[] paramArr = Enumerable.Range(0, dynamicParamName.Length - 1)
.Select(i => new SqlParameter(dynamicParamName[i], paramVals[i])
.ToArray();