简体   繁体   中英

How to insert and update SQL Server DateTime in a date column using Entity Framework Core in .NET Core

I have a table that contains a LastUpdateOn column, I would like to keep SQL Server current date & time (using GETDATE() ) in this column whenever I am doing insert or update operation in my table.

In ADO.NET, we used to call GETDATE() function in insert/update statements, but how we can achieve the same thing using Entity Framework Core?

Reason to store SQL Server date time is we do not want to store the application server date time in LastUpdateOn column as application will be running from different servers and their clock might be not in Sync so we want to store common time from all the places(app servers).

There are two quick solutions for this on top of my head:

  1. Simple put the value as default to GetDate() on this columns and pass null to EF when inserting or update;

  2. Create a function that calls GetDate() before an inserting/update and use this as the value;

Edit:

  1. Create a new EF configuration for DateTime values that get the GetDate() function before inserting/update and automate the process;

So as I moved away from stored procedures (where I used "GetDate()" or "CURRENT_TIMESTAMP" alot)... I embraced the c#/middleware layer.

I do a "null check" and set it on the c# code (in the entity framework data layer code)

Below shows DateTime. DateTime.MinValue means "somebody did not explicitly set it".

 myEntityFrameworkEntity.InsertDate = parameterInsertDateValue == DateTime.MinValue ? DateTime.Now : parameterInsertDateValue;

There are other variations, but the idea is the same. Did the "caller" explicitly set the property, or did they not set it, let me write a value on their behalf.

Now, sometimes I don't care what the caller set. If it is a LastUpdatedDate , you can just "force it" as well (always set it to DateTime.Now)....

// i don't care what the parameters are, i always update it in this layer
myEntityFrameworkEntity.LastUpdatedDate = DateTime.Now;

Also, instead of using DateTime(.Now) directly... I use this:

https://github.com/vfabing/Chronos.Net

You "inject" a DateTime-PROVIDER .. that can be mocked for Unit-Tests.

Here is a more complete example to show my EF code (for Rest-Services that needs "disconnected" entities).

    public const int ExpectedAddSingleOrUpdateSingleOrDeleteSingleSaveChangesAsyncRowCount = 1;

    public async Task<EmployeeEfEntity> UpdateAsync(
        EmployeeEfEntity inputEmployee,
        CancellationToken token)
    {
        int saveChangesAsyncValue = 0;
        
        /* find the object in the db-context using the object surrogate-primary-key (since this is an update) */
        EmployeeEfEntity foundEntity =
            await this.entityDbContext.EmployeeEfEntitys.FirstOrDefaultAsync(
                item => item.EmployeeEfEntityKey == inputEmployee.EmployeeEfEntityKey,
                token);

        if (null != foundEntity)
        {
            /* update the found-entity with the properties of the input object */

            /* the "normal" properties of the employee */
            foundEntity.EmployeeBadgeNumber = inputEmployee.EmployeeBadgeNumber;

            /* if the insert-date was explicit, use it, otherwise default to date-time.now */
            foundEntity.InsertDate = inputEmployee.InsertDate == DateTime.MinValue ? DateTime.Now : inputEmployee.InsertDate;

            /* we do not care about the input parameters, we always set it to "now" */
            foundEntity.LastUpdated = inputEmployee.LastUpdated == DateTime.Now;


            this.entityDbContext.Entry(foundEntity).State = EntityState.Modified;
            saveChangesAsyncValue = await this.entityDbContext.SaveChangesAsync(token);
            if (ExpectedAddSingleOrUpdateSingleOrDeleteSingleSaveChangesAsyncRowCount != saveChangesAsyncValue)
            {
                throw new ArgumentOutOfRangeException(
                    string.Format(ErrorMsgExpectedSaveChangesAsyncRowCount, saveChangesAsyncValue),
                    (Exception)null);
            }
        }
        else
        {
            ArgumentOutOfRangeException argEx = new ArgumentOutOfRangeException(
                string.Format(ErrorMsgPrimaryEntityNotFound, inputEmployee.EmployeeEfEntityKey),
                (Exception)null);

            this.logger.LogError(argEx);
        }

        return foundEntity;
    }

My code actually uses the Chronos.Net (injected) date-time-provider, but I removed it to keep the code simpler for this answer.

Since you're using Entity framework, which aimed at allowing database usage to be handled in C# more, I would just use DateTime.Now (DateTime.UtcNow if you want UTC time).

Set LastUpdateOn to DateTime.Now or DateTime.Utc.Now each time you enter/upate a record.

If you really want to use SQL server's GETDATE() method, then write a stored procedure that takes an interger (the id of the record to update) and use it to set LastUpdateOn for the field with the specified id to the value of GETDATE() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM