Kerangka Entitas: tabel tanpa kunci primer

165

Saya memiliki DB yang sudah ada dengan mana saya ingin membangun aplikasi baru menggunakan EF4.0

Beberapa tabel tidak memiliki kunci utama yang ditentukan sehingga ketika saya membuat Model Data Entitas baru, saya mendapatkan pesan berikut:

The table/view TABLE_NAME does not have a primary key defined 
and no valid primary key could be inferred. This table/view has 
been excluded. To use the entity, you will need to review your schema, 
add the correct keys, and uncomment it.

Jika saya ingin menggunakannya dan memodifikasi data, haruskah saya menambahkan PK ke tabel tersebut, atau apakah ada solusi agar saya tidak harus melakukannya?

Cris
sumber
21
Mengutip Joe Celko: jika tidak memiliki kunci utama, itu bukan tabel . Mengapa ada orang yang membuat tabel "biasa" tanpa kunci primer ?? Cukup tambahkan PK itu! Anda akan membutuhkannya - lebih cepat daripada nanti ....
marc_s
4
Jika ini adalah pandangan ini lihat kasus ini stackoverflow.com/a/10302066/413032
Davut Gürbüz
50
Sangat valid bahwa tidak setiap tabel membutuhkan kunci utama. Tidak sering bermanfaat, tetapi valid. EF yang membingungkan adalah salah satu alasan bagus, bukan karena itu butuh banyak. ;-).
Suncat2000
25
Bayangkan saya tidak bisa memodifikasi struktur DB di perusahaan saya dan itu dibuat oleh seseorang yang tidak akan mengubah struktur tabel, skenario ini mungkin terjadi.
Tito
4
Di sinilah kita berada. Kami harus bekerja dengan database Oracle pihak ke-3 yang tidak memiliki kunci utama.
David Brower

Jawaban:

58

Kesalahan berarti persis apa yang dikatakannya.

Bahkan jika Anda bisa mengatasi ini, percayalah, Anda tidak mau. Jumlah bug membingungkan yang dapat diperkenalkan sangat mengejutkan dan menakutkan, belum lagi fakta bahwa kinerja Anda kemungkinan akan menurun.

Jangan lakukan ini. Perbaiki model data Anda.

EDIT: Saya telah melihat bahwa sejumlah orang menurunkan pertanyaan ini. Saya kira itu baik-baik saja, tetapi perlu diingat bahwa OP bertanya tentang pemetaan tabel tanpa kunci primer, bukan tampilan . Jawabannya masih sama. Bekerja di sekitar kebutuhan EF untuk memiliki PK di atas meja adalah ide yang buruk dari sudut pandang kemudahan pengelolaan, integritas data, dan kinerja.

Beberapa berkomentar bahwa mereka tidak memiliki kemampuan untuk memperbaiki model data yang mendasarinya karena mereka memetakan ke aplikasi pihak ketiga. Itu bukan ide yang baik, karena model dapat berubah dari bawah Anda. Bisa dibilang, dalam hal ini, Anda ingin memetakan ke tampilan, yang, sekali lagi, bukan apa yang diminta OP.

Dave Markle
sumber
44
Setuju dalam senarios umum tetapi dalam senarios langka seperti tabel LOG Anda hanya perlu memasukkan catatan ASAP. Memiliki PK dapat menjadi masalah ketika memeriksa keunikan dan pengindeksan terjadi. Juga Jika PK Anda adalah IDENTITAS, maka mengembalikan nilai yang dihasilkan ke EF adalah masalah lain. menggunakan GUID saja? waktu pembuatan dan pengindeksan / pengurutan adalah masalah lain! ... SEHINGGA DALAM beberapa senarios OLTP kritis (seperti Logging) tidak memiliki PK adalah sebuah poin dan tidak memiliki poin positif!
Mahmoud Moravej
5
@ MahmoudMoravej: Pertama, jangan gabungkan ide pengelompokan indeks dan kunci primer. Mereka bukan hal yang sama. Anda dapat memiliki sisipan yang sangat berkinerja tinggi pada tabel dengan indeks berkerumun di kolom IDENTITAS. Jika Anda mengalami masalah dengan pemeliharaan indeks, Anda harus mempartisi tabel dengan benar. Meninggalkan tabel tanpa indeks berkerumun juga berarti bahwa Anda tidak dapat mendefrag secara efektif untuk mendapatkan kembali ruang setelah dihapus. Saya kasihan kepada orang miskin yang mencoba untuk menanyakan tabel logging Anda jika tidak memiliki indeks.
Dave Markle
149
"Perbaiki model data Anda" bukanlah jawaban yang nyata. Kadang-kadang kita harus hidup dalam situasi yang kurang ideal yang tidak kita ciptakan dan tidak dapat diubah. Dan, seperti yang dikatakan @Colin, ADA cara untuk melakukan persis apa yang diminta OP.
TheSmurf
13
Mengubah kode untuk memuaskan EF adalah solusi tersendiri. Tidak semua tabel memerlukan kunci primer atau harus dipaksa. Misalnya Anda memiliki Topik dan memiliki 0 atau banyak kata kunci. Tabel kata kunci dapat memiliki id topik induk dan kata kunci yang sesuai. UNTUK mengatakan bahwa saya perlu mengubah DB saya karena EF memaksa saya untuk menjadi lumpuh.
Mrchief
14
Ini harus diturunkan karena tidak menjawab pertanyaan. Kita sering perlu bekerja dengan database pihak ketiga yang tidak dapat diubah.
Kurren
104

Saya pikir ini diselesaikan oleh Tillito:

Kerangka Entitas dan Tampilan SQL Server

Saya akan mengutip karyanya di bawah ini:

Kami memiliki masalah yang sama dan ini solusinya:

Untuk memaksa kerangka entitas untuk menggunakan kolom sebagai kunci utama, gunakan ISNULL.

Untuk memaksa kerangka entitas agar tidak menggunakan kolom sebagai kunci utama, gunakan NULLIF.

Cara mudah untuk menerapkan ini adalah dengan membungkus pernyataan pilih tampilan Anda di pilih lain.

Contoh:

SELECT
  ISNULL(MyPrimaryID,-999) MyPrimaryID,
  NULLIF(AnotherProperty,'') AnotherProperty
  FROM ( ... ) AS temp

dijawab 26 Apr 10 pada 17:00 oleh Tillito

Colin
sumber
6
+1 Ini adalah jawaban yang tepat, di dunia yang sempurna akan sangat bagus untuk masuk dan memodifikasi semua database lama untuk memiliki integritas referensial, tetapi pada kenyataannya itu tidak selalu mungkin.
Dylan Hayes
9
Saya tidak akan merekomendasikan ini. Terutama bagian ISNULL. Jika EF mendeteksi dua PK yang sama, itu mungkin tidak membuat catatan unik, dan sebaliknya mengembalikan objek bersama. Ini telah terjadi kepada saya sebelumnya.
Todd
@Todd - bagaimana itu bisa terjadi jika MyPrimaryID adalah kolom NOT NULL?
JoeCool
@ JoCool, hanya karena BUKAN NULL bukan berarti itu unik. Saya memilih "SOLUSI INI BEKERJA ...", karena apa pun konteksnya, Anda dapat yakin akan keunikannya. Meskipun memikirkannya sekarang, jika catatan dihapus yang secara efektif akan mengubah catatan 'PK' berikut.
Todd
1
-1, karena ini tidak menjawab cara mengonfigurasi kode Entity Framework / C # untuk menangani cara memetakan ke tabel yang tidak memiliki seed identitas. Beberapa perangkat lunak pihak ke-3 (karena alasan tertentu) ditulis dengan cara ini.
Andrew Gray
27

Jika saya ingin menggunakannya dan memodifikasi data, haruskah saya menambahkan PK ke tabel tersebut, atau apakah ada solusi agar saya tidak harus melakukannya?

Bagi mereka yang mencapai pertanyaan ini dan menggunakan Entity Framework Core, Anda tidak perlu lagi menambahkan PK ke tabel mereka atau melakukan solusi apa pun. Sejak EF Core 2.1 kami memiliki fitur baru Jenis Pertanyaan

Jenis pertanyaan harus digunakan untuk:

  • Berfungsi sebagai tipe pengembalian untuk kueri FromSql () ad hoc.
  • Memetakan ke tampilan basis data.
  • Memetakan ke tabel yang tidak memiliki kunci utama yang ditentukan.
  • Memetakan ke kueri yang ditentukan dalam model.

