Using an SQLDataSource, how do I update entries by the uniqueID key? It's a simple question but I am soooo confused! I need to edit a value named "pageContent". It is the value that I need to update!
Cheers!
EDIT
This ones for you Jorge:
[key] id/int (No Nulls)
pageContent/nvarchar(MAX) (No Nulls)
Current Content:
[ id ] [ pageContent ]
1 <b>test</b>
2 test
SqlDataSource is used to bind database data to controls on web page and not to preform direct operations on database.
If you just need to update one column in table on given key, consider using System.Data.SqlClient.SqlConnection class to connect to db and System.Data.SqlClient.SqlCommand class to execute sql statement.
EDIT:
Example of use very similar to your case is in SqlCommand.Parameters help: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.parameters.aspx
Related
I am looking for an appropriate way to expand an existing database, based on entity framework 6 code first implementation, and adding unique values to the new field for every existing row in the table.
So far I have created a migration wich adds the new field.
The Up method looks like this:
Public Overrides Sub Up()
AddColumn("dbo.Customers", "UniqueCode", Function(c) c.String(unicode:=False))
End Sub
I am stuck at the point where the new field should be filled with a unique (calculated) value. To keep it simple, let's say every existing row in the database should be assigned a GUID upon the migration.
Using an SQL statement like this would update all rows with the same GUID. But I need it to be unique for every row.
Sql("Update dbo.Customers SET UniqueCode = '" & Guid.NewGuid().ToString)
Using a foreach in the Up method seems kinda wrong... What is best practice in this case?
In addition: The database I am using is access, so I can't use newid() or random(). The GUID is meant to be a dummy for a programmatically calculated value. It will be a hashed value of some other attributes of the customer. So it must be calculated and updated with migration.
I have found the following approach to be the best fit for my situation. I recommend splitting the database and data changes in 2 migrations, which allows you to use the framework for all changes and be fully up and down compatible.
Here the details to my approach:
Following Bradley Uffner's advice I loop through the data and update it row for row. But, doing this within one and the same migration, throws an error:
The model backing the 'DbContext' context has changed since the database was created. Consider using Code First Migrations to update the database.
Using a DbContext in the middle of it's migration leads to an inconsistent state. The model is already in its after migration state, but the database still has the before migration state in the tables. Model and database do not match, which leads to the above error. To make this work, I would have to disable model checking.
Reference: Change data in migration Up method - Entity Framework
In the above thread I found the suggestion to separate database changes from data changes. That's exactly what I did.
I created one migration to update the database
Public Overrides Sub Up()
AddColumn("dbo.Customers", "WebCode", Function(c) c.String(unicode := false))
End Sub
Public Overrides Sub Down()
DropColumn("dbo.Customers", "WebCode")
End Sub
Run the Update-Database command. And then create a second migration to make the data changes. The Up and Down methods will be empty upon creation. Here is the code I use to update the data row by row.
Public Overrides Sub Up()
Dim DbContext As New Data.DbContext
For Each customer In DbContext.Customers.Where(Function(x) String.IsNullOrEmpty(x.WebCode))
customer.WebCode = GetWebCode(customer)
Next
DbContext.SaveChanges()
End Sub
Public Overrides Sub Down()
Dim DbContext As New Data.DbContext
For Each customer In DbContext.Customers
customer.WebCode = Nothing
Next
MyDbContext.SaveChanges()
End Sub
Some might argue using a simple SQL in the Down method like
SQL("Update dbo.Customers SET WebCode = NULL")
is more efficient. I have tried that, but encountered an error at JetEntityFrameworkProvider.JetMigrationSqlGenerator.GenerateSqlStatmentConcrete which I was not able to locate and fix. It made Visual Studio crash.
If your database server is the SQL Server, you can use the builtin newid() function that generates GUIDs at the database server
https://learn.microsoft.com/en-us/sql/t-sql/functions/newid-transact-sql
The query would be
Update dbo.Customers SET UniqueCode = newid()
In case of the SQLite database, use the random() function.
The short version:
I have a grid view bound to a data source which has a SelectCommand with a left join in it because the FK can be null. On Update I want to create a record in the FK table if the FK is null and then update the parent table with the new records ID. Is this possible to do with just SqlDataSources?
The detailed version:
I have two tables: Company and Address. The column Company.AddressId can be null. On my ascx page I am using a SqlDataSource to select a left join of company and address and a GridView to display the results. By having my UpdateCommand and DeleteCommand of the SqlDataSource execute two statements separated by a semi-colon I am able to use the GridView's Edit and Delete functionality to update both table simultaneously.
The problem I have is when the Company.AddressId is null. What I need to have happen is have the data source create a record in the Address table and then update the Company table with the new Address.ID then proceed with the update as usual. I would like to do this with just data sources if possible for consistency/simplicity sake. Is it possible to have my data source do this, or perhaps add a second data source to the page to handle some of this?
Once I have that working I can probably figure out how to make it work with the InsertCommand as well but if you are on a roll and have an answer for how to make that fly as well feel free to provide it.
Thanks.
execute two statements separated by a
semi-colon
I don't see any reason why it wouldn't be possible to do both an INSERT and UPDATE in two statements with SqlDataSource just like you are doing here.
However, just so you know, if you have a lot of traffic or users using the application at the same time, you can run into concurrently issues where one user does something that affects another user and unexpected results can cascade and mess up your data. In general, for things like what you are doing - INSERT and UPDATE involving primary or foreign keys, usually SQL TRANSACTIONs are used. But, you must execute them as SQL stored procedures (or functions), on your SQL database. You are still able to call them from your SqlDataSource however by simply telling it that you are calling a stored procedure.
I'm unable to retrieve the latest inserted id from my SQL Server 2000 db using a typed dataset in asp.NET
I have created a tableadapter and I ticked the "Refresh datatable" and "Generate Insert, Update and Delete statements". This auto-generates the Fill and GetData methods, and the Insert, Update, Select and Delete statements.
I have tried every possible solution in this thread
http://forums.asp.net/t/990365.aspx
but I'm still unsuccesfull, it always returns 1(=number of affected rows).
I do not want to create a seperate insert method as the auto-generated insertCommand perfectly suits my needs.
As suggested in the thread above, I have tried to update the InsertCommand SQL syntax to add SELECT SCOPY_IDENTITY() or something similar, I have tried to add a parameter of type ReturnValue, but all I get is the number of affected rows.
Does anyone has a different take on this?
Thanks in advance!
Stijn
I decided to give up, I can't afford to waste any more time on this.
I use the Insert statement after which I do a select MAX(id) query to hget the insert ID
If anyone should have a solution, I'll be glad to read it here
Thanks
Stijn
I successfully found a way to get the incremental id after insert using my table adapter.
My approach is a little different, I'm using a Store procedure to make the insert, so my insert command has all the values but the ID, I made the sp return the ID just calling:
SET #ID=SCOPE_IDENTITY()
and then
COMMIT TRAN
and last line will be
RETURN #ID
Then I searched my table adapter parameters for InsertCommand and set the #RETURNVALUE to the column of the incremental ID of the table, so when it's executed automatically put the return value on the id field.
Hope this help
You need to tell your table's table-adapter to refresh the
data-table after update/insert operation.
This is how you can do that.
Open the properties of TableAdapter -> Default Select Query -> Advnaced options. and Check the option of Refresh the data table. Save the adapter now. Now when you call update on table-adapter, the data-table will be updated [refreshed] after the update/insert operation and will reflect the latest values from database table. if the primary-key or any coloumn is set to auto-increment, the data-table will have those latest value post recent update.
Now you can Call the update as TableAdapterObj.Update(ds.dataTable);
Read latest values from the DataTable(ds.dataTable) coloumns and assign respective values into the child table before update/insert. This will work exactly the way you want.
alt text http://ruchitsurati.net/files/tds1.png
I have a table which links to another table in the ASP.NET membership schema.
Problem is, all the PKs for the ASP.NET tables are uniqueidentifier so mine has to be too. When I add a SqlDatasource and call its Insert() method, I get the following error:
Cannot insert the value NULL into column 'DiscountCode', table 'CreamDb.dbo.CustomInfo1'; column does not allow nulls. INSERT fails.
The statement has been terminated.
The uniqueidentifier is also treated as an object (its data type), but there is no Guid data type. I had this problem before, but the schema was much simpler so I could fix it.
How can I go about fixing this? If I get rid of the data type part in the markup (so just leave the field/parameter name but not the data type stuff), I get another error so that is not possible.
Thanks
What do you mean by "there is no Guid data type"? What's wrong with System.Guid? Can't you just use Guid.NewGuid(), set the field appropriately, and do the insert?
EDIT: Just to give a bit more meat: attach an event handler to the Inserting event, and populate the field then, via the DbCommand returned by SqlDataSourceCommandEventArgs.Command. Or change the SQL used by the INSERT command to ask the database to populate the GUID field for you.
A popullar approach when dealing with references to the ASP.NET Membership Provider's data is, instead of keeping a proper foreign key to the GUIDs, instead store something like the LoweredUserName in your table. Then, use the Membership Provider's API to interact with the object you need. In some cases, you need an ObjectDataSource abstraction layer to accomplish CRUD scenarios.
Set the default value of the column in SQL Sever to "newid()".
Asp.net won't send the value, and the field will get a new guid.
I will explain problem with an example:
There is two table in my database, named entry, tags
There is a column named ID_ENTRY in both table. When I add a record to table, entry, I have to take the ID_ENTRY of last added record and add it to table, tags. How can I do it?
The only way to do this is with multiple statements. Using dynamic sql you can do this by separating each statement in your query string with a semi-colon:
"DECLARE #ID int;INSERT INTO [Entry] (...) VALUES ...; SELECT #ID = scope_identity();INSERT INTO [TAGS] (ID_ENTRY) VALUES (#ID);"
Make sure you put this in a transaction to protect against concurrency problems and keep it all atomic. You could also break that up into two separate queries to return the new ID value in the middle if you want; just make sure both queries are in the same transaction.
Also: you are using parameterized queries with your dynamic sql, right? If you're not, I'll personally come over there and smack you 10,000 times with a wet noodle until you repent of your insecure ways.
Immediatly after executing the insert statement on first table, you should query ##IDENTITY doing "SELECT ##identity". That will retrieve the last autogenerated ID... and then just insert it on the second table.
If you are using triggers or something that inserts rows... this may be not work. Use Scope_Identity() instead of ##IDENTITY
I would probably do this with an INSERT trigger on the named entry table, if you have all of the data you need to push to the tags table available. If not, then you might want to consider using a stored procedure that creates both inside a transaction.
If you want to do it in code, you'll need to be more specific about how you are managing your data. Are you using DataAdapter, DataTables, LINQ, NHibernate, ...? Essentially, you need to wrap both inserts inside a transaction of some sort so that either inserts get executed or neither do, but the means to doing that depend on what technology you are using to interact with the database.
If you use dynamic sql, why not use Linq to Entity Framework, now EF is the recommend data access technology from Microsoft (see this post Clarifying the message on L2S Futures from ADO.NET team blog), and if you do an insert with EF the last identity id will available for you automatically, I use it all the time it's easy.
Hope this helps!
Ray.