Run query within IF statement - c#

I'm trying to learn C# and have come across a problem that I hope you guys will know an easy solution.
I want to run two possible LINQ queries but reading from different places and returning a 2 different fields (both id's) based on an IF condition.
In VB6 it would have been something simple like:
Dim strQuery as string
Dim rs as adodb.recordset
If 1 = 1 then
strQuery = "Select messageid as id1, refid as id1 from x where ..."
else
strQuery = "Select commonid as id1, nextid as id2 from x where ..."
endif
set rs = cn.execute(strquery)
debug.print rs!id1 & rs!id2
How can this be done in c#?
I've tried:
IQueryable fD = null;
if (1 == 1)
{
fD = from qa in data.table1
select qa;
}
else
{
fD = from qa in data.table2
select qa;
}
foreach (var a in FD)
{
// Unable to see any data.
}

Thankyou Tetsuya Yamamoto for pointing me in the right direction IQueryable strQuery
foreach (**dynamic** a in strQuery)
{
//a.CentralContractorID
}
dynamic was the word which was missing, it now works perfect.

Related

How to get data without conditions in C#

Hi. I have 2 data tables like this:
I want to get the ID in Table1 if the User in Table2 exists or does not exist
This is the code I test and get the data:
string idGet = "";
string getValue = "Select ID, Port, User from Table1";
DataTable dtgetValue = XLDL.ReadTable(getValue);
if(dtgetValue.Rows.Count > 0)
{
List<ListOtherUser> listOtherUser = new List<ListOtherUser>();
for (int i = 0; i < dtgetValue.Rows.Count; i++)
{
listOtherUser.Add(new ListOtherUser { ID = dtgetValue.Rows[i]["ID"].ToString(), User = dtgetValue.Rows[i]["User"].ToString(), Port = dtgetValue.Rows[i]["Port"].ToString() });
}
foreach (var itemuser in listOtherUser)
{
string checkUser = "Select ID from Table2 where User = N'" + itemuser.User + "'";
DataTable dtcheckUser = XLDL.ReadTable(checkUser);
if (dtcheckUser.Rows.Count > 0)
{
idGet += itemuser.ID + ",";
}
else
{
//Here I want to continue to get the data of row ID=3 from Table1. However I don't know how to solve it?
}
}
}
As the data above I want the output as: idGet = 1 and 3 from Table1
With data from Table1 and Table2:
As the data above I want the output as: idGet = 2 and 3 from Table1
Looking forward to a solution from everyone. Thank you!
The best solution here though would be to do some SQL joins and exclude it coming in, but if you want a solution in code instead, depdending on how large that dataset is/will be, this is a good spot for LINQ.
var result = Table2.Where(p => table1.All(p2 => p2.UserID != p.UserID));
Adapted from this question.
If you opted for SQL, your query would look something more like this and while looking at your logic, you should absolutely not do that how you are trying to. That is so many single db calls for absolutely no reason.
Select Table1.ID
FROM Table1 LEFT OUTER JOIN
Table2 ON Table1.User = Table2.User
WHERE Table2.ID IS NULL;

Application returns data for me but not other users, even when I log in under their username - SQL Server/C#/WPF

Having a little bit of a strange error here that I have never encountered before. I have an application where users can type in a list of accounts in a datagrid and a date range and press a button and it will return the data for these accounts in a datagrid and give them the option to export it to an excel file. This works perfectly for me, logged in under my username and even when I log in under other people's username. The problem is when they try it, they get no data back. No errors, just it doesn't pull any data.
The interesting thing is this is all in the same database as the other information which they access without any problem. The only difference, which I think might be the explanation is I am calling this SQL code directly from the Application whereas everything else is called using stored procedures that sit on the server. The reason for this is I have to concatenate the SQL Query string for each item in the accounts field. Since they are able to enter as many accounts as they want, I cannot use a stored procedure since I don't know how many parameters it will have ultimately(if someone could let me know a method of doing this, I would actually prefer this way for keeping things consistent). Obviously the query string is working properly, as it's pulling data back for me, but the question I have is why is it failing to return data for others? The connection string is an SQL Authentication, so it shouldn't have anything to do with them not having Windows Authentication on the server, plus they are already able to log in to the application and it displays data on their dashboard, which couldn't happen...
Anyone that can point me in the right direction with this I would appreciate it...the only thing I can think of is it is an issue with using an in-code SQL string versus a stored procedure, but this doesn't make any sense since other people do this all the time in applications without issue.
public ICommand GetData
{
get => new RelayCommand(() =>
{
//call the SQL Code to lookup the account numbers
var SQLStr = "SELECT * FROM [Clients].[Data] WHERE (Account_Number = '";
for (var i = 0; i< AccountNums.Count; i++)
{
if (!String.IsNullOrEmpty(AccountNums[i].accNum)) SQLStr += i == 0 ? $"{AccountNums[i].accNum}'" : $" OR Account_Number = '{AccountNums[i].accNum}'";
}
SQLStr += $") AND SUB_QUERY_CREATED_ON BETWEEN '{StartDate.ToString()}' AND '{EndDate.ToString()}'";
_Data = DBMethods.GetSQLData(_Data, new Models.Clients.Data(), SQLStr, new List<string> { "ID" }, true);
ShowResPnl = true; //there are results, toggle the panel visibility bound variable
});
}
public static ObservableCollection<T> GetSQLData<T>(ObservableCollection<T> myCollection, T myClass, String SQLString, List<string> remParams, bool UseSQLQuery) where T : class
{
var conn = new SqlConnection();
try
{
var paramList = GenerateSQLParameters(myClass, remParams);
using (getConnection(conn))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(SQLString, conn))
{
cmd.CommandType = CommandType.Text;
SqlDataReader reader;
reader = cmd.ExecuteReader();
//only execute if the reader has data
if (reader.HasRows)
{
while (reader.Read())
{
var tempModel = Global.GenerateNewInstance(myClass) as T;
Type model = tempModel.GetType();
var prop = model.GetProperties();
PropertyInfo pi;
//set the values for each property in the model
foreach (var p in prop)
{
if (!remParams.Contains(p.Name))
{
pi = tempModel.GetType().GetProperty(p.Name);
if (reader[p.Name] == DBNull.Value)
{
pi.SetValue(tempModel, null);
}
else
{
pi.SetValue(tempModel, reader[p.Name]);
}
}
}
myCollection.Add(tempModel);
}
reader.Close();
cmd.Dispose();
}
}
}
}
catch (Exception ex)
{
ErrorWindow errWin = new ErrorWindow("There was a problem trying to Get the Data with the Query '" + SQLString + "'! Error: " + ex.Message);
errWin.Show();
}
return myCollection;
}
UPDATE: OK I got it working perfectly with help from THIS thread:
How do I split a string so I can access item x?
and more specifically this post:
What about using string and values() statement?
DECLARE #str varchar(max)
SET #str = 'Hello John Smith'
DECLARE #separator varchar(max)
SET #separator = ' '
DECLARE #Splited TABLE(id int IDENTITY(1,1), item varchar(max))
SET #str = REPLACE(#str, #separator, '''),(''')
SET #str = 'SELECT * FROM (VALUES(''' + #str + ''')) AS V(A)'
INSERT INTO #Splited
EXEC(#str)
SELECT * FROM #Splited
I created a stored procedure using this, then did a left join on Account numbers from the Data Table and used a WHERE clause to set the Start and End Dates and exclude items that were NULL(checked one of the columns). Works perfectly and only took about 2 or 3 seconds to return the data. I had another working method as detailed here https://sqlperformance.com/2012/07/t-sql-queries/split-strings#comments using a function which was taking well over a minute to return data for only 4 accounts...obviously was not going to work well enough so I found the method mentioned prior and it works excellently!

ASP.NET, C# How to Pass a StringQuery to a custom SQL Command

I have a slight issue, I have a ASP.NET Webforms application. I'm sending over a url?id=X were X is my database index or id.
I have a C# class file to run my SQL connection and query. Here is the code:
public DataTable ViewProduct(string id)
{
try
{
string cmdStr = "SELECT * Products WHERE Idx_ProductId = " + id;
DBOps dbops = new DBOps();
DataTable vpTbl = dbops.RetrieveTable(cmdStr, ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString);
return vpTbl;
}
catch (Exception e)
{
return null;
}
}
So as you can see my problem lies within string cmdStr = "SQL Query" + variable;
I'm passing over my index or id through the URL then requesting it and turning it into a string then using ViewProduct(productId).
I don't know what syntax or how to add the id into my C# string sql query. I've tried:
string cmdStr = "SELECT * Products WHERE Idx_ProductId = #0" + id;
string cmdStr = "SELECT * Products WHERE Idx_ProductId = {0}" + id;
also what I have currently to no avail.
I was so sure this would be a duplicate of some canonical question about parameterized queries in C#, but apparently there isn't one (see this)!
You should parameterize your query - if you don't, you run the risk of a malicious piece of code injecting itself into your query. For example, if your current code could run against the database, it would be trivial to make that code do something like this:
// string id = "1 OR 1=1"
"SELECT * Products WHERE Idx_ProductId = 1 OR 1=1" // will return all product rows
// string id = "NULL; SELECT * FROM UserPasswords" - return contents of another table
// string id = "NULL; DROP TABLE Products" - uh oh
// etc....
ADO.NET provides very simple functionality to parameterize your queries, and your DBOps class most assuredly is not using it (you're passing in a built up command string). Instead you should do something like this:
public DataTable ViewProduct(string id)
{
try
{
string connStr = ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
// #id is very important here!
// this should really be refactored - SELECT * is a bad idea
// someone might add or remove a column you expect, or change the order of columns at some point
cmd.CommandText = "SELECT * Products WHERE Idx_ProductId = #id";
// this will properly escape/prevent malicious versions of id
// use the correct type - if it's int, SqlDbType.Int, etc.
cmd.Parameters.Add("#id", SqlDbType.Varchar).Value = id;
using (SqlDataReader reader = cmd.ExecuteReader())
{
DataTable vpTbl = new DataTable();
vpTbl.Load(reader);
return vpTbl;
}
}
}
}
catch (Exception e)
{
// do some meaningful logging, possibly "throw;" exception - don't just return null!
// callers won't know why null got returned - because there are no rows? because the connection couldn't be made to the database? because of something else?
}
}
Now, if someone tries to pass "NULL; SELECT * FROM SensitiveData", it will be properly parameterized. ADO.NET/Sql Server will convert this to:
DECLARE #id VARCHAR(100) = 'NULL; SELECT * FROM SensitiveData';
SELECT * FROM PRoducts WHERE Idx_ProductId = #id;
which will return no results (unless you have a Idx_ProductId that actually is that string) instead of returning the results of the second SELECT.
Some additional reading:
https://security.stackexchange.com/questions/25684/how-can-i-explain-sql-injection-without-technical-jargon
Difference between Parameters.Add and Parameters.AddWithValue
SQL injection on INSERT
Avoiding SQL injection without parameters
How do I create a parameterized SQL query? Why Should I? (VB.NET)
How can I prevent SQL injection in PHP? (PHP specific, but many helpful points)
Is there a canonical question telling people why they should use SQL parameters?
What type Products.Idx_ProductId is?
Probably it is string, than you need to use quotes: "... = '" + id.Trim() + "'";

Why this SQL Server query can't work when I put it into a C# method?

I have the following problem trying to insert the following SQL server query into a C# method:
select *
from VulnerabilityReference
where Title = 'Message'
and convert(nvarchar(MAX), Description2) = N'http://www.securityfocus.com/archive/1/1201040152.5924.44.camel#laptop'
As you can see the Description2 field is casted
In Microsoft SQL Server Managment Studio the previous query work well and give me the following output:
Id Title Description2
52794 Message http://www.securityfocus.com/archive/1/1201040152.5924.44.camel#laptop
55340 Message http://www.securityfocus.com/archive/1/1201040152.5924.44.camel#laptop
55341 Message http://www.securityfocus.com/archive/1/1201040152.5924.44.camel#laptop
55342 Message http://www.securityfocus.com/archive/1/1201040152.5924.44.camel#laptop
Now I creat the following exist() method in C#
public long existReference(DataModel.Vulnerability.Reference reference)
{
long id = -1;
_strSQL = "SELECT * FROM VulnerabilityReference"
+ " WHERE Title = #REFERENCETITLE and convert(nvarchar(MAX), Description2) = N'#DESCRIPTION2' ";
System.Data.Common.DbCommand command;
command = _connection.CreateCommand();
_addParameter(command, "#REFERENCETITLE", reference.Title);
_addParameter(command, "#DESCRIPTION2", reference.Description2);
command.CommandText = _strSQL;
_dt = _fillDataTable(command);
if (_dt.Rows.Count == 0)
{
return -1;
}
id = _dt.Rows[0].Field<int>("Id");
return id;
}
The two field of the reference object contains the same values of the previous example but it don't work fine and found 0 records for this query.
Why? What could be the problem? How can I solve it?
Tnx
N'#DESCRIPTION2' is looking for the literal text #DESCRIPTION2 (not the value of the parameter by that name). If you want the parameter value, just use #DESCRIPTION2:
WHERE ...(blah)... = #DESCRIPTION2
Drop all things around variables that tell the parser what type of variable it is. That's already known:
N'#DESCRIPTION2'
in your statement needs to be
#DESCRIPTION2
your query should look like
_strSQL = "SELECT * FROM VulnerabilityReference"
+ " WHERE Title = #REFERENCETITLE and convert(nvarchar(MAX), Description2) = #DESCRIPTION2 ";