Jadi di DbContext Anda cukup tambahkan properti tipe berikut, DbQuery<T>bukan DbSet<T>seperti di bawah ini. Dengan asumsi nama tabel Anda adalah MyTable:

public DbQuery<MyTable> MyTables { get; set; }
CodeNotFound
sumber
1
Jawaban terbaik jika Anda menggunakan EF Core!
Jay
17

Kunci komposit juga bisa dilakukan dengan Entity Framework Fluent API

public class MyModelConfiguration : EntityTypeConfiguration<MyModel>
{
     public MyModelConfiguration()
     {
        ToTable("MY_MODEL_TABLE");
        HasKey(x => new { x.SourceId, x.StartDate, x.EndDate, x.GmsDate });
        ...
     }
}
Adrian Garcia
sumber
Dalam kasus 'pemetaan manual' semacam ini, saya menemukan bahwa menetapkan kunci khusus seperti yang Anda tunjukkan efektif; selain itu, jika Anda tidak mendapatkan manfaat dari kunci komposit (seperti yang ditunjukkan dalam jawaban ini) Anda dapat menandai modelBuilder.Entity<T>()panggilan berantai .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)dengan kunci-kunci oh-begitu-khusus yang tidak alami atau komposit, tetapi dapat diandalkan setelah menjadi unik (biasanya, lagian.)
Andrew Gray
5

Dalam kasus saya, saya harus memetakan entitas ke tampilan, yang tidak memiliki kunci utama. Selain itu, saya tidak diizinkan untuk mengubah Tampilan ini. Untungnya, Tampilan ini memiliki kolom yang merupakan string unik. Solusi saya adalah menandai kolom ini sebagai kunci utama:

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[StringLength(255)]
public string UserSID { get; set; }

EF curang. Bekerja dengan sempurna, tidak ada yang memperhatikan ... :)

Boris Lipschitz
sumber
tidak .. Ini akan membuat UserIDkolom jika Anda menggunakan pendekatan Code First ..!
Deepak Sharma
1
Anda belum menipu EF. Anda baru saja diperintahkan untuk mematikan Itentityfungsi. Pada dasarnya, jika saya benar, Itu masih akan membuat UserIDkolom untuk Anda sebagai PK tetapi tidak akan secara otomatis meningkatkan UserIDketika Anda membuat catatan baru seperti yang akan secara default. Selain itu, Anda masih perlu menyimpan nilai yang berbeda di UserID.
Celdor
1
@Celdor UserSID adalah sebuah string, itu tidak akan pernah "meningkat secara otomatis". Jika itu adalah kolom identitas bilangan bulat, maka basis data akan menambahkannya pada sisipan, bukan Kerangka Entitas.
reggaeguitar
4

EF tidak memerlukan kunci utama pada basis data. Jika ya, Anda tidak dapat mengikat entitas untuk dilihat.

Anda dapat memodifikasi SSDL (dan CSDL) untuk menentukan bidang unik sebagai kunci utama Anda. Jika Anda tidak memiliki bidang unik, maka saya yakin Anda disemprot. Tetapi Anda benar-benar harus memiliki bidang yang unik (dan PK), jika tidak, Anda akan mengalami masalah nanti.

Erick

Erick T
sumber
Ini menghindari hack ISNULL. Tetapi tergantung pada situasinya, jawaban lain mungkin diperlukan - Saya merasa beberapa tipe data tidak didukung untuk PK di EF misalnya.
Todd
3

Memiliki kunci identitas yang tidak berguna terkadang tidak ada gunanya. Saya menemukan jika ID tidak digunakan, mengapa menambahkannya? Namun, Entity tidak begitu memaafkan tentang hal itu, jadi menambahkan bidang ID akan lebih baik. Bahkan dalam kasus itu tidak digunakan, itu lebih baik daripada berurusan dengan kesalahan tidak henti Entity tentang kunci identitas yang hilang.

IyaTaisho
sumber
3

SOLUSI INI BEKERJA

Anda tidak perlu memetakan secara manual bahkan jika Anda tidak memiliki PK. Anda hanya perlu memberi tahu EF bahwa salah satu kolom Anda adalah indeks dan kolom indeks tidak dapat dibatalkan.

