Cara membaca nilai suatu bidang dengan properti IDENTITY. Menentukan presisi untuk tipe Desimal

Menunjukkan bahwa kolom baru adalah kolom identitas. Ketika baris baru ditambahkan ke tabel, mesin database menghasilkan nilai berurutan unik untuk kolom tersebut. Kolom pengidentifikasi biasanya digunakan dengan batasan PRIMARY KEY untuk menjaga keunikan pengidentifikasi baris dalam tabel. Properti IDENTITY dapat ditetapkan ke kolom bertipe tinyint, smallint, int, bigint, desimal(p,0), atau numerik(p,0). Anda hanya dapat membuat satu kolom identitas per tabel. Nilai default tidak dapat digunakan di kolom identitas. Anda harus menentukan nilai awal dan kenaikannya, atau Anda tidak dapat menentukan apa pun. Jika tidak ada nilai yang ditentukan, nilai defaultnya adalah (1,1).

Sintaksis:

[ IDENTITAS [ (benih, kenaikan) ]

Sperlu- nilai yang digunakan untuk baris pertama yang dimuat ke dalam tabel.

Sayapeningkatan - s Nilai kenaikan ditambahkan ke nilai ID baris yang dimuat sebelumnya.

[ Kartu waktu nomor] IDENTITAS INT (1, 1) BUKAN KUNCI UTAMA NULL

    Bidang terhitung.

Sintaksis:

<имя_столбца> SEBAGAI <выражение> ]

Ekspresi yang menentukan nilai kolom terhitung. Kolom terhitung adalah kolom virtual yang tidak disimpan secara fisik dalam tabel kecuali kolom tersebut BERSISTEM. Nilai kolom dihitung berdasarkan ekspresi yang menggunakan kolom lain dalam tabel yang sama.

Misalnya, definisi kolom terhitung mungkin:

Produk_biaya SEBAGAI Harga_per_potong * Kuantitas.

Ekspresi dapat berupa nama kolom yang tidak dihitung, konstanta, fungsi, variabel, atau kombinasi keduanya, yang dihubungkan oleh satu atau lebih operator. Ekspresi tidak boleh berupa subkueri atau berisi alias tipe data.

Kolom terhitung dapat digunakan dalam daftar pilihan, klausa WHERE, klausa ORDER BY, dan tempat lain di mana ekspresi reguler dapat digunakan, kecuali dalam kasus berikut.

Kolom terhitung tidak dapat digunakan sebagai definisi batasan DEFAULT atau FOREIGN KEY, atau bersama dengan definisi batasan NOT NULL. Namun, kolom terhitung dapat digunakan sebagai kolom kunci indeks atau sebagai bagian dari batasan PRIMARY KEY atau UNIQUE jika nilai kolom terhitung tersebut ditentukan oleh ekspresi deterministik (dapat diprediksi) dan tipe data hasil diperbolehkan di kolom indeks .

Misalnya, jika tabel berisi kolom bilangan bulat A Dan B, kolom terhitung a+b dapat dimasukkan dalam indeks, dan kolom terhitung a+DATEPART(hh, GETDATE())- tidak bisa, karena nilainya dapat berubah pada panggilan berikutnya.

Kolom yang dihitung tidak boleh menjadi kolom target dari pernyataan INSERT atau UPDATE.

DBMS secara otomatis menentukan apakah kolom yang dihitung dapat NULL berdasarkan ekspresi yang digunakan. Hasil dari sebagian besar ekspresi dianggap nullable, meskipun hanya kolom non-nullable yang digunakan, karena kemungkinan overflow atau underprecision dapat menghasilkan nilai null. Untuk menentukan apakah kolom tabel terhitung bisa NULL, gunakan fungsi COLUMNPROPERTY dengan properti IzinkanNull. Pastikan ekspresi tersebut tidak mengizinkan nilai NULL, Anda bisa dengan menentukan ISNULL dengan konstanta check_ekspresi, dengan konstanta adalah nilai bukan nol yang menggantikan nilai NULL apa pun. Kolom yang dihitung berdasarkan ekspresi yang berisi tipe yang ditentukan pengguna CLR memerlukan izin tipe REFERENCES.

Menunjukkan bahwa komponen tersebut SQLServer akan secara fisik menyimpan nilai terhitung dalam tabel dan memperbaruinya ketika kolom mana pun yang bergantung pada kolom terhitung berubah. Menentukan PERSISTED pada kolom terhitung memungkinkan Anda membuat indeks pada kolom terhitung yang bersifat deterministik namun tidak tepat.

Pada membuat tabel Selain teknik yang dibahas di atas, Anda dapat menentukan kata kunci CONSTRAINT opsional untuk memberi batasan nama yang unik dalam database.

MEMBUAT T MAMPU Pesanan(

ID_PesananINT BUKAN NULL ,

Piring INT BUKAN NULL,

Kuantitas_ porsi INT BUKAN PERIKSA NULL( Kuantitas_ porsi >0 ) ,

Tanggal TANGGAL BUKAN NULL ,

KUNCI UTAMA( ID_Pesanan, Piring, Tanggal),

KENDALA ASING_KEY

KUNCI ASING ( Piring, Tanggal) REFERENSI Menu( Piring, Tanggal)) ;

Kemudian Anda dapat bekerja dengan batasan bernama seperti pada objek database. Jika nama batasan tidak ditentukan, kernel SUDB akan membuatnya secara otomatis, memilih nama sesuai dengan aturan yang ditentukan dalam sistem.

Contoh script yang dibangun oleh sistem untuk membuat tabel Catalog_type_of_dish

BUAT TABEL .[Directory_type_of_dish](

IDENTITAS(1,1) BUKAN NULL,

[Tampilan] (20) BUKAN NULL,

KUNCI UTAMA KENDALA TERKELOMPOK

) DENGAN (PAD_INDEX = MATI, STATISTICS_NORECOMPUTE = MATI, IGNORE_DUP_KEY = MATI, ALLOW_ROW_LOCKS = AKTIF, ALLOW_PAGE_LOCKS = AKTIF)

Apa itu IDENTITAS

IDENTITAS bukan tipe data. Ini adalah beberapa properti tambahan, batasan yang dikenakan tipe bilangan bulat data di server MS SQL. Itu. properti ini dapat diterapkan ke bidang jenis berikut: kecil sekali, kecil, ke dalam, orang besar, desimal(p,0), atau numerik(p,0)

Setara dengan properti ini di FoxPro adalah tipe data Integer-AutoIncrement. Hanya saja, jangan berasumsi bahwa Integer-AutoIncrement adalah bidang dengan properti Identity. Sama sekali tidak. Ini persis analog. Mereka pada dasarnya serupa, tetapi memiliki sejumlah perbedaan. Pada artikel ini kita akan berbicara tentang properti IDENTITY di server MS SQL.

Bidang dengan properti IDENTITAS memiliki beberapa fitur berikut:

  • Dalam satu tabel, hanya satu field dengan properti IDENTITY yang diperbolehkan
  • Bidang dengan properti IDENTITY tidak dapat diedit. Mereka memiliki properti read-only.
  • Bidang dengan properti IDENTITY diberi nilai secara otomatis ketika catatan baru dibuat.

Ada beberapa fitur lain, tetapi itu merupakan konsekuensi dari fitur yang tercantum

Nilai baru adalah nilai terakhir yang digunakan ditambah beberapa nilai tetap. Perlu diketahui bahwa nilai baru tidak didasarkan pada nilai maksimum yang masuk catatan yang ada, dan ke nilai yang terakhir digunakan. Artinya, record dengan nilai yang terakhir digunakan mungkin tidak ada secara fisik, namun nilainya akan tetap digunakan.

Dengan kata lain, “lubang” cukup dapat diterima dalam urutan nilai suatu bidang dengan properti IDENTITY. Daftar nilai tidak berkesinambungan sama sekali

Biasanya, langkah kenaikannya adalah 1, tetapi bisa berupa bilangan bulat apa pun. Termasuk yang negatif.

Karena karakteristik bidang dengan properti IDENTITY, bidang tersebut sering digunakan sebagai kunci utama. Dengan kata lain, sebagai bidang yang nilainya selalu dapat mengidentifikasi rekaman tabel secara unik.

Perlu diingat bahwa properti IDENTITY tidak mengontrol keunikan data dengan cara apa pun. Misalnya jika bidang awalnya punya ketik BULAT, dan sejumlah nilai dimasukkan ke dalamnya. Dan kemudian struktur tabel diubah, dan properti IDENTITY diterapkan ke bidang ini, maka catatan baru mungkin memiliki data yang sama dengan yang sebelumnya dimasukkan ke dalam tabel ini. Oleh karena itu, jika bidang dengan properti IDENTITY digunakan sebagai kunci utama, maka bidang ini harus di-overlay pembatasan tambahan oleh keunikan.

Kerugian menggunakan bidang dengan properti IDENTITY sebagai kunci utama

Namun, meskipun ada keuntungan nyata menggunakan bidang dengan properti IDENTITY sebagai kunci utama, bidang tersebut juga memiliki kelemahan serius.

Nilai bidang dengan properti IDENTITY tidak dapat diketahui sampai rekaman dibuat secara fisik.

Jadi apa? Masalah apa? Mari buat rekor dan temukan nilai barunya.

Masalahnya adalah untuk mengetahui nilai suatu field dalam suatu record, record tersebut harus ditemukan terlebih dahulu. Dan pencarian record dilakukan tepat dengan nilai kunci utama. Yang nilainya perlu ditentukan. Lingkaran setan: untuk membaca nilai Anda perlu mengetahui nilai ini!

Struktur penyimpanan data di server MS SQL pada dasarnya berbeda dengan struktur penyimpanan data di file DBF. Tidak ada konsep seperti " nomor fisik catatan", "catatan berikutnya", "catatan terakhir", dll. Artinya, tidak mungkin untuk pergi ke "catatan terakhir" untuk membaca nilai kunci utamanya.

Selain itu, meskipun nilai baru dari bidang dengan properti IDENTITY selalu lebih besar dari nilai mana pun yang ada (jika kenaikannya adalah angka positif), juga tidak mungkin untuk menentukan nilai baru ini hanya dengan menghitung nilai maksimum dari bidang tersebut. nilai-nilai yang ada. Tidak, nilai maksimalnya sendiri tentu saja akan didapat. Tidak ada jaminan bahwa nilai yang dihasilkan adalah nilai persis dari catatan yang dibuat.

Intinya di sini adalah, sebagai aturan, server MS SQL digunakan dalam aplikasi multi-pengguna. Artinya, beberapa pengguna dapat membuat rekaman baru secara bersamaan. Ternyata salah satu pengguna membuat record baru, kemudian mulai menghitung nilai maksimalnya, dan pada saat itu pula pengguna lain juga membuat record baru. Akibatnya, pengguna pertama sebagai nilai maksimum akan mendapatkan nilai dari catatan yang dibuat oleh pengguna kedua.

Jadi haruskah kita berhenti menggunakan kolom dengan properti IDENTITY sebagai kunci utama? Sama sekali tidak. Namun, ada cara untuk menentukan nilai bidang dengan properti IDENTITY dari rekaman baru.

Cara menentukan nilai bidang dengan properti IDENTITY di catatan baru

Sebenarnya, ada tiga strategi mendasar untuk menentukan nilai suatu field dengan properti IDENTITY dalam record yang baru dibuat

Sekarang mari kita lihat lebih dekat kelebihan dan kekurangan masing-masing strategi.

Nilai yang dikembalikan oleh variabel sistem @@IDENTITY

MS SQL Server memiliki sejumlah variabel sistem, yang nilainya berubah secara otomatis ketika peristiwa tertentu terjadi. Secara khusus, nilai variabel sistem @@IDENTITY secara otomatis diatur ke nilai bidang dengan properti IDENTITY dari rekaman yang terakhir dibuat dalam koneksi saat ini. Itu. pembuatan entri baru di koneksi lain (oleh pengguna lain) tidak akan mempengaruhi nilainya dengan cara apa pun dalam koneksi ini.

Nah, ini dia solusinya. Cukup setelah membuat catatan baru, kita membaca nilai variabel sistem @@IDENTITY dan mendapatkan nilai yang diinginkan.

Secara umum, benar. Satu-satunya masalah adalah variabel sistem @@IDENTITY mengubah nilainya saat membuat entri setiap meja.

Dalam praktiknya, ini berarti bahwa jika pemicu penyisipan dipasang pada tabel, yang isinya berisi perintah INSERT untuk membuat catatan di tabel lain, yang, pada gilirannya, juga memiliki bidang dengan properti IDENTITY, maka @@ Variabel sistem IDENTITY akan menerima nilai field dari tabel kedua ini.

Dengan kata lain, Anda dapat mengandalkan nilai variabel sistem @@IDENTITY, namun perlu diingat bahwa variabel ini tidak terikat dengan nilai suatu bidang dalam satu tabel.

Nilai kembalian dari SCOPE_IDENTITY()

Di MS SQL 2000, fungsi sistem SCOPE_IDENTITY() diperkenalkan. Fungsi ini juga mengembalikan nilai bidang dengan properti IDENTITY dari rekaman terakhir yang dibuat, tetapi dibuat dalam LINGKUP saat ini.

Cukup sulit untuk menerjemahkan istilah RUANG LINGKUP ke dalam bahasa Rusia secara memadai. Namun kira-kira kita dapat mengatakan ini: RUANG LINGKUP adalah salah satu prosedur atau fungsi. Dengan kata lain, SCOPE_IDENTITY() akan mengembalikan nilai bidang dengan properti IDENTITY dari rekaman terakhir yang dibuat dalam prosedur di mana fungsi ini dipanggil.

Pemicunya sudah merupakan SCOPE yang berbeda (fungsi lain), sehingga tidak akan mempengaruhi nilai yang dikembalikan oleh SCOPE_IDENTITY().

Bahkan jika dua pengguna memanggil prosedur yang sama pada waktu yang sama, namun masing-masing memanggil prosedur dalam RUANG LINGKUPnya sendiri. Itu. sekali lagi tidak ada konflik.

