Saya mencoba untuk menyimpan. Net TimeSpan
di SQL server 2008 R2.
EF Code First tampaknya menyarankan itu harus disimpan Time(7)
dalam SQL.
Namun TimeSpan
dalam .Net dapat menangani periode lebih lama dari 24 jam.
Apa cara terbaik untuk menangani penyimpanan .Net TimeSpan
di SQL server?
.net
sql-server
timespan
GraemeMiller
sumber
sumber
Jawaban:
Saya akan menyimpannya di database sebagai
BIGINT
dan saya akan menyimpan jumlah kutu (misalnya properti TimeSpan.Ticks ).Dengan begitu, jika saya ingin mendapatkan objek TimeSpan ketika saya mengambilnya, saya bisa melakukan TimeSpan.FromTicks (nilai) yang akan mudah.
sumber
SELECT CAST(DATEADD(MILLISECOND, @Ticks/CAST(10000 AS BIGINT), '1900-01-01') AS TIME)
. The'1900-01-01'
tanggal tidak peduli, tentu saja, itu hanya variabel ketiga yang dibutuhkan olehDATEADD(...)
fungsi. Ingat ada 100 nanodetik dalam kutu, tetapi jika Anda menggunakanDATEADD(NANOSECOND...
Anda kemungkinan akan mendapatkan luapan, maka gunakan milidetik. Juga ingat bahwa Anda harus memeriksa fakta ini menggunakan C #TimeSpan.TicksPerMillisecond
(harus 10.000) untuk memastikan.Terima kasih atas sarannya. Karena tidak ada padanan dalam SQL server. Saya hanya membuat bidang ke-2 yang mengubah TimeSpan menjadi ticks dan menyimpannya dalam DB. Saya kemudian mencegah menyimpan TimeSpan
sumber
Jika Anda tidak perlu menyimpan lebih dari 24 jam, Anda bisa menyimpan waktu , karena SQL Server 2008 dan kemudian pemetaannya
time (SQL Server) <-> TimeSpan(.NET)
Tidak perlu konversi jika Anda hanya perlu menyimpan 24 jam atau kurang.
Sumber: http://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx
Tetapi , jika Anda ingin menyimpan lebih dari 24 jam, Anda harus menyimpannya dalam kutu, ambil data dan kemudian konversikan ke TimeSpan. Sebagai contoh
sumber
Time
Tipe SQL tidak dimaksudkan untuk mewakili durasi, tetapi bagian Waktu dari nilai DateTime; itu pilihan yang burukTimeSpan
.Tidak ada padanan langsung. Simpan saja secara numerik, mis. Jumlah detik atau sesuatu yang sesuai dengan akurasi yang Anda butuhkan.
sumber
Saya tahu ini adalah pertanyaan lama, tetapi saya ingin memastikan beberapa opsi lain dicatat.
Karena Anda tidak dapat menyimpan TimeSpan lebih dari 24 jam dalam bidang datatype sql waktu; beberapa opsi lain mungkin.
Gunakan varchar (xx) untuk menyimpan ToString of the TimeSpan. Manfaat dari ini adalah ketelitian tidak harus dimasukkan ke dalam tipe data atau perhitungan, (detik vs milidetik vs hari vs Fortnights) Yang perlu Anda lakukan adalah menggunakan TimeSpan.Parse / TryParse. Inilah yang akan saya lakukan.
Gunakan tanggal kedua, datetime atau set datetime, yang menyimpan hasil dari tanggal + rentang waktu pertama. Membaca dari db adalah soal TimeSpan x = SecondDate - FirstDate. Menggunakan opsi ini akan melindungi Anda untuk pustaka akses data non .NET yang mengakses data yang sama tetapi tidak memahami TimeSpans; jika Anda memiliki lingkungan seperti itu.
sumber
Agar konsisten dengan apa yang mungkin merupakan sumber yang paling mungkin menghasilkan rentang waktu (menghitung perbedaan 2 kali atau tanggal-kali), Anda mungkin ingin menyimpan .NET
TimeSpan
sebagaiDateTime
Jenis SQL Server .Ini karena dalam SQL Server, perbedaan 2
DateTime
(Cast
untukFloat
dan kemudianCast
kembali keDateTime
) hanyalahDateTime
relatif terhadap 1 Januari 1900. Kel. Perbedaan +0.1 detik adalah 1 Januari 1900 00: 00: 00.100 dan -0.1 detik adalah 31 Desember 1899 23: 59: 59.900.Untuk mengonversi .NET
TimeSpan
keDateTime
Tipe SQL Server , Anda harus terlebih dahulu mengonversinya menjadi .NETDateTime
dengan menambahkannya keDateTime
1 Januari 1900. Tentu saja, ketika Anda membacanya di .NET dari SQL Server, Anda harus terlebih dahulu membacanya menjadi NET.DateTime
Dan kemudian kurangi 1 Januari 1900 dari itu untuk mengubahnya menjadi NETTimeSpan
.Untuk kasus penggunaan di mana rentang waktu dihasilkan dari SQL Server
DateTime
dan dalam SQL Server (yaitu melalui T-SQL) dan SQL Server sebelum 2016, tergantung pada jangkauan dan kebutuhan presisi Anda, mungkin tidak praktis untuk menyimpannya sebagai milidetik (belum lagiTicks
) karenaInt
Jenis dikembalikan olehDateDiff
(vsBigInt
dari SS 2016 + 'sDateDiff_Big
) meluap setelah ~ 24 hari senilai milidetik dan ~ 67 tahun. detik. Sedangkan, solusi ini akan menangani rentang waktu dengan presisi hingga 0,1 detik dan dari -147 hingga +8,099 tahun.PERINGATAN:
Ini hanya akan bekerja jika perbedaannya relatif terhadap 1 Januari 1900 akan menghasilkan nilai dalam kisaran
DateTime
Tipe SQL Server (1 Januari 1753 hingga 31 Desember, 9999 alias -147 hingga +8.099 tahun). Kita tidak perlu terlalu khawatir diTimeSpan
sisi .NET , karena dapat menampung ~ 29 k hingga +29 k tahun. Saya tidak menyebutkanDateTime2
Tipe SQL Server (yang jangkauannya, di sisi negatifnya, jauh lebih besar daripada SQL ServerDateTime
), karena: a) tidak dapat dikonversi ke numerik melalui rentang sederhanaCast
dan b)DateTime
harus cukup. untuk sebagian besar kasus penggunaan.DateTime
Perbedaan SQL Server yang dihitung melalui metodeCast
- to -Float
- dan - back tampaknya tidak akurat setelah 0,1 detik.sumber
Ada beberapa cara bagaimana menyajikan rentang waktu dalam database.
waktu
Tipe data ini didukung sejak SQL Server 2008 dan merupakan cara yang disukai untuk menyimpan a
TimeSpan
. Tidak diperlukan pemetaan. Ini juga bekerja dengan baik dengan kode SQL.Namun, seperti yang dinyatakan dalam pertanyaan awal, tipe data ini dibatasi hingga 24 jam.
datetimeoffset
Tipe
datetimeoffset
data peta langsung keSystem.DateTimeOffset
. Ini digunakan untuk mengekspresikan offset antara adatetime
/datetime2
ke UTC, tetapi Anda juga dapat menggunakannya untukTimeSpan
.Namun, karena datatype menyarankan semantik yang sangat spesifik, maka Anda juga harus mempertimbangkan opsi lain.
datetime / datetime2
Salah satu pendekatan mungkin menggunakan tipe
datetime
ataudatetime2
. Ini terbaik dalam skenario di mana Anda perlu memproses nilai-nilai dalam database secara langsung, yaitu. untuk tampilan, prosedur tersimpan, atau laporan. Kekurangannya adalah Anda perlu mengurangi nilaiDateTime(1900,01,01,00,00,00)
dari tanggal untuk mendapatkan kembali rentang waktu dalam logika bisnis Anda.bigint
Pendekatan lain mungkin untuk mengubah TimeSpan menjadi tick dan menggunakan
bigint
datatype. Namun, pendekatan ini memiliki kelemahan yang sulit untuk digunakan dalam query SQL.varchar (N)
Ini terbaik untuk kasus-kasus di mana nilainya harus dibaca oleh manusia. Anda juga dapat menggunakan format ini dalam kueri SQL dengan memanfaatkan
CONVERT(datetime, ValidityPeriod)
fungsinya. Bergantung pada presisi yang dibutuhkan, Anda akan membutuhkan antara 8 dan 25 karakter.Bonus: Periode dan Durasi
Menggunakan string, Anda juga dapat menyimpan tipe data NodaTime , terutama
Duration
danPeriod
. Yang pertama pada dasarnya sama dengan TimeSpan, sementara yang lain menghargai bahwa beberapa hari dan bulan lebih panjang atau lebih pendek dari yang lain (mis. Januari memiliki 31 hari dan Februari memiliki 28 atau 29; beberapa hari lebih panjang atau lebih pendek karena waktu musim panas) ). Dalam kasus seperti itu, menggunakan TimeSpan adalah pilihan yang salah.Anda dapat menggunakan kode ini untuk mengonversi Periode:
Dan kemudian gunakan seperti
Saya sangat suka
NodaTime
dan sering menyelamatkan saya dari bug yang rumit dan banyak sakit kepala. Kekurangannya di sini adalah Anda benar-benar tidak dapat menggunakannya dalam query SQL dan perlu melakukan perhitungan dalam memori.Jenis yang Ditentukan Pengguna CLR
Anda juga memiliki opsi untuk menggunakan tipe data khusus dan mendukung
TimeSpan
kelas khusus secara langsung. Lihat CLR Jenis yang Ditentukan Pengguna untuk detail.Kelemahan di sini adalah bahwa tipe data mungkin tidak berperilaku baik dengan Laporan SQL. Juga, beberapa versi SQL Server (Azure, Linux, Data Warehouse) tidak didukung.
Konversi Nilai
Dimulai dengan EntityFramework Core 2.1, Anda memiliki opsi untuk menggunakan Konversi Nilai .
Namun, saat menggunakan ini, EF tidak akan dapat mengonversi banyak pertanyaan menjadi SQL, menyebabkan kueri berjalan di dalam memori; berpotensi mentransfer banyak dan banyak data ke aplikasi Anda.
Jadi setidaknya untuk saat ini, mungkin lebih baik tidak menggunakannya, dan hanya memetakan hasil kueri dengan Automapper .
sumber
Biasanya, saya menyimpan TimeSpan sebagai bigint yang diisi dengan kutu dari properti TimeSpan.Ticks seperti yang disarankan sebelumnya. Anda juga dapat menyimpan TimeSpan sebagai varchar (26) yang diisi dengan output TimeSpan.ToString (). Empat fungsi skalar (ConvertFromTimeSpanString, ConvertToTimeSpanString, DateAddTicks, DateDiffTicks) yang saya tulis sangat membantu untuk menangani TimeSpan di sisi SQL dan menghindari peretasan yang akan menghasilkan rentang yang dibatasi secara artifisial. Jika Anda dapat menyimpan interval dalam .NET TimeSpan sama sekali, itu harus bekerja dengan fungsi-fungsi ini juga. Selain itu, fungsi memungkinkan Anda untuk bekerja dengan TimeSpans dan kutu 100-nanosecond bahkan ketika menggunakan teknologi yang tidak termasuk .NET Framework.
sumber