Untuk melakukan ini, Anda dapat menambahkan nomor baris ke tampilan Anda dengan fungsi isNull seperti berikut ini

select 
    ISNULL(ROW_NUMBER() OVER (ORDER BY xxx), - 9999) AS id
from a

ISNULL(id, number) adalah titik kunci di sini karena memberi tahu EF bahwa kolom ini bisa menjadi kunci utama

Barny
sumber
2
Saya tidak akan menyarankan bagian ISNULL. Jika EF mendeteksi dua PK yang sama, itu mungkin tidak membuat catatan unik, dan sebaliknya mengembalikan objek bersama. Ini telah terjadi kepada saya sebelumnya.
Todd
1
Anda harus menggunakan isnull, jika tidak EF tidak akan percaya bahwa itu tidak dapat dibatalkan.
Archlight
2

Jawaban di atas benar jika Anda benar-benar tidak memiliki PK.

Tetapi jika ada satu tetapi tidak ditentukan dengan indeks dalam DB, dan Anda tidak dapat mengubah DB (ya, saya bekerja di dunia Dilbert), Anda dapat memetakan bidang secara manual untuk menjadi kuncinya.

Penjahat Poker
sumber
2

Ini hanya tambahan untuk jawaban @Erick T. Jika tidak ada kolom tunggal dengan nilai unik, solusinya adalah menggunakan kunci komposit, sebagai berikut:

[Key]
[Column("LAST_NAME", Order = 1)]
public string LastName { get; set; }

[Key]
[Column("FIRST_NAME", Order = 2)]
public string FirstName { get; set; }

Sekali lagi, ini hanya solusi. Solusi nyata adalah memperbaiki model data.

Pengembang
sumber
2

Ini mungkin terlambat untuk menjawab ... namun ...

Jika sebuah tabel tidak memiliki kunci utama maka ada beberapa skenario yang perlu dianalisis untuk membuat EF berfungsi dengan baik. Aturannya adalah: EF akan bekerja dengan tabel / kelas dengan kunci utama. Begitulah cara melacak ...

Katakan, tabel Anda 1. Rekaman unik: keunikan dibuat oleh satu kolom kunci asing: 2. Rekaman unik: keunikan dibuat oleh kombinasi beberapa kolom. 3. Rekaman tidak unik (untuk sebagian besar *).

Untuk skenario # 1 dan # 2 Anda dapat menambahkan baris berikut ke modul DbContext metode OnModelCreating: modelBuilder.Entity (). HasKey (x => new {x.column_a, x.column_b}); // sebanyak kolom yang diperlukan untuk membuat catatan unik.

Untuk skenario # 3 Anda masih dapat menggunakan solusi di atas (# 1 + # 2) setelah Anda mempelajari tabel (* apa yang membuat semua catatan unik). Jika Anda harus menyertakan SEMUA kolom untuk membuat semua catatan unik maka Anda mungkin ingin menambahkan kolom kunci utama ke tabel Anda. Jika tabel ini berasal dari vendor pihak ke-3 daripada mengkloning tabel ini ke database lokal Anda (semalam atau sebanyak yang Anda butuhkan) dengan kolom kunci primer ditambahkan secara sewenang-wenang melalui skrip klon Anda.

Sam Saarian
sumber
1
  1. Ubah struktur Tabel dan tambahkan Kolom Utama. Perbarui Model
  2. Ubah file .EDMX dalam XML Editor dan coba tambahkan Kolom Baru di bawah tag untuk tabel spesifik ini (TIDAK AKAN BEKERJA)
  3. Alih-alih membuat Kolom Primer baru ke tabel Keluar, saya akan membuat kunci komposit dengan melibatkan semua kolom yang ada ( DITERAPKAN )

Kerangka Entitas: Menambahkan DataTable tanpa Kunci Utama ke Model Entitas.

Pratap
sumber
Saya mencoba pendekatan kunci komposit dengan EF 4.0 dan tidak berhasil.
Ralph Willgoss
Pendekatan ini bekerja dengan sempurna bagi saya, bisa jadi
menyusahkan
1

Perbarui ke jawaban @CodeNotFound .