Retrieval of Word Score from mysql database in c#

I want to retrieve a score of words from databse and then I will make a decision about paragraph that this is positive paragraph or negative paragraph
The database file format is like this. where some key word have positive and negative score
Word Pos_Score Neg_Score
Able .324 .834
Country .987 .213
Love .378 .734
agree .546 .123
industry .289 .714
guests .874 .471
The Paragraph will be like this.
I agree with you. It seems an intelligent tourist industry allows its guests to either immerse fully, in part, or not, depending upon the guest. That is why the ugly American charges have always confused me.
Now I will compare each word of the paragraph with database file if the word found in the database file then I will retrieve the Pos_Scoe and Neg_Score score of word and these score will be store in variable when the whole paragraph will compare at the end Pos_Score will add separately and the Neg_Score will add separately . and this will be the result.
Code that i try is this
private void button1_Click(object sender, EventArgs e)
{
string MyConString = "server=localhost;" +
"database=sentiwornet;" + "password=zia;" +
"User Id=root;";
MySqlConnection connection = new MySqlConnection(MyConString);
MySqlCommand command = connection.CreateCommand();
MySqlDataReader Reader;
StreamReader reader = new StreamReader("D:\\input.txt");
string line;
while ((line = reader.ReadLine()) != null)
{
string[] parts = line.Split(' ');
foreach (string part in parts)
{
command.CommandText = "SELECT Pos_Score FROM score WHERE Word = 'part'";
command.CommandText = "SELECT Neg_Score FROM score WHERE Word = 'part'";
//var
connection.Open();
Reader = command.ExecuteReader();
}
}
}
First, this query promises to be horribly inefficient. Instead, if your paragraphs are small enough, I would execute all of the joins inside the database by passing in the arguments as a CSV-list, then converting to a table in SQL. The following function will do that (courtesy of http://codebank.wordpress.com/2007/03/06/simple-sql-csv-to-table-2/):
Caveat: you will need to strip all punctuation out using something like string.Replace(new[] { '.', ',' ... etc })
Also, it's possible that my code doesn't do exactly what you want - it may not even compile - but that is the joy of programming. This gives you the general idea I have on how to solve a rather complex problem.
Edit: I just realized you are using MySql. This code would work for MSSQL - I have never used MySql from the CLR, so I don't know if all of the classes are equivalent. You may need to go back to what you were doing before.
CSV to List
Create Function dbo.fn_CSVToTable (#CSVList Varchar(MAX))
Returns #Table Table (ColumnData Varchar(50))
As
Begin
If right(#CSVList, 1) <> ','
Select #CSVList = #CSVList + ','
Declare #Pos Smallint,
#OldPos Smallint
Select #Pos = 1,
#OldPos = 1
While #Pos < Len(#CSVList)
Begin
Select #Pos = CharIndex(',', #CSVList, #OldPos)
Insert into #Table
Select LTrim(RTrim(SubString(#CSVList, #OldPos, #Pos - #OldPos))) Col001
Select #OldPos = #Pos + 1
End
Return
End
SQL Procedure
CREATE PROCEDURE dbo.spGetWordScores (#csv varchar(MAX))
AS
select POS_SCORE, NEG_SCORE, WORD from score
inner join dbo.fn_CSVToTable(#csv) input
on input.ColumnData = score.WORD
New C# Code
var MyConString = "server=localhost;" +
"database=sentiwornet;" + "password=zia;" +
"User Id=root;";
var connection = new MySqlConnection(MyConString);
//Each line in the array will probably be one paragraph.
var fileLines = File.ReadAllLines("D:\\input.txt");
foreach (var line in fileLines)
{
//Format your line into words by removing punctuation. I'm not going to bother
//with that code because it is trivial.
//var csv = line.Split(' ');
var command = connection.CreateCommand();
command.CommandText = "exec spGetWordScores";
command.Parameters.AddWithValue("#csv", csv);
var ds = command.ExecuteDataSet();
//Now you have a DataSet with your word scores. do with them what you will.
}
Helpful Extension Method
public static class Extensions
{
public static DataSet ExecuteDataSet(this SqlCommand command)
{
using (SqlDataAdapter da = new SqlDataAdapter(command)) {
DataSet ds = new DataSet();
// Fill the DataSet using default values for DataTable names, etc
da.Fill(ds);
return ds;
}
}
}
Going back and forward to the database is going to kill your performance. Best to write a stored procedure that takes in your input string, splits it and calculates the score - this way all of the processing will happen on one machine and you will save significant time by not communicating partial results.

Categories