Я пытаюсь сохранить .Net TimeSpan
в SQL Server 2008 R2.
EF Code First предполагает, что он должен храниться в виде Time(7)
SQL.
Однако TimeSpan
в .Net можно обрабатывать более длительные периоды, чем 24 часа.
Каков наилучший способ хранения .Net TimeSpan
на сервере SQL?
.net
sql-server
timespan
GraemeMiller
источник
источник
Ответы:
Я бы сохранил его в базе данных как
BIGINT
и я бы сохранил количество тиков (например, свойство TimeSpan.Ticks ).Таким образом, если бы я хотел получить объект TimeSpan при его получении, я мог бы просто сделать TimeSpan.FromTicks (значение), что было бы легко.
источник
SELECT CAST(DATEADD(MILLISECOND, @Ticks/CAST(10000 AS BIGINT), '1900-01-01') AS TIME)
.'1900-01-01'
Дата не имеет значения, конечно, это всего лишь третья переменная требуетDATEADD(...)
функции. Помните, что в тике есть 100 наносекунд, но если вы используете,DATEADD(NANOSECOND...
вы, вероятно, получите переполнение, следовательно, используя миллисекунды. Также помните, что вы должны проверить этот факт, используя C #TimeSpan.TicksPerMillisecond
(должно быть 10000), чтобы быть уверенным.Спасибо за совет. Как нет эквивалента в SQL-сервере. Я просто создал 2-е поле, которое преобразовало TimeSpan в тики и сохранило его в БД. Я тогда предотвратил сохранение TimeSpan
источник
Если вам не нужно хранить более 24 часов, вы можете просто сохранить время , поскольку в SQL Server 2008 и более поздних версиях сопоставление
time (SQL Server) <-> TimeSpan(.NET)
Конверсии не нужны, если вам нужно хранить только 24 часа или меньше.
Источник: http://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx
Но если вы хотите хранить более 24 часов, вам нужно будет хранить его в тиках, извлекать данные и затем преобразовывать их в TimeSpan. Например
источник
Time
тип SQL предназначен не для представления длительности, а для части времени значения DateTime; это ужасный выбор дляTimeSpan
.Прямого эквивалента нет. Просто сохраните его в числовом виде, например, количество секунд или что-то соответствующее вашей требуемой точности.
источник
Я знаю, что это старый вопрос, но я хотел убедиться, что есть несколько других вариантов.
Поскольку вы не можете хранить TimeSpan больше 24 часов в поле типа данных sql time; пара других вариантов может быть.
Используйте varchar (xx) для хранения ToString TimeSpan. Преимуществом этого является то, что точность не должна быть включена в тип данных или вычисление, (секунды против миллисекунд против дней против удач). Все, что вам нужно, это использовать TimeSpan.Parse / TryParse. Это то, что я бы сделал.
Используйте вторую дату, datetime или datetimeoffset, которая хранит результат первой даты + временной интервал. Чтение из БД - это вопрос TimeSpan x = SecondDate - FirstDate. Использование этой опции защитит вас от доступа других библиотек доступа к данным .NET к тем же данным, но не понимающих TimeSpans; в случае, если у вас есть такая среда.
источник
Чтобы соответствовать тому, что, вероятно, является наиболее вероятным источником генерации промежутка времени (вычисляя разницу в 2 раза или дату-время), вы можете сохранить .NET
TimeSpan
какDateTime
тип SQL Server .Это связано с тем, что в SQL Server разница в 2
DateTime
(Cast
toFloat
, а затемCast
обратно в aDateTime
) является простоDateTime
относительной относительно 1 января 1900 года. Пример. Разница в +0,1 секунды будет равна 1 января 1900 г. 00: 00: 00,100, а -0,1 секунды - 31 декабря 1899 г. 23: 59: 59,900.Чтобы преобразовать .NET
TimeSpan
вDateTime
тип SQL Server , вы должны сначала преобразовать его вDateTime
тип .NET , добавив его кDateTime
1 января 1900 года. Конечно, когда вы читаете его в .NET из SQL Server, вы должны сначала прочитайте это в .NETDateTime
и затем вычтите 1 января 1900 из этого, чтобы преобразовать это в .NETTimeSpan
.Для случаев использования, когда промежутки времени генерируются из SQL Server
DateTime
и в SQL Server (т.е. через T-SQL), а SQL Server - до 2016 года, в зависимости от вашего диапазона и требований к точности, их хранение может оказаться нецелесообразным в миллисекундах (не говоря ужеTicks
), потому чтоInt
тип, возвращаемыйDateDiff
(по сравнениюBigInt
с SS 2016 +DateDiff_Big
) переполняется через ~ 24 дня миллисекунд и ~ 67 лет. секунд. Принимая во внимание, что это решение будет обрабатывать промежутки времени с точностью до 0,1 секунды и от -147 до +8,099 лет.ПРЕДУПРЕЖДЕНИЯ:
Это сработает только в том случае, если разница относительно 1 января 1900 года приведет к значению в диапазоне типа SQL Server
DateTime
(с 1 января 1753 по 31 декабря 9999 или от -147 до +8,099 лет). Нам не нужно сильно беспокоиться оTimeSpan
стороне .NET , поскольку она может хранить от ~ 29 до +29 лет. Я не упомянулDateTime2
тип SQL Server (чей диапазон, с отрицательной стороны, намного больше, чем у SQL ServerDateTime
), потому что: a) он не может быть преобразован в числовое с помощью простогоCast
и b)DateTime
должен быть достаточный диапазон для подавляющего большинства случаев использования.SQL Server
DateTime
различие , подсчитанное поCast
- к -Float
- и - метод обратный не появляется , чтобы быть точными за 0,1 секунды.источник
Существует несколько способов представления временного интервала в базе данных.
время
Этот тип данных поддерживается начиная с SQL Server 2008 и является предпочтительным способом хранения
TimeSpan
. Нет необходимости в отображении. Это также хорошо работает с кодом SQL.Однако, как указано в исходном вопросе, этот тип данных ограничен 24 часами.
DateTimeOffset
Тип
datetimeoffset
данных отображается непосредственно наSystem.DateTimeOffset
. Он используется для выражения смещения междуdatetime
/datetime2
UTC, но вы также можете использовать его дляTimeSpan
.Однако, поскольку тип данных предлагает очень специфическую семантику, вам следует также рассмотреть другие варианты.
datetime / datetime2
Одним из подходов может быть использование
datetime
илиdatetime2
типов. Это лучше всего в сценариях, где вам нужно обрабатывать значения в базе данных напрямую, т.е. для просмотра, хранимых процедур или отчетов. Недостатком является то, что вам необходимо вычесть значениеDateTime(1900,01,01,00,00,00)
из даты, чтобы получить временной интервал в вашей бизнес-логике.BIGINT
Другим подходом может быть преобразование TimeSpan в тики и использование
bigint
типа данных. Однако этот подход имеет тот недостаток, что его громоздко использовать в запросах SQL.VARCHAR (N)
Это лучше всего подходит для случаев, когда значение должно быть читаемым человеком. Вы также можете использовать этот формат в запросах SQL, используя
CONVERT(datetime, ValidityPeriod)
функцию. В зависимости от требуемой точности вам потребуется от 8 до 25 символов.Бонус: период и продолжительность
Используя строку, вы также можете хранить типы данных NodaTime , особенно
Duration
иPeriod
. Первый в основном такой же, как TimeSpan, в то время как последний учитывает, что некоторые дни и месяцы длиннее или короче других (т.е. в январе 31 день, а в феврале 28 или 29; некоторые дни длиннее или короче из-за перехода на летнее время ). В таких случаях использование TimeSpan - неправильный выбор.Вы можете использовать этот код для преобразования периодов:
А потом использовать как
Мне очень нравится,
NodaTime
и это часто спасает меня от хитрых ошибок и много головной боли. Недостатком здесь является то, что вы действительно не можете использовать его в запросах SQL, и вам нужно выполнять вычисления в памяти.Пользовательский тип CLR
У вас также есть возможность использовать пользовательский тип данных и
TimeSpan
напрямую поддерживать пользовательский класс. См. Пользовательские типы CLR для деталей.Недостатком здесь является то, что тип данных может плохо работать с отчетами SQL. Кроме того, некоторые версии SQL Server (Azure, Linux, Data Warehouse) не поддерживаются.
Преобразование значений
Начиная с EntityFramework Core 2.1, у вас есть возможность использовать преобразование значений .
Однако при использовании этого EF не сможет конвертировать многие запросы в SQL, в результате чего запросы будут выполняться в памяти; потенциально переносит много и много данных в ваше приложение.
Поэтому, по крайней мере, на данный момент, может быть, лучше не использовать его, а просто отобразить результат запроса с помощью Automapper .
источник
Обычно я храню TimeSpan как bigint, заполненный тиками из свойства TimeSpan.Ticks, как было предложено ранее. Вы также можете сохранить TimeSpan как varchar (26), заполненный выводом TimeSpan.ToString (). Четыре скалярные функции (ConvertFromTimeSpanString, ConvertToTimeSpanString, DateAddTicks, DateDiffTicks), которые я написал, полезны для обработки TimeSpan на стороне SQL и позволяют избежать взломов, которые могут привести к искусственно ограниченным диапазонам. Если вы можете сохранить интервал в .NET TimeSpan, он также должен работать с этими функциями. Кроме того, функции позволяют работать с TimeSpans и тиками по 100 наносекунд даже при использовании технологий, не включающих .NET Framework.
источник