2010-10-22 220 views
124

我有一個現有的分貝,我想使用EF4.0實體框架:表沒有主鍵

一些表沒有定義主鍵,這樣,當我創建一個新的實體,以建立一個新的應用程序數據模型中,我收到以下消息:「表/視圖TABLE_NAME沒有定義主鍵,並且沒有有效的主鍵可以被推斷出來,這個表/視圖已經被排除了,要使用這個實體,你需要檢查你的架構,添加正確的密鑰,並取消註釋「。

如果我想使用它們並修改數據,我必須向這些表添加一個PK,還是有解決方法,以便我不必?

+19

引用Joe Celko:*如果它沒有主鍵,則不是表*。爲什麼人人都會創建一個沒有主鍵的「常規」表?只需添加那些PK!你會需要他們 - 而不是晚於... – 2010-10-22 12:55:22

+2

+1即使你引用celko ;-) – 2010-10-22 13:19:32

+4

如果它的一個視圖這個哈瓦看起來這個案例http://stackoverflow.com/a/10302066/413032 – 2012-04-24 16:32:43

回答

47

錯誤的含義正是它所說的。

即使你能解決這個問題,相信我,你不想。可能引入的令人困惑的錯誤數量驚人而可怕,更不用說您的性能可能會下降。

不要解決這個問題。修復你的數據模型。

編輯:我見過很多人都在回答這個問題。我想這很好,但請記住,OP詢問了如何映射沒有主鍵,而不是視圖。答案依然如此。從可管理性,數據完整性和性能的角度來看,解決EF需要對錶進行PK是個壞主意。

有些人評論說他們沒有能力修復底層數據模型,因爲他們映射到第三方應用程序。這不是一個好主意,因爲模型可以從你下面改變。可以說,在這種情況下,你會想要映射到一個視圖,而這又不是OP所要求的。

+34

同意常見senarios,但在罕見的senarios像LOG表,你只需要儘快插入記錄。在檢查唯一性和編制索引時發生PK可能是一個問題。另外如果你的PK是IDENTITY,那麼將生成的值返回給EF是另一個問題。使用GUID呢?世代時間和索引/排序是另一個問題!...所以在沒有PK的一些重要OLTP senarios(如Logging)中,這是一個觀點,並且它沒有任何正面的觀點! – 2012-01-29 22:18:47

+3

@MahmoudMoravej:首先,不要混淆聚類索引和主鍵的想法。他們不是一回事。您可以在IDENTITY列上具有聚簇索引的表上進行非常高性能的插入。如果遇到索引維護問題,則應正確分區表。留下沒有聚集索引的表格也意味着您不能有效地對其進行碎片整理,以便在刪除後回收空間。我憐憫那些試圖查詢日誌表的人,如果它沒有索引的話。 – 2012-01-30 04:08:54

+1

感謝Dave,你讓我重新思考:-)。我不知道我們可以擁有非羣集PK(雖然它的性能比clusterd-one少於唯一性檢查,不是嗎?特別是在IDENTITY PK當新的插入將被放在表空間的末尾)。 – 2012-01-30 11:16:04

2

如果你真的沒有PK,上面的答案是正確的。

但是,如果有一個,但它只是沒有指定與數據庫中的索引,並且你不能改變數據庫(是的,我在迪爾伯特的世界工作),你可以手動映射領域(S)是鑰匙。

4

EF不需要數據庫上的主鍵。如果確實如此,則無法將實體綁定到視圖。

您可以修改SSDL(和CSDL)以將唯一字段指定爲主鍵。如果你沒有一個獨特的領域,那麼我相信你會被洗腦。但你真的應該有一個獨特的領域(和一個PK),否則你將在稍後遇到問題。

埃裏克

+0

這可以避免ISNULL破解。但根據情況,可能需要其他答案 - 例如,我有一種感覺,某些數據類型不支持EF中的PK。 – Todd 2014-10-11 03:35:09

93

我認爲這是由Tillito解決:

Entity Framework and SQL Server View

我引用下面的他項:

我們有同樣的問題,這是解決方案:

要強制實體框架使用列作爲主鍵,請使用ISNULL。

要強制實體框架不要使用列作爲主鍵,請使用NULLIF。

一個簡單的方法來運用,這是包裝視圖的select語句的另一個選擇。

實施例:

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

回答年04月26 '10在17:00由Tillito

+33

實際回答問題。 – TheSmurf 2012-11-26 21:38:03

+6

+1這是正確的答案,在一個完美的世界中,進入並修改所有遺留數據庫以具有參照完整性是非常好的,但實際上並非總是可行。 – 2013-05-01 17:48:32

+7

我不會推薦這個。特別是ISNULL部分。如果EF檢測到兩個相同的PK,它可能不會呈現唯一記錄,而是返回一個共享對象。這發生在我以前。 – Todd 2013-08-19 03:17:15

