I have a table with DateCreated and DateUpdated columns and using Entity Framework to insert/update values to the database.
I need the DateCreated column to get the SQL Server's GetDate() value on insertion only.
DateUpdated column value should always get updated with current GetDate() value on insertion and update both.
For the DateCreated column, I've set StoreGeneratedPattern="Computed" and on SQL Server table I've set default value of the column to be GetDate(), which works nicely as expected.
For the DateUpdated column I could not find a way to get the GetDate() value automatically set each time an entry is updated. This value get's set only when an entry is inserted.
Could someone shed some light on this.
If you want DateUpdated to be set by the database, you can use a trigger to set the value to getdate(). I believe EF will also get the value set by the trigger if you set StoreGeneratedPattern="Computed" for DateUpdated.
For reference, your trigger would look something like this (you'll have to update per your table's PK):
create trigger MyTable_UpdatedTrigger
on MyTable
for update
as
begin
update t set DateUpdated = getdate()
from MyTable t
join inserted i on t.Id = i.Id
end
Related
I want to be able to add a date that the cell in a row was modified (it is a boolean so from false to true) and i want it to override the last date? I want to use this as the trigger for a zap and all i have found so far is that I can add CURRENT_TIMESTAMP AS "current_timestamp" to my select statement within my create or replace view command. This then doesn't update when i make changes to a row and keeps the original date. Any ideas?
PostgreSQL database stores ID of transaction for every row and may store transaction-commit timestamps if the configuration parameter track_commit_timestamp is set to TRUE
if it is set to TRUE then you can select the row-last-modification-moment by using function pg_xact_commit_timestamp withing system column xmin
the query would be like this:
SELECT some_columns, pg_xact_commit_timestamp(t.xmin) AS change_moment
FROM thetable AS t
create automatic datetime(date with timestamp) when update the data in postgresql(phppgadmin) on database table
Plese advise me
thanks
1.if you use timestamp type in the column when you update the record then date time also updated
2.if you use varchar type in the column when you fire a query
demo
$sql = "update table_name set field_name=now() where your condition";
I've been searching for a while trying to figure this out. I'm trying to create a table with a composite primary key. The first part of the key is also a foreign key to the parent table. The second part is autogenerated on the SQL Server. So, I have a table that should look like this:
ParentId ChildId
-------- -------
1 1
1 2
1 3
2 1
2 2
2 3
2 4
The ChildId column is only unique within the context of the ParentId. The values are autogenerated on the server using an INSTEAD OF INSERT trigger so that each ChildId has its own sequence.
My issue is that while this works grand within SQL Server, and classic ADO.NET SqlCommand statements, Entity Framework does not want to work with this.
If I set the ChildId column's StoreGeneratedPattern to be an Identity then EF generates SQL that looks like this:
insert [dbo].[ChildTable]([ParentId], [Name])
values (#0, #1)
select [ChildId]
from [dbo].[ChildTable]
where ##ROWCOUNT > 0 and [ParentId] = #0 and [Id] = scope_identity()
This just generates an error:
System.Data.Entity.Infrastructure.DbUpdateConcurrencyException : Store
update, insert, or delete statement affected an unexpected number of
rows (0). Entities may have been modified or deleted since entities
were loaded. Refresh ObjectStateManager entries.
---->
System.Data.OptimisticConcurrencyException : Store update, insert, or
delete statement affected an unexpected number of rows (0). Entities
may have been modified or deleted since entities were loaded. Refresh
ObjectStateManager entries.
However, if I create a test table with a key based on a GUID and set the StoreGeneratedPattern to be an Identity then the SQL generated looks like this:
declare #generated_keys table([Id] uniqueidentifier)
insert [dbo].[GuidTable]([Name])
output inserted.[Id] into #generated_keys
values (#0)
select t.[Id]
from #generated_keys as g join [dbo].[GuidTable] as t on g.[Id] = t.[Id]
where ##ROWCOUNT > 0
And the entity in my application is updated with the value of the GUID that the SQL Server generated.
So, that suggests that the column does not have to be an IDENTITY column in order for the Entity Framework to get a value back, however, since it uses the logical table inserted the value of ChildId won't be the value that it was changed to by the trigger. Also, the inserted table cannot have an UPDATE operation applied to it to push the values back inside the trigger (Tried that, it said "The logical tables INSERTED and DELETED cannot be updated.")
I feel that I've kind of backed myself in to a corner here, but before I rethink the design is there any way to get the ChildId value(s) back into the application via Entity Framework?
I found this article which offered a suggestion: http://wiki.alphasoftware.com/Scope_Identity+in+SQL+Server+with+nested+and+INSTEAD+OF+triggers
The TL;DR version is that the INSTEAD OF INSERT performs a SELECT at the end to return the keys. The article was for the loss of the SCOPE_IDENTITY() value due to the trigger but it also works here too.
So, what I did was this:
The Trigger now now reads
ALTER TRIGGER dbo.IOINS_ChildTable
ON dbo.ChildTable
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
-- Acquire the lock so that no one else can generate a key at the same time.
-- If the transaction fails then the lock will automatically be released.
-- If the acquisition takes longer than 15 seconds an error is raised.
DECLARE #res INT;
EXEC #res = sp_getapplock #Resource = 'IOINS_ChildTable',
#LockMode = 'Exclusive', #LockOwner = 'Transaction', #LockTimeout = '15000',
#DbPrincipal = 'public'
IF (#res < 0)
BEGIN
RAISERROR('Unable to acquire lock to update ChildTable.', 16, 1);
END
-- Work out what the current maximum Ids are for each parent that is being
-- inserted in this operation.
DECLARE #baseId TABLE(BaseId int, ParentId int);
INSERT INTO #baseId
SELECT MAX(ISNULL(c.Id, 0)) AS BaseId, i.ParentId
FROM inserted i
LEFT OUTER JOIN ChildTable c ON i.ParentId = c.ParentId
GROUP BY i.ParentId
-- The replacement insert operation
DECLARE #keys TABLE (Id INT);
INSERT INTO ChildTable
OUTPUT inserted.Id INTO #keys
SELECT
i.ParentId,
ROW_NUMBER() OVER(PARTITION BY i.ParentId ORDER BY i.ParentId) + b.BaseId
AS Id,
Name
FROM inserted i
INNER JOIN #baseId b ON b.ParentId = i.ParentId
-- Release the lock.
EXEC #res = sp_releaseapplock #Resource = 'IOINS_ChildTable',
#DbPrincipal = 'public', #LockOwner = 'Transaction'
SELECT Id FROM #keys
END
GO
The Entity Model has the Id column's StoreGeneratedPattern set to being Identity. This means that when Entity Framework attempts to read the SCOPE_IDENTITY() it will get the value the SELECT statement in the trigger supplied rather than the value its own SELECT ... SCOPE_IDENTITY() supplied, which is now in the next result set which EF wasn't expecting and will ignore.
This has some obvious issues.
Because the trigger now selects data to be returned from the trigger it means that other code, say a stored proc, that inserts some data and performs its own select is going to have the data from its own selected pushed out. So if you have code expecting only one result set from a database operation, it now has an additional result set.
If you are only ever going to use the entity framework then this may all be fine. However, I can't say what the future holds so I'm not entirely comfortable with this solution.
I have a sybase 15 DB and for one of my tables, I want to make a column default to the current date/time of the row insert. Is this possible?
In a sybase text, the following is said:
ALTER TABLE sales_order
MODIFY order_date DEFAULT CURRENT DATE
On my DB this doesn't do anything, as CURRENT DATE is not recognized.
using getDate() is a valid solution, you must have had a syntax error. Try it like this:
create table test_tbl (
date_data DATETIME default getDate() NOT NULL
)
Try using getDate() instead
... DEFAULT GETDATE() is correct. the case is irrelevant; mixed case may indicate a Java method, but it is a straight TSQL Function. Please post the exact error msg if you want further assistance.
Also, the ALTER TABLE method sets the Default for future INSERTS; if you want the existing data changed, you need to UPDATE (good for small tables) or unload/reload the table (demanded for the large).
Watch the NULL/NOT NULL: you do not want to change that without understanding. Again, the existing/future issue needs address. NOT NULL prevents NULL being explicitly passed as an INSERT VALUE.
CURRENT_DATE is a SQL standard that isn't universally adopted.
As noted elsewhere the getdate() T-SQL function should be used instead.
Using a SQL 2008 R2 November release database and a .net 4.0 Beta 2 Azure worker role application. The worker role collects data and inserts it into a single SQL table with one identity column. Because there will likely be multiple instances of this worker role running, I created an Insert Instead Of trigger on the SQL table. The trigger performs Upsert functionality using the SQL Merge function. Using T-SQL I was able to verify the insert instead of trigger functions correctly, new rows were inserted while existing rows were updated.
This is the code for my trigger:
Create Trigger [dbo].[trgInsteadOfInsert] on [dbo].[Cars] Instead of Insert
as
begin
set nocount On
merge into Cars as Target
using inserted as Source
on Target.id=Source.id AND target.Manufactureid=source.Manufactureid
when matched then
update set Target.Model=Source.Model,
Target.NumDoors = Source.NumDoors,
Target.Description = Source.Description,
Target.LastUpdateTime = Source.LastUpdateTime,
Target.EngineSize = Source.EngineSize
when not matched then
INSERT ([Manufactureid]
,[Model]
,[NumDoors]
,[Description]
,[ID]
,[LastUpdateTime]
,[EngineSize])
VALUES
(Source.Manufactureid,
Source.Model,
Source.NumDoors,
Source.Description,
Source.ID,
Source.LastUpdateTime,
Source.EngineSize);
End
Within the worker role I am using Entity Framework for an object model. When I call the SaveChanges method I receieve the following exception:
OptimisticConcurrencyException
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
I understand this is likly due to SQL not reporting back an IdentityScope for each new inserted/updated row. Then EF thinks the rows were not inserted and the transaction is not ultimately not committed.
What is the best way to handle this exception? Maybe using OUTPUT from the SQL merge function?
Thanks!
-Paul
As you suspected, the problem is that any insertions into a table with an Identity column are immediately followed by a select of the scope_identity() to populate the associated value in the Entity Framework. The instead of trigger causes this second step to be missed, which leads to the 0 rows inserted error.
I found an answer in this StackOverflow thread that suggested adding the following line at the end of your trigger (in the case where the item is not matched and the Insert is performed).
select [Id] from [dbo].[TableXXX] where ##ROWCOUNT > 0 and [Id] = scope_identity()
I tested this with Entity Framework 4.1, and it solved the problem for me. I have copied my entire trigger creation here for completeness. With this trigger defenition I was able to add rows to the table by adding Address entities to the context and saving them using context.SaveChanges().
ALTER TRIGGER [dbo].[CalcGeoLoc]
ON [dbo].[Address]
INSTEAD OF INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT OFF;
-- Insert statements for trigger here
INSERT INTO Address (Street, Street2, City, StateProvince, PostalCode, Latitude, Longitude, GeoLoc, Name)
SELECT Street, Street2, City, StateProvince, PostalCode, Latitude, Longitude, geography::Point(Latitude, Longitude, 4326), Name
FROM Inserted;
select AddressId from [dbo].Address where ##ROWCOUNT > 0 and AddressId = scope_identity();
END
I had almost exactly the same scenario: Entity Framework-driven inserts to a view with an INSTEAD OF INSERT trigger on it were resulting in the "...unexpected number of rows (0)..." exception. Thanks to Ryan Gross's answer I fixed it by adding
SELECT SCOPE_IDENTITY() AS CentrePersonID;
at the end of my trigger, where CentrePersonID is the name of the key field of the underlying table that has an auto-inrcementing identity. This way the EF can discover the ID of the newly-inserted record.