Di EF Core 3.0 DbQuery<T>sudah usang, alih-alih Anda harus menggunakan jenis entitas Keyless yang seharusnya melakukan hal yang sama. Ini dikonfigurasikan dengan HasNoKey()metode ModelBuilder . Di kelas DbContext Anda, lakukan ini

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<YourEntityType>(eb =>
        {
            eb.HasNoKey();
        });

}

Namun ada beberapa batasan, terutama:

  • Tidak pernah dilacak untuk perubahan dalam DbContext dan oleh karena itu tidak pernah dimasukkan, diperbarui atau dihapus pada database.
  • Hanya mendukung sebagian kemampuan pemetaan navigasi, khususnya:
    • Mereka mungkin tidak pernah bertindak sebagai tujuan utama suatu hubungan.
    • Mereka mungkin tidak memiliki navigasi ke entitas yang dimiliki
    • Mereka hanya dapat berisi properti navigasi referensi yang menunjuk ke entitas biasa.
    • Entitas tidak dapat berisi properti navigasi ke tipe entitas keyless.

Ini berarti bahwa untuk pertanyaan

Jika saya ingin menggunakannya dan memodifikasi data, haruskah saya menambahkan PK ke tabel tersebut, atau apakah ada solusi agar saya tidak harus melakukannya?

Anda tidak dapat mengubah data dengan cara ini - namun Anda dapat membaca. Seseorang dapat membayangkan menggunakan cara lain (misalnya ADO.NET, Dapper) untuk memodifikasi data - ini bisa menjadi solusi dalam kasus di mana Anda jarang perlu melakukan operasi yang tidak dibaca dan masih ingin tetap menggunakan EF Core untuk sebagian besar kasus Anda.

Juga, jika Anda benar-benar membutuhkan / ingin bekerja dengan tabel heap (keyless) - pertimbangkan untuk membuang EF dan menggunakan cara lain untuk berbicara dengan database Anda.

Peter Lindsten
sumber
0

Dari sudut pandang praktis, setiap meja - bahkan sebuah meja yang didenormalkan seperti meja gudang - harus memiliki kunci utama. Atau, jika gagal, ia setidaknya harus memiliki indeks yang unik dan tidak dapat dibatalkan.

Tanpa semacam kunci unik, rekaman duplikat dapat (dan akan) muncul di tabel, yang sangat bermasalah baik untuk lapisan ORM dan juga untuk pemahaman dasar data. Tabel yang memiliki rekaman duplikat mungkin merupakan gejala desain yang buruk.

Paling tidak, tabel setidaknya harus memiliki kolom identitas. Menambahkan kolom ID pembuatan otomatis membutuhkan waktu sekitar 2 menit di SQL Server dan 5 menit di Oracle. Untuk sedikit usaha ekstra, banyak, banyak masalah akan dihindari.

Ash8087
sumber
Aplikasi saya dalam pengaturan data warehouse (dengan Oracle) dan Anda meyakinkan saya untuk pergi melalui 5 menit untuk menambahkan indeks. Ini benar-benar hanya membutuhkan waktu 5 menit (atau sedikit lebih jika Anda perlu mencarinya atau memodifikasi ETL).
Trent
0

Kami juga mengalami masalah ini, dan sementara kami memiliki kolom yang memiliki nol, yang penting adalah kami memiliki kolom dependen yang tidak memiliki nol dan kombinasi dari dua kolom ini unik.

Jadi mengutip tanggapan yang diberikan oleh Pratap Reddy, itu bekerja dengan baik bagi kami.

Azerax
sumber
0

Saya sangat senang masalah saya terpecahkan.

Tidak dapat memperbarui EntitySet - karena ia memiliki elemen DefiningQuery dan tidak ada elemen <UpdateFunction>

dan lakukan ini: Lihat di bawah garis itu dan temukan tag. Itu akan memiliki pernyataan pilih ol besar di dalamnya. Hapus tag dan isinya ..

sekarang tanpa mengubah DB TI dapat disisipkan ke tabel yang belum memiliki PK

terima kasih semua dan terima kasih Pharylon

aseman arabsorkhi
sumber
-8

Tabel hanya perlu memiliki satu kolom yang tidak memungkinkan nulls

tuan9
sumber