Kerugian dari fungsi ini termasuk fakta bahwa fungsi ini harus dipanggil dalam RUANG LINGKUP tempat catatan baru dari tabel yang kami minati dibuat. Dan hal ini tidak selalu memungkinkan.

Dengan kata lain, untuk penggunaan yang benar SCOPE_IDENTITY() harus selalu memperhatikan ruang lingkup SCOPE. Seringkali dengan membuat prosedur khusus.

Menemukan rekor baru berdasarkan nilai bidang lain

Jika Anda ingat, masalah utama dalam menentukan nilai suatu bidang dengan properti IDENTITY adalah bahwa bidang tersebut digunakan sebagai kunci utama. Itu. Berdasarkan nilainya, entri yang diperlukan ditemukan.

Namun, tabel sering kali memiliki bidang atau kumpulan bidang yang juga dapat digunakan untuk mengidentifikasi rekaman secara unik. Misalnya jika yang sedang kita bicarakan tentang direktori, maka, tentu saja, direktori tersebut memiliki kolom “Nama”. Jelas juga bahwa bidang ini harus unik di dalam direktori. Jika tidak, tujuan penggunaan buku referensi itu sendiri akan hilang begitu saja. Mengapa memasukkan entri ke dalam direktori dengan nilai yang sama?

Mengapa tidak menggunakan “Nama” ini sebagai kunci utama? Mengapa Anda memerlukan bidang dengan properti IDENTITY? Ini adalah topik untuk diskusi lain. Singkatnya, "Nama" adalah untuk pengguna (data eksternal) dan IDENTITAS adalah untuk memastikan integritas referensial database (data internal).

Nilai bidang dengan properti IDENTITY dalam catatan baru tidak diketahui. Namun arti dari field Judul dalam rekaman baru ini sudah cukup diketahui. Pengguna memasukkannya sendiri! Ini berarti bahwa setelah membuat catatan baru, Anda dapat menemukan catatan baru ini berdasarkan nilai bidang “Nama” dan membaca nilai bidang tersebut dengan properti IDENTITY.

Satu-satunya masalah adalah bahwa bidang atau kumpulan bidang tersebut tidak selalu ada untuk mengidentifikasi catatan secara unik. Omong-omong, ini adalah salah satu alasan untuk memasukkan apa yang disebut kunci pengganti. Bidang yang sama dengan properti IDENTITY.

Namun, jika Anda memutuskan untuk menggunakan strategi ini untuk menemukan catatan baru, pastikan untuk menerapkan batasan keunikan pada bidang “Judul” (atau kumpulan bidang yang Anda pilih). Artinya, agar tidak ada dua record dengan nilai yang sama pada field ini secara kebetulan.

Cara bekerja dengan bidang dengan properti IDENTITY di FoxPro

Kita sudah selesai dengan bagian teoritisnya, sekarang “mari kita coba memulai semua hal ini.” Itu. Mari putuskan bagaimana menggunakan semua pengetahuan ini di FoxPro. Mari kita perjelas lagi masalah yang perlu dipecahkan.

Catatan ditambahkan ke tabel server MS SQL yang memiliki bidang dengan properti IDENTITY. Segera setelah membuat catatan baru, Anda perlu mendapatkan nilai bidang dengan properti IDENTITY di sisi FoxPro.

FoxPro memiliki tiga opsi mendasar untuk mengatur pekerjaan dengan server MS SQL

  • Menggunakan Tampilan Jarak Jauh
  • Menggunakan Adaptor Kursor

Di sini kita harus memikirkan peristiwa mana yang sebenarnya membuat catatan di server MS SQL. Semuanya jelas dengan Pass-Trough. Ini sebenarnya adalah perintah langsung ke server untuk membuat record baru. Namun dengan Remote View dan Cursor Adapter, situasinya sedikit berbeda.

Hasil dari Remote View dan Cursor Adapter adalah sebuah kursor. Itu. tabel sementara yang secara fisik terletak di mesin klien. Secara default, kursor ini secara otomatis terbuka dalam mode buffering baris optimis (3) dan hanya dapat dialihkan ke mode buffering tabel optimis (5). Tidak mungkin untuk beralih ke mode buffering pesimistis atau menonaktifkan buffering sepenuhnya untuk kursor ini

Akibatnya, rekor baru akan dibuat secara fisik terlebih dahulu mesin klien di kursor ini. Lebih tepatnya, di buffer kursor ini. Pembuatan catatan secara fisik di server MS SQL hanya akan terjadi setelah buffer direset.

Untuk buffering baris, buffer flush dapat terjadi secara otomatis ketika Anda melakukan salah satu hal berikut:

  • Melompat (atau mencoba melompat) ke entri lain
  • Menutup kursor
  • Beralih ke mode buffering tabel
  • Dengan perintah TableUpdate()

Untuk buffering tabel, buffer hanya dapat di-flush menggunakan perintah TableUpdate() dan tidak ada yang lain.

Tidak ada tindakan atau operasi lain dengan Tampilan Jarak Jauh atau Adaptor Kursor yang akan menyebabkan pembuatan catatan baru di server MS SQL. Jika, saat melakukan operasi apa pun, ternyata catatan baru telah dibuat di server MS SQL, ini berarti kursor berada dalam mode buffering baris, dan salah satu peristiwa yang menyebabkan reset buffer otomatis terjadi.

Misalnya, hal ini dapat terjadi dengan perintah Requery() untuk Tampilan Jarak Jauh. Namun ini tidak berarti bahwa perintah Requery() menghapus buffer. Sama sekali tidak. Sederhananya, salah satu syarat untuk menjalankan perintah Requery() adalah menutup kursor yang sudah ada sebelumnya. Namun kejadian ini akan menyebabkan reset buffer otomatis jika kursor berada dalam mode buffering baris.

Untuk menghindari kesalahpahaman seperti itu, alihkan kursor ke mode buffering tabel (5). Dalam hal ini, Anda akan selalu dapat mengontrol proses reset buffer.

Namun, Anda harus memahami bahwa meskipun Anda mengatur mode buffering tabel, mengubah beberapa catatan di Tampilan Jarak Jauh atau Adaptor Kursor, dan kemudian mengeluarkan perintah TableUpdate(), buffer akan tetap dihapus satu catatan dalam satu waktu. Itu. Tidak hanya satu perintah yang akan dikirim ke server, misalnya untuk modifikasi, tetapi sekumpulan perintah untuk memodifikasi setiap record secara terpisah.

Sehubungan dengan operasi pembuatan record baru, maka di semua event objek Adaptor Kursor Selalu Hanya satu record yang dimasukkan dalam satu waktu.

Penggunaan langsung teknologi Pass-Through melalui fungsi SQLEXEC()

Dengan metode kerja ini, programmer bekerja langsung dengan server MS SQL. Ini menghasilkan semua perintah yang dikirim ke server, menerima hasilnya, dan memprosesnya sendiri. Dalam hal ini, tidak sulit untuk mengirim permintaan tambahan ke server untuk nilai fungsi SCOPE_IDENTITY

