I need to change what rows are grabbed from the database based upon a few flags. How can I do this? My current code is like this:
this.tblTenantTableAdapter.Fill(this.rentalEaseDataSet.tblTenant);
Say if I wanted only rows that the id was greater than 50, how would I do that?
Edit:
The code to access the database was autogenerated by the original programmer a long time ago though VisualStudio. I don't know exactly how to get a connection from the autogenerated code. If I could do that I know how to use the SqlDataAdapter
Why wouldn't you use a WHERE clause in your SQL query?
Also, I would hope you don't use your ID field for anything like this. If you just want the first 50 selections, you may want to use a TOP 50 clause or something similar.
For some info on how to do this with your TableAdapter: http://www.shiningstar.net/ASPNet_Articles/DataSet/DataSetProject7.aspx
On the server side you can use plaid old SQL:
SELECT * FROM TBLTENANT WHERE id > 50
On the client side:
rentalEaseDataSet.tblTenant.DefaultView.RowFilter = "id > 50";
I would imagine that the simplest way is to change whatever SQL query is running behind the scenes using a WHERE clause.
Your TableAdapter needs to have the CommandText specified to a SQL query with a WHERE clause.
private void InitCommandCollection() {
this._commandCollection = new global::System.Data.SqlClient.SqlCommand[1];
this._commandCollection[0] = new global::System.Data.SqlClient.SqlCommand();
this._commandCollection[0].Connection = this.Connection;
this._commandCollection[0].CommandText = #"SELECT * FROM MyTable WHERE ID >50;";
this._commandCollection[0].CommandType = global::System.Data.CommandType.Text;
}
NOTE: The above query is just an example, not meant as a solution query. The format of the above code is used to edit the generated Table Adapter designer class's InitCommandCollection() method so you can specify your own SQL. It is possible your class already has some SQL in here, in which case you could just alter it.
Related
I am trying to test different queries on a dataset from an existing Sql Server DB. I need to be able to grab a row by its id column for the project I am doing. What seems like a straightforward query gets no results however.
DataSet prodspdata = new prodspDataSet();
DataRow[] load;
load = prodspdata.Tables["TripNumber"].Select("[ctripnumber] = '21605178'");
Console.WriteLine(load.Length);
Console.ReadLine();
Output from load.Length is 0. I understand from documentation that load should be an array of rows returned from the Select() query. I know that this result exists from looking in the data so I expect load.length to be 1.
I tested a query from within Sql Server Management Studio to make sure I wasn't missing something:
SELECT * FROM TripNumber WHERE ctripnumber = '21605178'
This returns the 1 row as expected.
Is my Select query bad? I am brand new to C#, am I testing it wrong? I simply need to know if load contains any results so I know that my query works as intended.
EDIT: So it appears my DataTable has no rows.
DataTable loadTable;
loadTable = prodspdata.Tables["TripNumber"];
Console.WriteLine(loadTable.Rows.Count);
Console.ReadLine();
This returns 0 rows whereas loadTable.Columns.Countgives me 133
Did I miss a step, perhaps something to do with a TableAdapter?
Don't use the square brackets in your filtering.
load = prodspdata.Tables["TripNumber"].Select("ctripnumber = '21605178'");
Also remember that you can use Visual Studio debugger to see the contents of DataSets and Datatables.
I had not actually filled my dataset with anything, which was causing the problem. I severely neglected the TableAdapter. The code I added was:
prodspDataSetTableAdapters.TripNumberTableAdapter ta = new prodspDataSetTableAdapters.TripNumberTableAdapter();
DataTable loadTable = ta.GetData();
So without a TableAdapter instantiated and a table filled with the data (based on the TableAdapter's settings) you basically get an empty schema of the database with tables, columns and no values. Rookie mistake.
Given the following code (which is mostly irrelevant except for the last two lines), what would your method be to get the value of the identity field for the new record that was just created? Would you make a second call to the database to retrieve it based on the primary key of the object (which could be problematic if there's not one), or based on the last inserted record (which could be problematic with multithreaded apps) or is there maybe a more clever way to get the new value back at the same time you are making the insert?
Seems like there should be a way to get an Identity back based on the insert operation that was just made rather than having to query for it based on other means.
public void Insert(O obj)
{
var sqlCmd = new SqlCommand() { Connection = con.Conn };
var sqlParams = new SqlParameters(sqlCmd.Parameters, obj);
var props = obj.Properties.Where(o => !o.IsIdentity);
InsertQuery qry = new InsertQuery(this.TableAlias);
qry.FieldValuePairs = props.Select(o => new SqlValuePair(o.Alias, sqlParams.Add(o))).ToList();
sqlCmd.CommandText = qry.ToString();
sqlCmd.ExecuteNonQuery();
}
EDIT: While this question isn't a duplicate in the strictest manner, it's almost identical to this one which has some really good answers: Best way to get identity of inserted row?
It strongly depends on your database server. For example for Microsoft SQL Server you can get the value of the ##IDENTITY variable, that contains the last identity value assigned.
To prevent race conditions you must keep the insert query and the variable read inside a transaction.
Another solution could be to create a stored procedure for every type of insert you have to do and make it return the identity value and accept the insert arguments.
Otherwise, inside a transaction you can implement whatever ID assignment logic you want and be preserved from concurrency problems.
Afaik there is not finished way.
I solved by using client generated ids (guid) so that my method generated the id and returns it to the caller.
Perhaps you can analyse some SqlServer systables in order to see what has last changed. But you would get concurrency issues (What if someone else inserts a very similar record).
So I would recommend a strategy change and generate the id's on the clients
You can take a look at : this link.
I may add that to avoid the fact that multiple rows can exist, you can use "Transactions", make the Insert and the select methods in the same transaction.
Good luck.
The proper approach is to learn sql.
You can do a SQL command followed by a SELECT in one run, so you can go in and return the assigned identity.
See
I'm using SQLite to compare some ids (varchar 50) so I get a numeric database id.
I'm using C# and visual studio 2003. Pretty new in C# so maybe I'm doing a newbie mistake.
When doing some comparison like the following
SELECT * FROM tblUSer WHERE Use_id like '%Ñ120%'
I don't get anything even if this exist... I suppose is an encoding problem, but I don't know how to solve it.
I can't change the database schema since is not my database (need to modify select some data and update a field).
I can't change the data per se since it is a data that already exist and the user codes are the same as some reference like a club id or something...
Changing the data to UTF-8 worked to make it do the query (without it it would give an error) but still I don't get the desired data. Maybe is also how the data is saved by the original program.
What do I do so my query works with the Ñ?
What if your remove the N from your query and just check
Use_id LIKE '%120%'
and then select the appropriate ones in C#?
try this:
SELECT * FROM tblUSer WHERE Use_id like N'%Ñ120%'
Notice the N letter.
You should write in this way:
SELECT * FROM tblUSer WHERE Use_id like N'%Ñ120%'
I have a reports page where you can enter the query manually for a report. How can I block any INSERT, UPDATE or DELETE statements, and only run SELECT?
using (var connection = new SQLiteConnection(connectionString))
{
var da = new SQLiteDataAdapter
{
SelectCommand = new SQLiteCommand(query, connection)
};
try
{
da.Fill(table);
}
I could check if the query string contains "INSERT", "UPDATE" or "DELETE", but I don't think it's a good practice.
You could use an EXPLAIN statement to break the query down into VM instructions and examine the opcode column of the output. If the value "OpenWrite" occurs then the query is not read-only.
Checking the query string is not good practice? Compared to what? Allowing a user to enter any SQL statement they want to in your report page? I can't think of a much worse practice than that. If you're going to allow that sort of thing, you absolutely need to somehow restrict the types of statements they enter, and maybe require a Where clause (to avoid millions of rows being returned) etc.
in fact did you check what happens when you try to fill the table with the data adapter having anything else than a select in the query variable? I doubt you get an empty table or dataset, I would expect an exception in which case you could rollback the transaction.
I would anyway try to create the connection as readonly as suggested above by Sorax and I would actually parse the query variable as well.
Since the SQlite database is just one file, my guess is that you can make the database readonly through the filesystem. This is of course not a fancy solution but is one that does not require any code (of course except when you're throwing exceptions when writing isn't possible).
A) Use a read-only connection - I think that would be almost the best solution
B) Use more than one TextBox as Input (but this would become more a solution like checking the String for Insert etc.)
For Example
Select |____| From |_________| Where |_______|
Edit: to answer your comment just have a look at http://www.sqlite.org/c3ref/open.html especially the topic "SQLITE_OPEN_READONLY" - I haven't done anything with sqlite now, but I think that should do the trick...
This is what I am working with to get back to the web dev world
ASP.Net with VS2008
Subsonic as Data Access Layer
SqlServer DB
Home Project description:
I have a student registration system. I have a web page which should display the student records.
At present I have a gridview control which shows the records
The user logs on and gets to the view students page. The gridview shows the students in the system, where one of the columns is the registration status of open, pending, complete.
I want the user to be able to apply dynamic sorting or filters on the result returned so as to obtain a more refined result they wish to see. I envisioned allowing user to filter the results by applying where clause or like clause on the result returned, via a dataset interface by a subsonic method. I do not want to query the databse again to apply the filter
example: initial query
Select * from studentrecords where date = convert(varchar(32,getdate(),101)
The user then should be able to applly filter on the resultset returned so that they can do a last name like '%Souza%'
Is this even possible and is binding a datasource to a gridview control the best approach or should i create a custom collection inheriting from collectionbase and then binding that to the gridview control?
PS: Sorry about the typo's. My machine is under the influence of tea spill on my laptop
I use LINQ-to-SQL, not Subsonic, so YMMV, but my approach to filtering has been to supply an OnSelecting handler to the data source. In LINQ-to-SQL, I'm able to replace the result with a reference to a DataContext method that returns a the result of applying a table-valued function. You might want to investigate something similar with Subsonic.
As tvanfosson said, LINQ is very well suited to making composable queries; you can do this either with fully dunamic TSQL that the base library generates, or via a UDF that you mark with [FunctionAttribute(..., IsComposable=true)] in the data-context.
I'm not familiar with Subsonic, so I can't advise there; but one other thought: in your "date = " code, you might consider declaring a datetime variable and assigning it first... that way the optimiser can usually do a better job of optimising it (the query is simpler, and there is no question whether it is converting the datetime (per row) to a varchar, or the varchar to a datetime). The most efficient way of getting just the date portion of something is to cast/floor/cast:
SET #today = GETDATE()
SET #today = CAST(FLOOR(CAST(#today as float)) as datetime)
[update re comment]
Re composable - I mean that this allows you to build up a query such that only the final query is executed at the database. For example:
var query = from row in ctx.SomeComplexUdf(someArg)
where row.IsOpen && row.Value > 0
select row;
might go down the the server via the TSQL:
SELECT u1.*
FROM dbo.SomeComplexUdf(#p1) u1
WHERE u1.IsOpen = 1 -- might end up parameterized
AND u1.Value > 0 -- might end up parameterized
The point here being that only the suitable data is returned from the server, rather than lots of data being returned, then thrown away. LINQ-to-SQL can do all sorts of things via compsable queries, including paging, sorting etc. By minimising the amount of data you load from the database you can make significant improvements in performance.
The alternative without composability is that it simply does:
SELECT u1.*
FROM dbo.SomeComplexUdf(#p1) u1
And then throws away the other rows in your web app... obviously, if you are expecting 20 open records and 10000 closed records, this is a huge difference.
How about something like this?
Rather than assigning a data source / table to your grid control, instead attach a 'DataView' to it.
Here's sort of a pseudocode example:
DataTable myDataTable = GetDataTableFromSomewhere();
DataGridView dgv = new DataGridView();
DataView dv = new DataView(myDataTable);
//Then you can specify things like:
dv.Sort = "StudentStatus DESC";
dv.Filter = "StudentName LIKE '" + searchName + '";
dgv.DataSource = dv;
...and so on.