I have Dynamic dataWebsite which uses a SQL SP to do update operations..I have a problem here, my delete functionality is also a update (setting IsDeleted=1) operations. I am currently using LINQ query and calling datacontext.SubmitChanges() for deleting. The problem is, the update LINQ query (that sets IsDeleted=1) when I call SubmitChanges() is also calling the update SP which is meant for only Update Operations. Is there any option to fire my LINQ query directly to DB instead of calling update SP?
Employee ild = (from emp in _dataContext.Employee
where emp.IN_ID == int.Parse(ID)
select emp).FirstOrDefault();
ild.IsDeleted=1;
_dataContext.Submitchanges();
The above code always call UpdateSP that is configured to Update operation.
In this case, could you use a delete stored proc which will get called just like your update proc. The delete proc doesn't need to actually perform a DELETE FROM table query, but instead could do an Update on the underlying table setting the IsDeleted flag as appropriate:
CREATE PROCEDURE
#Id int
AS
UPDATE dbo.Employee
SET IsDeleted = 1
WHERE Id = #Id
You would then map this function to the delete behavior in LINQ to SQL just as you did the Update method. With this option, your client code would do a simple Remove on the table rather than dealing with the IsDeleted flag:
_dataContext.Employee.Remove(ild);
_dataContext.SubmitChanges();
In your model, I would argue that you shouldn't expose IsDeleted at all. That is a database implementation detail. When using soft deletes, you should abstract away your physical table and expose the functionality through views or table value functions.
As an alternative to the soft delete option, you could consider including a Tombstone table mimicing your transactional table. On a delete operation, use a stored proc or trigger to move the record from the transactional table to the tombstone table. With that, you could eliminate the IsDeleted flag from the database and elminate the need to include the filtering on all access (including reporting).
I'm not 100% sure that I follow the idea here.
generally to delete the record you would say:
_dataContext.Employee.remove(ild);
_dataContext.Submitchanges();
But it seems like you wanted to just update the record to read any Enployee that has a setting IsDeleted = 1 as a deleted record. By running the code you current have there are are generateing an UPDATE statement and so the UpdateSP will fire.
Is there a reason you can't use the .remove() method and ophysically delete the entry?
Related
I'm writing a trigger in which I need to check the incoming data and potentially change it. Then later in the trigger I need to use that new data for further processing. A highly simplified version looks something like this:
ALTER TRIGGER [db].[trig_update]
ON [db].[table]
AFTER UPDATE
AS
BEGIN
DECLARE #thisprofileID int
IF (Inserted.profileID IS NULL)
BEGIN
SELECT #thisprofileID=profileID
FROM db.otherTable
WHERE userid = #thisuserID;
UPDATE db.table
SET profileID = #thisprofileID
WHERE userid = #thisuserID;
-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
END
IF ({conditional})
BEGIN
UPDATE db.thirdTable
SET [profileID] = Inserted.profileID
...{20+ other fields}
FROM Inserted ...{a few joins}
WHERE {various criteria}
END
END
The problem that we're running into is that the update statement fails because Inserted.profileID is null, and thirdTable.profileID is set to not allow nulls. table.profileID will never stay null; if it is created as null then this trigger should catch it and set it to a value. But even though we're updated 'table', Inserted still has the null value. So far it makes sense to me why this is happening.
I'm unsure how to correct the problem. In the area with commented Xs I tried running an update query against the Inserted table to update profileID, but this resulted in an error because the pseudo-table apparently can't be updated. Am I incorrect in this presumption? That would be an easy solution.
The next most logical solution to me would be to INSERT INTO a table variable to make a copy of Inserted and then use that in the rest of the trigger, but that fails because the table variable is not defined. Defining that table variable would require more fields than I care to count, and will present a major maintenance nightmare any time that we need to make changes to the structure of 'table'. So assuming this is the best approach, is there an easy way to copy the data and structure of Inserted into a table variable without explicitly defining the structure?
I don't think that a temp table (which I could otherwise easily insert into) would be a good solution because my limited understanding is that they are far slower than a table variable that lives only inside the trigger. I assume that temp table also must be public, and cause problems if our trigger fires twice and both instances need the temp table.
In my asp.net mvc application , I use Sql Data Adapter to update a record.
For example
UPDATE sample SET status = 1 WHERE id = #id
I need to test a scenerio where this sql code cannot be run and not any records are updated. How can i make this?
Should i make a lock for sample table and how can i do that ?
How can i make this UPDATE query somehow not works and not updates any record ?
Forgot to note that: I cannot change this code or application code and cannot give random #id parameter.
I need to do that in database level.
You can make the specific table in database read only by using one of the below techniques.
Insert, Update, Delete Trigger
Check Constraint and Delete Trigger
Make the Database Read Only
Put the Table in a Read Only File Group
DENY Object Level Permission
Create a View
You could set id to a value that does not exist for sure (e.g. -1).
Or you could remove the user rights of the user accessing the database (in the connection string) for updating this table. Hoping it's not sa :)
Add an [Authorize] attribute to the controller in question and attempt to perform the operation as a guest user.
Edit. To do it server side, enter the following to a query window on the database
Begin Transaction
That should lock up the database while you do your tests
I have a number of tables that get updated through my app which return a lot of data or are difficult to query for changes. To get around this problem, I have created a "LastUpdated" table with a single row and have a trigger on these complex tables which just sets GetDate() against the appropriate column in the LastUpdated table:
CREATE TRIGGER [dbo].[trg_ListItem_LastUpdated] ON [dbo].[tblListItem]
FOR INSERT, UPDATE, DELETE
AS
UPDATE LastUpdated SET ListItems = GetDate()
GO
This way, the clients only have to query this table for the last updated value and then can decided whether or not they need to refresh their data from the complex tables. The complex tables are using snapshot isolation to prevent dirty reads.
In busy systems, around once a day we are getting errors writing or updating data in the complex tables due to update conflicts in "LastUpdated". Because this occurs in the statement executed by the trigger, the affected complex table fails to save data. The following error is logged:
Snapshot isolation transaction aborted due to update conflict. You
cannot use snapshot isolation to access table 'dbo.tblLastUpdated'
directly or indirectly in database 'devDB' to update, delete, or
insert the row that has been modified or deleted by another
transaction. Retry the transaction or change the isolation level for
the update/delete statement.
What should I be doing here in the trigger to prevent this failure? Can I use some kind of query hints on the trigger to avoid this - or can I just ignore errors in the trigger? Updating the data in LastUpdated is not critical, but saving the data correctly into the complex tables is.
This is probably something very simple that I have overlooked or am not aware of. As always, thanks for any info.
I would say that you should look into using Change Tracking (http://msdn.microsoft.com/en-gb/library/cc280462%28v=sql.100%29.aspx), which is lightweight builtin SQL Server functionality that you can use to monitor the fact that a table has changed, as opposed to logging each individual change (which you can also do with Change Data Capture). It needs Snapshot Isolation, which you are already using.
Because your trigger is running in your parent transaction, and your snapshot has become out of date, your whole transaction would need to start again. If this is a complex workload, maintaining this last updated data in this way would be costly.
Short answer - don't do that! Making the updated transactions dependent on one single shared row makes it prone to deadlocks and and update conflicts whole gammut of nasty things.
You can either use views to determine last update, e.g.:
SELECT
t.name
,user_seeks
,user_scans
,user_lookups
,user_updates
,last_user_seek
,last_user_scan
,last_user_lookup
,last_user_update
FROM sys.dm_db_index_usage_stats i JOIN sys.tables t
ON (t.object_id = i.object_id)
WHERE database_id = db_id()
Or, if you really insist on the solution with LastUpdate, you can implement it's update from the trigger in an autonomous transactions. Even though SQL Server doesn't support autonomous transactions, it could done using liked servers: How to create an autonomous transaction in SQL Server 2008
The schema needs to change. If you have to keep your update table, make a row for every table. That would greatly reduce your locks because each table could update their very own row and not competing for the sole row in a table.
LastUpdated
table_name (varchar(whatever)) pk
modified_date (datetime)
New Trigger for tblListItem
CREATE TRIGGER [dbo].[trg_ListItem_LastUpdated] ON [dbo].[tblListItem]
FOR INSERT, UPDATE, DELETE
AS
UPDATE LastUpdated SET modified_date = GetDate() WHERE table_name = 'tblListItem'
GO
Another option that I use a lot is having a modified_date column in every table. Then people know exactly which records to update/insert to sync with your data rather than dropping and reloading everything in the table each time one record changes or is inserted.
Alternatively, you can update the log table inside the same transaction which you use to update your complex tables inside your application & avoid the trigger altogether.
Update
You can also opt for inserting a new row instead of updating the same row in LastUpdated table. You can then query max timestamp for latest update. However, with this approach your LastUpdated table would grow each day which you need to take care of if volume of transactions is high.
How do I debug a complex query with multiple nested sub-queries in SQL Server 2005?
I'm debugging a stored procedure and trigger in Visual Studio 2005. I'd like to be able to see what the results of these sub-queries are, as I feel that this is where the bug is coming from. An example query (slightly redacted) is below:
UPDATE
foo
SET
DateUpdated = ( SELECT TOP 1 inserted.DateUpdated FROM inserted )
...
FROM
tblEP ep
JOIN tblED ed ON ep.EnrollmentID = ed.EnrollmentID
WHERE
ProgramPhaseID = ( SELECT ...)
Visual Studio doesn't seem to offer a way for me to Watch the result of the sub query. Also, if I use a temporary table to store the results (temporary tables are used elsewhere also) I can't view the values stored in that table.
Is there anyway that I can add a watch or in some other way view these sub-queries? I would love it if there was some way to "Step Into" the query itself, but I imagine that wouldn't be possible.
Ok first I would be leary of using subqueries in a trigger. Triggers should be as fast as possible, so get rid of any correlated subqueries which might run row by row instead of in a set-based fashion. Rewrite to joins. If you only want to update records based on what was in the inserted table, then join to it. Also join to the table you are updating. Exactly what are you trying to accomplish with this trigger? It might be easier to give advice if we understood the business rule you are trying to implement.
To debug a trigger this is what I do.
I write a script to:
Do the actual insert to the table
without the trigger on on it
Create a temp table named #inserted
(and/or one named #deleted)
Populate the table as I would expect
the inserted table in the trigger to
be populated from the insert you do.
Add the trigger code (minus the
create or alter trigger parts)
substituting #inserted every time I
reference inserted. (if you plan to
run multiple times until you are
ready to use it in a trigger throw
it in an explicit transaction and
rollback after checking your
results.
Add a query to check the table(s)
you are changing with the trigger for
the values you wanted to change.
Now if you need to add debug
statements to see what is happening
between steps, you can do so.
Run making changes until you get the
results you want.
Once you have the query working as
you expect it to, it is easy to take
the # signs off inserted and use it
to create the body of the trigger.
This is what I usually do in this type of scenerio:
Print out the exact sqls getting generated by each subquery
Then run each of then in the Management Studio as suggested above.
You should check if different parts are giving you the right data you expect.
I'm using triggers on my sql database to capture change information for a table, it seems to be having a problem with nhibernate though.
The table has a few columns and primary keys and triggers on it. The triggers look like this
CREATE TRIGGER [dbo].[tr_Instrument_update] ON [dbo].[Instrument] FOR UPDATE AS
BEGIN
INSERT [MyAudit].[audit].[Instrument]
SELECT 'Updated', i.*
FROM inserted
INNER JOIN [MyAudit].[dbo].[Instrument] i ON inserted.[InstrumentID] = i.[InstrumentID]
END
Basically on every change we copy the row into the audit table. I have tested and if I modify the data directly through sql management studio triggers function correctly and I get data written to the audit table, however if i update through my app I get the following:
NHibernate.StaleObjectStateException
was unhandled by user code
Message=Row was updated or deleted by
another transaction (or unsaved-value
mapping was incorrect)
I assume this is because the trigger updates another table in another database, is there anyway to make nhibernate ignore this as the change will not affect any of its data, in our mappings we have no reference to this audit data.
Figured out that the trigger was causing Nhibernate to do two identical update calls for some reason. The solution was to SET NOCOUNT ON inside the trigger. Still not sure though why nhibernate makes two updates!