LOCAL lcNewValue, lnResut lcNewValue = "Nilai baru" lnResut = SQLExec(m.lnConnectHandle,"INSERT INTO MyTab (Field1) VALUES (?m.lcNewValue)") IF m.lnResut>0 SQLExec(m.lnConnectHandle,"SELECT NewIdent=SCOPE_IDENTITY()","NewIdent") ?NewIdent.NewIdent ELSE LOCAL laError(1) =AERROR(laError) * Анализ массива laError для уточнения причины ошибки ENDIF !}

Dalam contoh ini, m.lnConnectHandle adalah angka, nomor koneksi ke server MS SQL yang dikonfigurasi sebelumnya. MyTab adalah tabel yang memiliki field dengan properti IDENTITY.

Setelah menjalankan kueri kedua pada kursor yang dihasilkan NewIdent di bidang NewIdent pada rekaman pertama, kita mendapatkan nilai yang diinginkan. Dalam sintaksis ini, perintah penyisipan dan panggilan ke fungsi SCOPE_IDENTITY() terjadi di SCOPE yang sama. Oleh karena itu, kami mendapatkan nilai yang diinginkan.

Menggunakan Tampilan Jarak Jauh

Remote View adalah semacam “tambahan” pada teknologi Pass-Through. Intinya, saat membuat catatan baru, perintah INSERT INTO yang sama dijalankan. Namun, masalahnya adalah meskipun kita membaca nomor koneksi yang menjalankan Remote View dan kemudian menjalankan kueri untuk menentukan nilai yang dikembalikan oleh SCOPE_IDENTITY(), kita akan mendapatkan NULL karena dalam hal ini perintah penyisipan dan SCOPE_IDENTITY() adalah dilaksanakan di LINGKUP yang berbeda. Oleh karena itu, hanya ada dua cara untuk menentukan nilai bidang dengan properti IDENTITY.

* Menentukan nilai variabel sistem @@IDENTITY LOCAL lnConnectHandle lnConnectHandle = CursorGetProp("ConnectHandle","MyRemoteView") SQLExec(m.lnConnectHandle,"SELECT NewIdent=@@IDENTITY","NewIdent") ?NewIdent.NewIdent * Menentukan dengan nilai bidang lain LOCAL lnConnectHandle, lcNickName lnConnectHandle = CursorGetProp("ConnectHandle","MyRemoteView") lcNickName = MyRemoteView.NickName SQLExec(m.lnConnectHandle,"SELECT TabId FROM MyTab WHERE NickName=?lcNickName","NewIdent") ? Identitas Baru

Dalam kedua contoh tersebut, MyRemoteView adalah nama Tampilan Jarak Jauh Anda. NickName adalah nama field di Remote View yang nilainya dicari record baru, dan TabID adalah field yang sama dengan properti IDENTITY yang nilainya harus ditentukan

Diasumsikan bahwa pembuatan rekor baru telah terjadi. Entah perintah TableUpdate() dikeluarkan secara eksplisit, atau Tampilan Jarak Jauh berada dalam mode buffering baris dan upaya telah dilakukan untuk berpindah ke rekaman lain.

Dan mengapa dalam kasus kedua bukan solusi pencarian yang tampaknya lebih jelas digunakan setelah Requery()? Sesuatu seperti

REQUERY("MyRemoteView") PILIH MyRemoteView LOCATE FOR NickName = "Nilai baru" ?MyRemoteView.TabID

Ada beberapa alasan untuk hal ini.

Pertama, Requery() melibatkan eksekusi ulang kueri. Itu. Diasumsikan bahwa buffer semua entri Remote View telah dihapus. Namun hal ini mungkin tidak terjadi. Misalnya, mereka menghapus buffer satu per satu dalam satu putaran.

Kedua, biasanya Remote View berisi ketentuan tambahan pemilihan rekaman, dan rekaman yang baru dibuat mungkin tidak disertakan dalam kondisi pemilihan sama sekali. Itu. setelah Requery(), rekaman, meskipun dibuat secara fisik di server, tidak akan ditampilkan di Tampilan Jarak Jauh itu sendiri.

Menggunakan Adaptor Kursor

Objek Adaptor Kursor diperkenalkan ke FoxPro dimulai dengan Visual FoxPro 8. Objek ini dirancang untuk memudahkan bekerja dengan data jarak jauh saat melakukan beberapa hal. operasi standar. Khususnya, operasi pembuatan rekor baru. Melalui Adaptor Kursor, Anda dapat menerapkan ketiga opsi untuk mendapatkan nilai bidang dengan properti IDENTITY dalam catatan baru.

Nilai yang dikembalikan oleh variabel sistem @@IDENTITY

Setelah buffer direset dan catatan baru dibuat secara fisik di server MS SQL, acara AfterInsert akan diaktifkan di objek Adaptor Kursor. Di sinilah Anda perlu membuat permintaan tambahan ke server dan membaca nilai variabel sistem @@IDENTITY

PROSEDUR SetelahInsert LPARAMETERS cFldState, lForce, cInsertCmd, lResult IF lResult=.T. && penyisipan berhasil. Kita perlu mendapatkan nilai ID LOCAL currentArea currentArea=SELECT() COBA IF 1=SQLEXEC(this.DataSource,"SELECT NewIdent=@@IDENTITY","NewIdent") REPLACE TabId WITH NewIdent.NewIdent IN (This.Alias) GUNAKAN DALAM IDRes LAIN LOKAL laError(1) =AERROR(laError) * Analisis array laError untuk menentukan penyebab kesalahan ENDIF FINALLY SELECT (currentArea) ENDTRY ENDIF ENDPROC

Menurut saya kodenya cukup jelas dan tidak memerlukan penjelasan. Setelah penciptaan yang sukses catatan baru di server, menggunakan SQLExec() untuk koneksi yang sama, menentukan nilai @@IDENTITY dan menulis nilai ini ke catatan kursor saat ini di bidang kunci.

Di Visual FoxPro 9, properti telah ditambahkan ke objek Adaptor Kursor SisipkanCmdSegarkanCmd. Ini adalah perintah yang dikirim ke server hanya setelah record baru berhasil dimasukkan. Itu. tidak perlu memverifikasi bahwa rekor baru telah dibuat.

Dipasangkan dengan properti baru lainnya SisipkanCmdRefreshFieldList Anda dapat melakukan pembaruan berdasarkan nilai variabel sistem @@IDENTITY dengan lebih mudah. Untuk melakukan ini, Anda hanya perlu melakukan pengaturan berikut objek CursorAdapter

CursorAdapter.InsertCmdRefreshCmd = "PILIH @@IDENTITY" CursorAdapter.InsertCmdRefreshFieldList = "TabId"

Di sini TabId bukanlah nama field dengan properti IDENTITY dalam tabel itu sendiri di server MS SQL, tetapi nama field kursor yang diterima di sisi klien di mana isi field dengan properti IDENTITY ditampilkan. Biasanya, nama-nama ini sama, tetapi secara umum mungkin berbeda. Detail selengkapnya tentang properti SisipkanCmdRefreshFieldList baca di bawah. Pada bagian yang dikhususkan untuk mencari record baru berdasarkan nilai field lainnya.

