Im having a table called transaktions where i inserted customers billings and customer number. My primary key is an int id that has identity specifikation. My question is how do i select all rows that contains a specific customer_nr and returns all the results?
Right now im doing:
public string getCustomerTransaktions(string CustNr)
{
using (var cmd = new SqlCommand("select billing_name from [transaktions] where customer_nr = #customer_nr", Connect()))
{
cmd.Parameters.AddWithValue("#customer_nr", custNr);
using (var er = cmd.ExecuteReader())
{
if (er.Read())
{
return (string)er["billing_name"];
}
}
}
return "UNKNOWN";
}
This will only print the first row that matches the customer nr, there are atleast 20 rows left. Anyone have any suggestion that will help me?
Best Regards
Agree both with #Niklas and #Skurmedel, you need to both use a loop for processing multiple records and collate them together before returning them as a result.
e.g.
public List<string> getCustomerTransaktions(string CustNr)
{
List<string> names = new List<string>();
using (var cmd = new SqlCommand("select billing_name from [transaktions] where customer_nr = #customer_nr", Connect()))
{
cmd.Parameters.AddWithValue("#customer_nr", custNr);
using (var er = cmd.ExecuteReader())
{
while(er.Read())
{
names.Add((string)er["billing_name"]);
}
}
}
return names;
}
Since you do return ... and your method specification pretty much limits the results to one particular value, you can never return more than one billing name. It will return a name as soon as a row has been read, or your default if no rows were returned.
You should put the values in a list or likewise and return that.
try to change the if to a while
while (er.Read())
I guesss a simple solution would be to return the whole ResultSet instead of tring to work around with string. Then iterate through its all items from your calling method
Related
this is code we have for retrieving a header left joined to its lines (one query), instead of returning two result sets (one for head, one for lines) for getting related data from a database, we always get ONE head, and however many lines it has.
Could you please help me understand why if the Distinct() at the bottom is removed it would return HEAD duplicates corresponding to the number of lines that were retrieved.
Is this because for every row in the reader, we project a HEAD even if it's the same? so if the HEAD has 40 lines, we are projecting the same HEAD 40 times? then a DISTINCT will eliminate 39 and return just one?
Would just doing .FirstOrDefault() without Distinct() be equivalent in this scenario as Distinct() because at the end of the day, it is projecting the same HEAD object?
public static IEnumerable<T> Select<T>(this IDataReader dr, Func<T> selector)
{
if (dr == null)
throw new ArgumentException(nameof(dr));
while (dr.Read())
yield return selector();
}
public void Test()
{
DTOHead head = null;
Dictionary<string, DTOHead> entryDictionary = new Dictionary<string, DTOHead>();
using (DbDataReader reader = cmd.ExecuteReader())
{
var head = reader.Select(dr =>
{
DTOHead entry = null;
if (!entryDictionary.TryGetValue((string)dr["Key"], out entry))
{
DTOHead dtoHead = new DTOHead();
dtoHead.Key = (string)dr["Key"]
dtoHead.Description = (string)dr["DESCRIPTION"];
dtoHead.Lines = new List<DTOLine>();
entry = dtoHead;
entryDictionary.Add(entry.Key, entry);
}
if (dr["LINE_NO"] != DBNull.Value)//skip, there are no lines for this one
{
DTOLine dtoLine = new DTOLine();
dtoLine.LineNo = (string)dr["LINE_NO"];
dtoLine.Qty = (string)dr["QTY"];
entry.Lines.Add(dtoLine);
}
return entry;
}).Distinct();
}
}
Is this because for every row in the reader, we project a HEAD even if it's the same? so if the HEAD has 40 lines, we are projecting the same HEAD 40 times? then a DISTINCT will eliminate 39 and return just one?
Yes, it is this exactly. Your implementation of Select will project one DTOHead for each row in reader. Assuming that you only have one unique "Key" in your result set, it will always be the same DTOHead reference... the one that you create then add to entryDictionary. The call to Distinct then removes all the duplicates and leaves you with an IEnumerable<DTOHead> with one item.
Would just doing .FirstOrDefault() without Distinct() be equivalent in this scenario as Distinct() because at the end of the day, it is projecting the same HEAD object?
Since you indicate that your result set will only contain ONE Head then yeah... you can drop the call to Distinct and just use FirstOrDefault, assuming that you don't want an IEnumerable<DTOHead> and only want an instance of DTOHead.
If that's the case though, you don't need entryDictionary. You can just read the first row from reader, then project the remaining rows into an IEnumerable<DTOLine> with your Select method.
public void Test()
{
DTOHead head = null;
using (DbDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
// Deal with the first row by creating the DTOHead.
head = new DTOHead();
head.Key = (string)reader["Key"];
head.Description = (string)reader["DESCRIPTION"];
head.Lines = new List<DTOLine>();
if (reader["LINE_NO"] != DBNull.Value)//skip, there are no lines for this one
{
// Deal with the first row by creating the first DTOLine.
DTOLine line = new DTOLine();
line.LineNo = (string)reader["LINE_NO"];
line.Qty = (string)reader["QTY"];
head.Lines.Add(dtoLine);
// Project the remaining rows into lines.
head.Lines.AddRange(reader.Select(dr =>
{
DTOLine dtoLine = new DTOLine();
dtoLine.LineNo = (string)dr["LINE_NO"];
dtoLine.Qty = (string)dr["QTY"];
return dtoLine;
});
}
}
}
}
I got a problem where I can't read the data from my database correctly.
To give you an example, I got the important value that is in the database 6.69879289850025E-06, but I read 6.0 (which is not accurate since it's suppose to be way smaller) in the C# program.
Something similar happen to ImportantValue2 where the value that is in the database is -0,000158976621370616 and in my C# program I get 0,0.
public double ImportantValue1 { get; set; }
public double ImportantValue2 { get; set; }
public string Note { get; set; }
public MyObject(SQLiteDataReader reader)
{
ImportantValue1 = Convert.ToDouble(reader["important_value_1"]); //Value in the database is REAL
ImportantValue2 = Convert.ToDouble(reader["important_value_2"]);//Value in the database is REAL
Note = reader["note"].ToString(); //Value in the database is TEXT
}
Update
And this is how I call it.
using (SQLiteConnection c = new SQLiteConnection(connection))
{
c.Open();
using (SQLiteCommand cmd = new SQLiteCommand(sqlCommand, c))
{
using (SQLiteDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
objectFromBD = new MyObject(reader);
}
}
}
}
And the SQLite code
CREATE TABLE "table"(
"id" INTEGER,
"important_value_1" REAL NOT NULL,
"important_value_2" REAL NOT NULL,
"note" TEXT NOT NULL,
PRIMARY KEY ("id" AUTOINCREMENT)
);
Thank you for your help!
reader["important_value_1"] will return index which column exists in your SQL script instead of your expectation value.
reader["important_value_1"] will get the value of the specified column.
You can try to use reader["important_value_1"] in reader.GetDouble function to read your data from columns.
ImportantValue1 = reader.GetDouble(reader["important_value_1"])
ImportantValue2 = reader.GetDouble(reader["important_value_2"])
SqliteDataReader.Item[] Property
Note
You might need to use reader.Read() let the reader point to read the next row if you want.
while (reader.Read()){
//... read all rows from your db
}
Here is a temporary solution I got, but that is not efficient.
I saw that I can read a string with the reader, but I couldn't do it with a double. So I used reader.GetString(rowValue); and than I converted the string to a double using the fonction below.
public double StringToDoubleWithNotation(string value)
{
return Convert.ToDouble(Decimal.Parse(value, NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint));
}
Now everything is fine, but I would prefer to see a better solution since doing 3 conversion is not that efficient.
I have created a custom class list which is filled from the result of a query. Specifically, me query returns (int, timestamp) 2 columns -> 2 values.
public class SucessfulCompletion
{
public int Result;
public string Timestampvalue;
public SucessfulCompletion(int result, string timestamp) => (Result, Timestampvalue) = (result, timestamp);
}
public List<SucessfulCompletion> SuccessfulCalculationsTimestamp(string connectionstring)
{
List<SucessfulCompletion> QueryListResult = new List<SucessfulCompletion>();
using (SqlConnection sqlConnection = new SqlConnection(connectionstring))
{
var query_table_timestamp = (
#"SELECT CASE
WHEN t.STATUS = 'SUCCESS' AND t.STATUS_DESCRIPTION = 'ALL QUERIES COMPLETED SUCCESSFULLY' THEN 1
ELSE 0
END SuccessfulCompletion, t.TIMESTAMP
FROM (SELECT TOP (1) l.TIMESTAMP, l.STATUS, l.STATUS_DESCRIPTION
FROM LOG_DETAILS l
ORDER BY 1 DESC) t");
sqlConnection.Open();
using (SqlCommand sqlCommand = new SqlCommand(query_table_timestamp, sqlConnection))
{
using (SqlDataReader reader = sqlCommand.ExecuteReader())
{
while (reader.Read())
{
QueryListResult.AddRange(new List<SucessfulCompletion>
{
new SucessfulCompletion(reader.GetInt32(0), reader.GetDateTime(1).ToString())
});
}
reader.Close();
}
sqlCommand.Cancel();
}
}
return QueryListResult;
}
The code to create the custom class list was taken from this SO question
So the QueryListResult would be like [1, "2020-10-04 HH:MM:SS"]
Now I want to make an if statement to check if the first index of the QueryListResult is ether 0 or 1.
List<SucessfulCompletion> reportsucessfulcompletion = new List<SucessfulCompletion>();
reportsucessfulcompletion = SuccessfulCalculationsTimestamp(SQLServerConnectionDetails());
if (reportsucessfulcompletion[0]=1) //my problem is here
{
//Enable is only if successful
PreviewCalculationsButton.IsEnabled = true;
PreviewReportButton.IsEnabled = true;
//add textbox of success
SQLSuccessfulTextCalculations.Text = String.Format("Completed On: {0}", reportsucessfulcompletion[1]);
}
else
{
//add textbox of fail
SQLFailedTextCalculations.Text = String.Format("Failed On: {0}", reportsucessfulcompletion[1]);
}
In the if statement I get an error
Cannot implicitly convert type 'int' to 'TestEnvironment.MainWindow.SucessfulCompletion'
I know it may be a silly question for someone experienced with C# but I am a newbie, so I would appreciate your help. Please inform me in the comments if the theme of the question is a duplicate one I will close the question.
You're comparing an jnstance of your class to a number.
These are different things.
And one equal sign sets rather than compares
Try
If ( reportsucessfulcompletion[0].Result == 1)
You should make these properties rather than variables.
I also recommend Dapper as a "micro" orm very close to the ado metal, but which saves a fair bit of coding whilst implementing best practice for you.
So I'm working on learning LINQ and was assigned to work with two .txt files and to join them.
So far I'm doing well, but I've reached a bit of an impasse with the display. I'm supposed to have the name display once and then the following cases that are closed have only the case information.
The issue I'm having is that the name keeps repeating after the dataset is listed in the ListView. I think there is something wrong with the LINQ statement or the way I'm going through the foreach loop. Here is the code for the main form below:
//Fills the lists by calling the methods from the DB classes
techs = TechnicianDB.GetTechnicians();
incidents = IncidentDB.GetIncidents();
//Creates a variable to use in the LINQ statements
var ClosedCases = from Incident in incidents
join Technician in techs
on Incident.TechID equals Technician.TechID
where Incident.DateClosed!= null
orderby Technician.Name, Incident.DateOpened descending
select new { Technician.Name, Incident.ProductCode, Incident.DateOpened, Incident.DateClosed, Incident.Title };
//variables to hold the technician name, and the integer to increment the listview
string techName = "";
int i = 0;
//foreach loop to pull the fields out of the lists and to display them in the required areas in the listview box
foreach (var Incident in ClosedCases)
{
foreach (var Technician in ClosedCases)
{
if (Technician.Name != techName)
{
lvClosedCases.Items.Add(Technician.Name);
techName = Technician.Name;
}
else
{
lvClosedCases.Items.Add("");
}
}
lvClosedCases.Items[i].SubItems.Add(Incident.ProductCode);
lvClosedCases.Items[i].SubItems.Add(Incident.DateOpened.ToString());
lvClosedCases.Items[i].SubItems.Add(Incident.DateClosed.ToString());
lvClosedCases.Items[i].SubItems.Add(Incident.Title);
i++;
}
And here is the result I get: Result
As can be seen by the bar on the right hand side, the list continues on for several more columns.
What am I missing here?
Thank you.
EDIT: Per request, here is what the results are supposed to look like:
The example I was given
Why you are iterating closed cases twice?
foreach (var Incident in ClosedCases)
{
foreach (var Technician in ClosedCases)
{
}
}
This section simply reads from an excel spreadsheet. This part works fine with no performance issues.
IEnumerable<ImportViewModel> so=data.Select(row=>new ImportViewModel{
PersonId=(row.Field<string>("person_id")),
ValidationResult = ""
}).ToList();
Before I pass to a View I want to set ValidationResult so I have this piece of code. If I comment this out the model is passed to the view quickly. When I use the foreach it will take over a minute. If I hardcode a value for item.PersonId then it runs quickly. I know I'm doing something wrong, just not sure where to start and what the best practice is that I should be following.
foreach (var item in so)
{
if (db.Entity.Any(w => w.ID == item.PersonId))
{
item.ValidationResult = "Successful";
}
else
{
item.ValidationResult = "Error: ";
}
}
return View(so.ToList());
You are now performing a database call per item in your list. This is really hard on your database and thus your performance. Try to itterate trough your excel result, gather all users and select them in one query. Make a list from this query result (else the query call is performed every time you access the list). Then perform a match between the result list and your excel.
You need to do something like this :
var ids = so.Select(i=>i.PersonId).Distinct().ToList();
// Hitting Database just for this time to get all Users Ids
var usersIds = db.Entity.Where(u=>ids.Contains(u.ID)).Select(u=>u.ID).ToList();
foreach (var item in so)
{
if (usersIds.Contains(item.PersonId))
{
item.ValidationResult = "Successful";
}
else
{
item.ValidationResult = "Error: ";
}
}
return View(so.ToList());