1
  1. 改變表結構,並添加一個主列。更新模型
  2. 修改XML編輯器中的.edmx文件,並嘗試在標籤中添加一個新列這個特定表而不是創建一個新的主列於表退出的(無效)
  3. ,我會 做通過涉及所有現有的列組合鍵(保護正常工作

Entity Framework: Adding DataTable with no Primary Key to Entity Model.

+0

我嘗試了EF 4.0的組合鍵方法,但沒有奏效。 – 2012-08-23 15:16:10

+0

這種方法對我來說是完美的,可能是一個與遺留系統「有時」工作的痛苦...... – pinmonkeyiii 2014-05-30 21:42:53

-6

表只需要有一列不允許爲空

2

擁有無用的身份密鑰有時毫無意義。我發現如果ID不被使用,爲什麼添加它?然而,實體並不那麼寬容,所以添加一個ID字段將是最好的。即使在未使用的情況下,它也比處理Entity關於丟失的身份密鑰的不間斷錯誤要好得多。

5

此解決方案

你不需要手動映射,即使你沒有一個PK。 你只需要告訴EF你的一列是索引而索引列是不可空的。

要做到這一點,你可以添加行號,以你的觀點與ISNULL函數類似下面的

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

ISNULL(id, number)是這裏的關鍵點,因爲它告訴EF這列可以是主鍵

+2

雖然我不會建議ISNULL部分。如果EF檢測到兩個相同的PK,它可能不會呈現唯一記錄,而是返回一個共享對象。這發生在我以前。 – Todd 2013-08-19 03:15:52

+1

您必須使用isnull,否則EF將不會承認它不爲空。 – Archlight 2014-02-25 15:19:34

0

從實際的角度來看,每個表 - 甚至像倉庫表這樣的非規格化表 - 都應該有一個主鍵。或者,如果失敗了,它至少應該有一個唯一的,不可爲空的索引。

沒有某種獨特的鍵,重複的記錄可以(將)在表中出現,這既是對ORM層,也爲數據的基本理解很成問題。具有重複記錄的表格可能是不良設計的症狀。

至少,表格應該至少有一個標識列。添加一個自動生成的ID列在SQL Server中需要大約2分鐘,在Oracle中需要5分鐘。對於這種額外的努力,許多問題將被避免。

+0

我的應用程序位於數據倉庫設置(使用Oracle),並且您說服我通過5分鐘來添加索引。它只需要5分鐘(或稍多,如果你需要[查看](http://stackoverflow.com/questions/11464396/add-a-auto-increment-primary-key-to-existing-table- in-oracle)或修改ETL)。 – Trent 2016-01-20 18:36:48

0

我們遇到了這個問題爲好,雖然我們有一個列有空,重要的是,我們必須說沒有空,並且這兩列的組合是獨一無二的依賴列。

所以要引述普拉塔普·雷迪作出的反應,這對我們工作的罰款。

5

在我來說,我有一個實體映射到一個視圖,它不具有主鍵。而且,我不允許修改這個視圖。 幸運的是,這個視圖有一列是唯一的字符串。我的解決方案是將此列標記爲主鍵:

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

被欺騙的EF。工作完美,沒有人注意到...... :)

+0

否..如果您使用Code First方法,它將創建'UserID'列。 – 2014-10-22 18:05:44

+1

你沒有騙過EF。你只是命令關閉'Itentity'功能。基本上,如果我是正確的,它仍然會爲你創建'UserID'列作爲PK,但是當你創建一個新記錄時它不會自動增加'UserID',因爲它是默認的。另外,您仍然需要在'UserID'中保留不同的值。 – Celdor 2015-01-27 10:56:35

+0

@Celdor UserSID是一個字符串,它永遠不會「自動增加」。如果它是一個整數標識列,那麼數據庫將在插入時增加它,而不是實體框架。 – reggaeguitar 2017-07-07 16:03:27

1

這只是@Erick T的答案的補充。如果沒有具有唯一值沒有單列,解決辦法是使用複合鍵,如下所示:

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

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

同樣,這僅僅是一個解決辦法。真正的解決方案是修復數據模型。

8

組合鍵也可以與實體框架流利API

public class MyModelConfiguration : EntityTypeConfiguration<MyModel> 
{ 
    public MyModelConfiguration() 
    { 
     ToTable("MY_MODEL_TABLE"); 
     HasKey(x => new { x.SourceId, x.StartDate, x.EndDate, x.GmsDate }); 
     ... 
    } 
} 
+0

在這種'手動映射'的情況下,我發現在顯示時指定一個自定義鍵是有效的;此外,如果您沒有組合鍵的好處(如本答案中所示),您可以使用'.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)'標記一個'modelBuilder.Entity ()'鏈式調用'非自然或複合的特殊密鑰,但能夠依靠它們是唯一的(通常,無論如何)。 – 2017-01-27 22:48:17

1

這可能是後期做了回答。不過......

如果表簡化版,有一個主鍵然後爲了使EF正常工作,需要分析的場景很少。規則是:EF將與主鍵一起使用表/類。這就是它如何跟蹤...

說,你的表 1.記錄是唯一的: 2.記錄是唯一:唯一性是由單一外鍵列做出的獨特的組合製成多列。 3.記錄不是唯一的(大部分*)。

對於場景#1和#2可以添加下面的行的DbContext模塊OnModelCreating方法: modelBuilder.Entity()HasKey(X =>新的{x.column_a,x.column_b}); //使記錄具有唯一性所需的列數。

對於場景#3,在研究表(*無論如何都使所有記錄獨一無二)後仍然可以使用上述解決方案(#1 +#2)。如果您必須包含所有列才能使所有記錄具有唯一性,那麼您可能需要將主鍵列添加到您的表中。如果此表來自第三方供應商,則將該表克隆到本地數據庫(隔夜或需要多少時間),並通過您的克隆腳本隨意添加主鍵列。