Nilai kembalian dari SCOPE_IDENTITY()

Di sini segalanya menjadi sedikit lebih rumit. Intinya adalah Anda tidak dapat bertindak dengan cara yang sama seperti dalam mendefinisikan variabel sistem @@IDENTITY. SQLExec() dan Adaptor Kursor beroperasi dalam LINGKUP yang berbeda. Oleh karena itu, dengan pendekatan ini, SCOPE_IDENTITY() akan selalu mengembalikan NULL. Untuk mengatasi kontradiksi ini, digunakan prosedur khusus.

Untuk memulainya, Anda perlu membuat prosedur tersimpan berikut di server MS SQL itu sendiri

BUAT PROSEDUR Get_ValueInt @ValueIn Int, @ValueOut Int OUTPUT SEBAGAI SET NOCOUNT PADA SELECT @ValueOut=@ValueIn

Seperti yang Anda lihat, tujuan dari prosedur ini hanyalah untuk menetapkan nilai parameter masukan ke parameter keluaran. Anda sekarang dapat menggunakan prosedur ini untuk menentukan nilai SCOPE_IDENTITY() di Adaptor Kursor. Untuk melakukan ini di acara tersebut Sebelum Masukkan substitusi seperti itu sedang dilakukan

PROSEDUR Sebelum Masukkan LPARAMETER cFldState, lForce, cInsertCmd cInsertCmd = cInsertCmd + ; "; nyatakan @id int" + ;"; PILIH @id=SCOPE_IDENTITY()" + ;

"; EXEC Get_ValueInt @id,

[dilindungi email] "ENDPROC, pada dasarnya, prosedur tersimpan dinamis dihasilkan. Itu. bukan hanya satu perintah INSERT, tetapi serangkaian perintah. Perintah dipisahkan satu sama lain dengan titik koma, meskipun hal ini tidak perlu. Cukup memisahkan perintah satu sama lain dengan spasi sederhana.

Menemukan rekor baru berdasarkan nilai bidang lain

Jika Anda memiliki Visual FoxPro 8, maka Anda dapat menggunakan metode yang mirip dengan metode yang digunakan untuk mencari nilai variabel sistem @@IDENTITY. Itu. dalam metode AfterInsert objek Adaptor Kursor, lakukan kueri tambahan melalui SQLExec()

Dimulai dengan Visual FoxPro 9, objek Adaptor Kursor diperkenalkan properti tambahan, memungkinkan Anda mengotomatiskan prosedur ini tanpa menulis kode tambahan

SisipkanCmdRefreshFieldList- daftar bidang yang nilainya akan diperbarui setelah Sisipkan
SisipkanCmdRefreshKeyFieldList- sebuah field, atau sekumpulan field non-kunci yang juga secara unik mengidentifikasi sebuah record, yang akan digunakan untuk mencari record baru

Perlu dicatat bahwa properti ini tidak menunjukkan nama bidang tabel dari server MS SQL itu sendiri, tetapi nama bidang terkait yang diterima kursor di sisi klien. Untuk contoh yang sama akan terlihat seperti ini:

InsertCmdRefreshFieldList = "TabID" InsertCmdRefreshKeyFieldList = "Nama Panggilan"

Dengan kata lain, berdasarkan nilai field NickName, sebuah record akan ditemukan pada tabel di server MS SQL dan nilai field TabID akan dibaca, setelah itu nilai ini akan ditulis ke record baru di sisi klien.


Anda dapat melihat pembahasan lebih detail mengenai topik ini dan contoh penggunaannya di sini



Vladimir Maksimov
Pembaruan terakhir: 01/05/06

Anda telah melihat beberapa konvensi konfigurasi yang digunakan pendekatan ini. Secara khusus, Anda melihat cara menyesuaikan model entitas menggunakan anotasi data yang diungkapkan melalui atribut C# dan menggunakan Fluent API. Dalam artikel ini dan artikel berikutnya, kita akan melihat lebih dekat cara menyesuaikan model data Anda.

Mengatur Jenis Kolom

Sebelumnya dalam contoh Code-First, Anda melihat penggunaan atribut metadata tertentu yang memungkinkan Anda mengkustomisasi tipe data kolom dalam tabel database dan menerapkan batasan padanya (misalnya, apakah kolom tersebut mendukung nilai NULL). Selanjutnya kita akan melihat atribut-atribut ini lebih detail.

Batasan panjang

Tabel di bawah menunjukkan konvensi untuk membatasi panjang kolom, implementasinya sebagai anotasi, dan di Fluent API:

Pembatasan panjang dapat diterapkan pada string atau array byte. Menurut konvensi, Code-First hanya menggunakan batasan panjang maksimal, ini berarti SQL Server menyetel tipe data untuk array string dan byte ke NVARCHAR(n) dan VARBINARY(n), dengan n adalah panjang yang ditentukan dalam batasan. Secara default, jika tidak ada batasan panjang yang diterapkan pada properti model, Code-First akan menyetel panjang kolom maksimum yang mungkin menjadi NVARCHAR(max) dan VARBINARY(max).

Seperti yang ditunjukkan dalam tabel, dengan menggunakan anotasi data, Anda dapat mengatur panjang minimum untuk properti model menggunakan atribut MinLength - batasan ini tidak berpengaruh pada tabel database. (Seperti dijelaskan sebelumnya, atribut metadata dapat digunakan tidak hanya di Entity Framework, namun, misalnya, juga dalam validasi model ASP.NET.) Inilah sebabnya Fluent API tidak memiliki metode HasMinLength(), karena API ini adalah bagian dari Entity Framework dan bertanggung jawab untuk menyiapkan konvensi yang terkait dengan Code-First saja.

Perlu dicatat bahwa Anda dapat menentukan panjang bidang maksimum dan minimum dalam satu atribut StringLength, menggunakan parameter bernama dari atribut ini. Contoh berikut menunjukkan penggunaan batasan panjang menggunakan anotasi (di sini kita menggunakan contoh model yang kita buat di artikel “Menggunakan Kode-Pertama” sebelumnya):

Menggunakan Sistem; menggunakan System.Collections.Generik; menggunakan System.ComponentModel.DataAnnotations; namespace CodeFirst ( kelas publik Pelanggan ( public int CustomerId ( get; set; ) public string FirstName ( get; set; ) public string LastName ( get; set; ) public string Email ( get; set; ) public int Age ( get; set ; ) byte publik Foto ( dapatkan; set; ) // Tautan ke pesanan Daftar virtual publik Pesanan ( get; set; ) ) kelas publik Pesanan ( public int OrderId ( get; set; ) public string Nama Produk ( get; set; ) public string Deskripsi ( get; set; ) public int Quantity ( get; set; ) public DateTime Tanggal Pembelian ( dapatkan; set; ) // Tautan ke Pelanggan Pelanggan publik pembeli ( dapatkan; set; ) ) )

Dan pada kode berikut, pengaturan serupa dilakukan menggunakan Fluent API (izinkan saya mengingatkan Anda bahwa untuk menggunakan API ini, Anda perlu mengganti metode konfigurasi PadaModelCreating() di kelas konteks, yang dalam contoh kita adalah kelas SampleContext):

().Properti(c => c.NamaDepan).HasMaxLength(30); modelBuilder.Entitas ().Properti(c => c.Email).HasMaxLength(100);

modelBuilder.Entitas

Seperti dijelaskan sebelumnya, Entity Framework secara otomatis memetakan tipe data model ke tipe data yang kompatibel dengan SQL. Code-First memungkinkan Anda mengontrol proses ini dengan secara eksplisit menentukan tipe data untuk kolom, seperti yang ditunjukkan pada contoh di bawah ini:

Pelanggan kelas publik ( public int CustomerId ( get; set; ) // ... public byte Photo ( get; set; ) // ... ) // sama dengan Fluent API protected override void OnModelCreating(DbModelBuilder modelBuilder) ( modelBuilder. Kesatuan ().Properti(c => c.CustomerId) .HasColumnType("smallint"); modelBuilder.Entitas

().Properti(c => c.Foto) .HasColumnType("gambar"); )

Dukungan kolom NULL

Konvensi Entity Framework untuk mendukung nilai null dalam kolom tabel adalah bahwa semua tipe .NET yang mendukung null (objek) dipetakan ke tipe SQL dengan klausa NULL eksplisit, dan sebaliknya untuk tipe .NET yang tidak mendukung struktur null ( ) dipetakan ke tipe SQL dengan secara eksplisit menentukan pernyataan NOT NULL. Untuk secara eksplisit menentukan bahwa tipe data tidak boleh mendukung nilai NULL, Anda perlu menggunakan atribut Required dalam model data atau menggunakan metode IsRequired() pada objek konfigurasi di Fluent API. Untuk secara eksplisit menunjukkan bahwa tipe data harus mendukung nilai NULL, Anda perlu menggunakan koleksi Nullable

atau gunakan sintaks C#, yang mana untuk tipe nilai yang mendukung null menyertakan tanda tanya setelah tipenya (misalnya, int?).

Contoh di bawah ini menunjukkan penggunaan pengaturan ini untuk mengonfigurasi informasi tentang tipe nullable atau non-nullable dalam tabel database: Pelanggan kelas publik ( public int CustomerId ( get; set; ) public string FirstName ( get; set; ) public string LastName ( get; set; ) // Bidang ini dapat berupa NULL // karena kita telah secara eksplisit menentukan tipe int? public int? Age ( get; set; ) // Mirip dengan properti public Nullable sebelumnya Age1 ( get; set; ) // ... ) // sama dengan Fluent API protected override void OnModelCreating(DbModelBuilder modelBuilder) ( modelBuilder.Entity ().Properti(c => c.NamaDepan).IsRequired();

modelBuilder.Entitas

().Properti(c => c.LastName).IsRequired(); )

Entity Framework mengharuskan setiap kelas model entitas memiliki kunci unik (karena setiap tabel di basis data relasional data harus digunakan kunci utama). Kunci ini digunakan dalam objek konteks untuk melacak perubahan pada objek model. Code-First membuat beberapa asumsi ketika mencari kunci dalam tabel. Misalnya, ketika kita membuat database untuk kelas entitas Pelanggan dan Pesanan sebelumnya dalam pendekatan Code-First, Entity Framework menandai bidang CustomerId dan OrderId dalam tabel sebagai kunci utama dan mengaturnya untuk mendukung tipe non-nullable:

EF juga secara otomatis menambahkan dukungan untuk penambahan otomatis di bidang ini (izinkan saya mengingatkan Anda bahwa di T-SQL hal ini dilakukan menggunakan pernyataan IDENTITY). Paling sering, kunci utama dalam database bertipe INT atau GUID, meskipun tipe primitif apa pun dapat digunakan sebagai kunci utama. Kunci utama dalam database dapat terdiri dari beberapa kolom tabel, demikian pula kunci model entitas EF dapat terdiri dari beberapa properti model. Nanti Anda akan melihat cara mengatur kunci komposit.

Menetapkan kunci utama secara eksplisit

Dalam kasus dua kelas Pelanggan dan Pesanan, tidak perlu khawatir menentukan kunci utama secara eksplisit, karena Kami menggunakan properti CustomerId dan OrderId, yang mengikuti konvensi penamaan kunci - “+Id”. Mari kita lihat contoh di mana Anda perlu menentukan kunci primer secara eksplisit. Tambahkan kelas sederhana berikut ke file model Anda:

Proyek kelas publik ( Pengidentifikasi Panduan publik ( get; set; ) DateTime StartDate publik ( get; set; ) DateTime EndDate publik ( get; set; ) Biaya desimal publik ( get; set; ) )

Tujuan kami adalah untuk menunjukkan bahwa properti Identifier di kelas ini adalah kunci utama tabel. Seperti yang Anda lihat, nama properti ini tidak mengikuti konvensi penamaan Entity Framework untuk kunci utama.

Tambahkan deskripsi tabel baru ke kelas konteks SampleContext:

SampleContext kelas publik: DbContext ( // ... public DbSet Proyek ( dapatkan; set; ) // ... )

Sekarang, jika Anda menjalankan aplikasi kami dan memasukkan data pelanggan baru, pengecualian akan dihasilkan di kelas DbModelBuilder karena kelas tersebut tidak dapat membangun model data entitas dengan benar. (Izinkan saya mengingatkan Anda bahwa aplikasi kita adalah situs ASP.NET sederhana yang menerapkan kemampuan untuk memasukkan pelanggan baru.)

Pengecualian ini disebabkan oleh Entity Framework tidak menemukan properti bernama Id atau ProjectId di tabel Project, dan Code-First tidak dapat menentukan bidang mana yang akan digunakan sebagai kunci utama tabel. Masalah ini dapat diperbaiki dengan menggunakan anotasi data atau Fluent API, seperti yang ditunjukkan pada contoh di bawah:

Proyek kelas publik ( Pengidentifikasi Panduan publik ( get; set; ) DateTime StartDate publik ( get; set; ) DateTime EndDate publik ( get; set; ) Biaya desimal publik ( get; set; ) ) // sama dengan Fluent API protected override void OnModelCreating(DbModelBuilder modelBuilder) ( modelBuilder.Entity ().HasKey(p => p.Identifier); )

Perhatikan bahwa saat menggunakan Fluent API, metode HasKey() ditentukan setelah pemanggilan metode Entitas (), bukan setelah memanggil Entitas ().Property(), seperti yang dilakukan pada contoh di atas, karena Kunci utama disetel di tingkat tabel, bukan di tingkat properti.

Menyiapkan kenaikan otomatis untuk kunci utama

Seperti dapat dilihat dari tabel, mengikuti konvensi, Entity Framework menentukan kenaikan otomatis untuk properti bertipe int. Dalam tabel Proyek yang dibuat sebelumnya, jenis kunci utama ditentukan sebagai Panduan, sehingga EF tidak menggunakan penghitung untuk bidang ini saat membuat tabel di database. Hal ini ditunjukkan pada gambar:

Mari tambahkan formulir web baru ke proyek kita, yang akan kita sebut DatabaseGenerated.aspx. Di handler Page_Load, tambahkan kode berikut di mana kita menambahkan data baru ke tabel Project. Dalam hal ini, data ini akan ditambahkan setiap kali kita membuka halaman formulir web di browser.

Menggunakan Sistem; menggunakan Sistem.Data.Entitas; menggunakan CodeFirst; namespace ProfessorWeb.EntityFramework ( kelas parsial publik DatabaseGenerated: System.Web.UI.Page ( protected void Page_Load(pengirim objek, EventArgs e) ( // Pengaturan ini diperlukan agar database secara otomatis // dihapus dan dibuat ulang ketika perubahan struktur model // (untuk memudahkan pengujian contoh) Database.SetInitializer(New DropCreateDatabaseIfModelChanges ()); Konteks SampleContext = SampleContext baru(); proyek proyek

= Proyek baru ( StartDate = DateTime.Now, EndDate = DateTime.Now.AddMonths(1), Biaya = 8000M );

Baik database maupun Entity Framework tidak mengetahui bahwa kita ingin membuat Panduan baru untuk setiap entri baru, sehingga Panduan yang berisi semua angka nol akan dibuat secara otomatis. Jika Anda me-refresh halaman di browser (sebenarnya, dalam hal ini kode akan mencoba memasukkan catatan baru ke dalam tabel), maka Entity Framework akan mengembalikan SqlException, yang terjadi karena kami mencoba memasukkan catatan dengan identifier yang sudah ada pada tabel, yaitu e. dalam hal ini, batasan kunci utama dipicu - batasan tersebut harus unik untuk setiap rekaman baru.

Oleh karena itu, untuk mengatasi masalah ini, kita perlu menghasilkan pengenal unik Panduan dalam kode. Tabel yang menggunakan kenaikan otomatis untuk kunci utama tidak memiliki ini pekerjaan ekstra, Karena Untuk setiap record baru yang disisipkan, penghitung membuat nilai baru untuk kunci utama dengan mengambil nilai kunci utama untuk catatan terakhir dan menambahkan 1 ke dalamnya (jika konstruksi IDENTITY(1,1) digunakan).

Untuk mengatasi masalah ini untuk kunci bertipe selain int, Anda perlu menggunakan atribut metadata DatabaseGenerated, yang konstruktornya menentukan Pencacahan DatabaseGeneratedOption, yang memiliki tiga kemungkinan nilai:

Tidak ada

Basis data tidak membuat nilai unik apa pun untuk kunci utama. Sebenarnya, dengan opsi ini Anda bisa menonaktifkannya penambahan otomatis kenaikan otomatis ke kunci utama bertipe int.

Identitas

Saat Anda memasukkan nilai ke dalam tabel, database akan membuat nilai unik untuk kunci utama.

Dihitung

Mirip dengan Identity, dengan satu-satunya pengecualian bahwa kunci utama akan dihasilkan tidak hanya saat memasukkan catatan ke dalam tabel, tetapi juga saat memperbaruinya.

Ubah kelas model untuk menginstruksikan database membuat kunci primer unik:

Proyek kelas publik ( Pengidentifikasi Panduan publik ( get; set; ) DateTime StartDate publik ( get; set; ) DateTime EndDate publik ( get; set; ) Biaya desimal publik ( get; set; ) )

Jalankan proyek sampel dan segarkan halaman beberapa kali untuk memasukkan beberapa catatan ke dalam tabel dan memastikan bahwa pengecualian tidak lagi muncul. Gambar di bawah menunjukkan data yang ditambahkan ke tabel:

Harap perhatikan ID yang dibuat secara otomatis untuk proyek. Efek yang sama dapat dicapai dengan menggunakan metode HasDatabaseGeneratedOption() di Fluent API:

Penggantian yang dilindungi batal OnModelCreating(DbModelBuilder modelBuilder) ( modelBuilder.Entity ().Properti(p => p.Identifier).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); )

Bekerja dengan tipe data yang kompleks

Entity Framework telah mendukung kemampuan untuk menggunakan tipe kompleks sejak versi 1. Faktanya, tipe kompleks di .NET adalah kelas yang bisa direferensikan dalam kelas model. Tipe kompleks tidak memiliki kunci dan dapat digunakan di beberapa objek model. Mari kita lihat contoh model berikut:

Pengguna kelas publik ( public int UserId ( get; set; ) public int SocialNumber ( get; set; ) public string Nama Depan ( get; set; ) public string LastName ( get; set; ) public string StreetAddress ( get; set; ) public string Kota ( dapatkan; set; ) kode pos string publik ( dapatkan; set; ) )

Di kelas ini, alamat tempat tinggal pengguna dapat dipisahkan menjadi kelas tersendiri dan dirujuk ke:

Pengguna kelas publik ( public int UserId ( get; set; ) public int SocialNumber ( get; set; ) public string FirstName ( get; set; ) public string LastName ( get; set; ) public Address Address ( get; set; ) ) Alamat kelas publik ( public int AddressId ( get; set; ) public string StreetAddress ( get; set; ) public string City ( get; set; ) public string ZipCode ( get; set; ) )

Berdasarkan konvensi, Entity Framework akan menguraikan model ini - seperti dua tabel terpisah. Namun tujuan kita adalah membuat tipe kompleks dari kelas Address. Cara tradisional untuk membuat tipe kompleks dari kelas Address, mewakili penghapusan AddressId:

Alamat kelas publik ( // public int AddressId ( get; set; ) public string StreetAddress ( get; set; ) public string City ( get; set; ) public string ZipCode ( get; set; ) )

Selain aturan bahwa tipe kompleks tidak boleh memiliki kunci, Code-First menerapkan dua aturan lain yang harus dipenuhi untuk mendeteksi tipe kompleks. Pertama, tipe kompleks hanya boleh berisi properti sederhana. Kedua, kelas yang menggunakan tipe ini tidak diperbolehkan menentukan tipe koleksi untuk properti tipe kompleks. Dengan kata lain, jika Anda ingin menggunakan tipe Alamat yang kompleks di kelas Pengguna, maka properti yang memiliki tipe tersebut tidak boleh ditandai Daftar

atau gunakan koleksi lain.

Seperti yang ditunjukkan pada gambar di bawah, setelah menjalankan aplikasi, Code-First mengenali tipe kompleks dan membuat bidang khusus di tabel Pengguna (ingat untuk menambahkan deklarasi Pengguna di kelas konteks):

Perhatikan bagaimana kolom yang menjelaskan alamat pengguna diberi nama: ComplexTypeName_PropertyName. Ini adalah konvensi Entity Framework untuk memberi nama tipe kompleks.

Mengonfigurasi Tipe Kompleks untuk Melewati Konvensi Kode-Pertama

Bagaimana jika kelas Anda yang mendeskripsikan tipe kompleks tidak mengikuti konvensi Entity Framework, misalnya, Anda ingin menggunakan bidang AddressId di kelas Alamat? Jika sekarang kita menambahkan bidang ini ke kelas Alamat dan menjalankan proyek, maka alih-alih satu tabel Pengguna dan tipe Alamat yang kompleks, Entity Framework akan membuat dua tabel, teman terkait dengan kunci asing lainnya. Untuk memperbaiki masalah ini, Anda dapat menentukannya secara eksplisit Atribut ComplexType di kelas model atau penggunaan Metode ComplexType() Kelas DbModelBuilder di Fluent API:

Alamat kelas publik ( public int AddressId ( get; set; ) public string StreetAddress ( get; set; ) public string City ( get; set; ) public string ZipCode ( get; set; ) ) // sama dengan Fluent API protected override void OnModelCreating(DbModelBuilder modelBuilder) ( modelBuilder.ComplexType

(); }

Telah dikatakan di atas bahwa kelas yang mendeskripsikan tipe kompleks seharusnya hanya memiliki properti sederhana (yaitu properti yang tidak merujuk ke objek lain). Kesepakatan ini dapat diatasi dengan cara yang sama. Di bawah ini adalah contoh dimana tipe kompleks baru UserInfo telah ditambahkan yang mereferensikan tipe FullName lain:

Pengguna kelas publik ( public int UserId ( get; set; ) UserInfo publik UserInfo ( get; set; ) Alamat Alamat publik ( get; set; ) ) UserInfo kelas publik ( public int SocialNumber ( get; set; ) // Bukan properti sederhana Nama Lengkap publik Nama Lengkap ( dapatkan; set; ) ) Nama Lengkap kelas publik ( string publik Nama Depan ( dapatkan; set; ) string publik Nama Belakang ( dapatkan; set; ) ) Alamat kelas publik ( public int AddressId ( dapatkan; set; ) string publik Alamat Jalan ( dapatkan; setel; ) string publik Kota ( dapatkan; set; ) kode pos string publik ( dapatkan; set; ) )

Dengan menentukan ke Code-First bahwa UserInfo adalah tipe kompleks menggunakan atribut ComplexType, kami mengatasi batasan yang dikenakan pada tipe kompleks menggunakan konvensi default.

Perlu diperhatikan bahwa Code-First memungkinkan Anda menyesuaikan tipe kompleks seperti tabel biasa menggunakan Fluent API atau anotasi. Di bawah ini adalah contoh untuk menyiapkan tipe Alamat yang kompleks:

Alamat kelas publik ( public int AddressId ( get; set; ) public string StreetAddress ( get; set; ) public string City ( get; set; ) public string ZipCode ( get; set; ) ) // sama dengan Fluent API protected override void OnModelCreating(DbModelBuilder modelBuilder) ( modelBuilder.ComplexType

().Properti(a => a.StreetAddress).HasMaxLength(100); )

Gambar di bawah menunjukkan struktur tabel Pengguna. Di sini Anda dapat melihat bagaimana EF memberi nama properti tipe kompleks dengan referensi di dalamnya dan EF menempatkan batasan pada bidang StreetAddress:

Deskripsi pengaturan lainnya

Di bagian ini, kita akan melihat secara singkat semua pengaturan kolom tabel lainnya, yang jarang digunakan karena fitur spesifiknya.

Kolom stempel waktu

Tipe data T-SQL TIMESTAMP menentukan kolom yang didefinisikan sebagai VARBINARY(8) atau BINARY(8), bergantung pada nullabilitas kolom. Untuk setiap database, sistem memelihara penghitung yang nilainya bertambah setiap kali baris yang berisi sel TIMESTAMP disisipkan atau diperbarui, dan menetapkan nilai tersebut ke sel tersebut. Jadi, dengan menggunakan sel bertipe TIMESTAMP, Anda dapat menentukan waktu relatif perubahan terakhir baris tabel yang sesuai. (ROWVERSION adalah sinonim untuk TIMESTAMP.)

Dengan sendirinya, nilai yang disimpan dalam kolom TIMESTAMP tidak penting. Kolom ini biasanya digunakan untuk menentukan apakah baris tabel tertentu telah berubah sejak terakhir kali diakses. Hal ini memungkinkan akses bersamaan ke tabel database ditangani dengan mengizinkan thread lain untuk memblokir jika thread saat ini telah mengubah nilai berturut-turut.

Di Code-First, untuk menunjukkan bahwa kolom harus bertipe TIMESTAMP, nama yang sama harus digunakan Atribut stempel waktu dalam anotasi atau Metode IsRowVersion() di Fluent API, seperti yang ditunjukkan pada contoh di bawah ini:

RowVersion byte publik ( get; set; ) // sama dengan Fluent API protected override void OnModelCreating(DbModelBuilder modelBuilder) ( modelBuilder.Entity ().Properti(p => p.RowVersion).IsRowVersion(); )

Cara yang kurang umum untuk memastikan keamanan saat bekerja dengan thread konkuren adalah dengan menentukan pemeriksaan konkurensi untuk setiap kolom. Metode ini juga dapat digunakan dalam DBMS yang tidak mendukung tipe Timestamp/Rowversion. Saat beroperasi dengan cara ini, thread tidak memeriksa apakah record dalam tabel telah berubah, namun hanya memblokir akses ke thread lain hingga proses penulisan selesai. Untuk menentukan kolom yang harus lolos pemeriksaan konkurensi, gunakan Atribut ConcurrencyCheck dalam anotasi, atau Metode IsConcurrencyToken() di API Lancar.

Mengubah pengkodean string dari Unicode ke ASCII

Secara default, Entity Framework mengubah segalanya jenis string model data seperti string atau char menjadi tipe string data SQL, menggunakan pengkodean Unicode dua byte - NVARCHAR atau NCHAR. Anda dapat mengubah perilaku ini dan secara eksplisit memberitahu EF untuk menggunakan byte tunggal Pengkodean ASCII– Tipe VARCHAR dan CHAR akan digunakan sesuai kebutuhan. Untuk melakukan ini, Anda perlu menggunakan Metode IsUnicode() dengan parameter boolean diteruskan ke false di Fluent API. Anotasi tidak memberikan kemampuan untuk menyesuaikan pengkodean string.

Menentukan presisi untuk tipe Desimal

Anda dapat menggunakan Metode HasPrecision() dengan meneruskan dua parameter ke dalamnya, yang digunakan di Fluent API. Anotasi data di Code-First tidak menawarkan alternatif untuk metode ini. Secara default, Entity Framework menetapkan presisi ke 18 dan skala ke 2 untuk tipe Desimal.

Contoh di bawah ini menunjukkan penggunaan metode ini, untuk properti Biaya dari tabel Proyek yang kita buat sebelumnya, ketika melihat kunci utama:

Penggantian yang dilindungi batal OnModelCreating(DbModelBuilder modelBuilder) ( modelBuilder.Entity ().Properti(p => p.Biaya).HasPrecision(6, 3); )

  • Sergei Savenkov

    semacam ulasan "pendek"... seolah-olah mereka sedang terburu-buru di suatu tempat