2012-02-23 117 views
11

是否有任何方法將實體標記爲只讀並且不爲其指定任何密鑰?實體框架代碼第一個只讀實體

+0

代碼第一次和只讀是一種相互排斥的。出於好奇,爲什麼你不想要一個主鍵? – Brian 2012-02-23 15:01:03

+1

Enttity映射到一個視圖,我不想更新/插入它,也沒有關鍵。 – Otake 2012-02-23 15:32:42

+0

默認情況下,EF不會對視圖進行更新。 – 2012-02-23 16:00:45

回答

11

在Code First中,您可以執行幾項操作來強制執行只讀。首先是在查詢時使用AsNoTracking()

var readOnlyPeople = (from p in context.People 
         where p.LastName == "Smith" 
         select p).AsNoTracking(); 

這告訴代碼第一次不跟蹤更改這些實體,所以當你打電話SaveChanges()沒有對這些對象所做的更改將是持久的。

在調用SaveChanges()之前,您可以執行的第二件事是將狀態設置爲Unchanged

context.Entry(person).State = EntityState.Unchanged; 
context.SaveChanges(); 

這告訴Code First忽略對該實體所做的任何更改。

只要沒有密鑰,所有實體都必須有密鑰。這可能不一定映射到數據庫中的主鍵,但它「必須唯一標識實體集內的實體類型實例」。

+2

嗨布里斯,你的建議對我來說不是理想的解決方案(我真的更喜歡只是將該實體標記爲只讀 - 它存在於NH中),但我不認爲我想要的是EF中一個整潔的解決方案。按照「所有實體都必須擁有鑰匙」,我贊同你的看法,但有時你必須使用某些觀點,而且他們沒有任何鑰匙,如果我可以將entitiy標記爲只讀,爲什麼我需要鑰匙。 – Otake 2012-03-09 09:33:52

+0

其實你可以使用一個類似於這裏建議的ICacheableEntity接口的IReadOnlyEntity標記接口(有博客文章描述這個以及我最初發現的代碼,但我找不到它們)http://stackoverflow.com/a/ 6593261/34474你應該考慮一些關於它們之間的關係的問題(如果有人有興趣,讓我知道)最後,我們正在以更自動化的方式來做Brice建議的事情。 – Cohen 2012-12-26 11:33:47

+0

如果您的視圖沒有自然鍵,您可以添加一個以幫助EntityFramework。 在視圖定義: SELECT \t NEWID()爲[VirtualKey] ... 在實體的地圖: //主鍵 this.HasKey(T => t.VirtualKey); – Elton 2017-02-15 16:38:34

8

在EF6中使用代碼優先,我創建了一些反映視圖的實體,顯然不應該修改或保存。要防止實體被改變了,我用的保護套屬性:

public class TransplantCenterView 
{ 
    public string TransplantsThisYear { get; protected set; } 
} 

實體框架依然能夠設置該屬性,但其他開發人員可以不小心做沒有一個編譯時錯誤。這很好,但似乎更好的解決方案是完全消除跟蹤。


感謝reggaeguitar's answer,它似乎有一個答案(請投他的答案了,如果下面是有幫助的),這也使我從改變我的代碼:

public class MyContext : DbContext 
{ 
    public DbSet<TransplantCenterVeiw> TransplantCenterViews {get; set;} 
} 

要:

public class MyContext : DbContext 
{ 
    //appears the DbSet is still needed to make Set<Entity>() work 
    protected DbSet<TransplantCenterView> _transplantCenterViews {get; set;} 
    //this .AsNoTracking() disables tracking for our DbSet. 
    public DbQuery<TransplantCenterView> TransplantCenterViews { 
     get { return Set<TransplantCenterView>().AsNoTracking(); } 
    } 
} 

我不知道有什麼利弊,這一點,但我現有的代碼繼續沒有任何扯起工作,所以似乎勝利。

+0

查看我的答案,以禁用對實體的跟蹤。 – reggaeguitar 2017-08-16 19:30:37

+0

Devs _仍然可以調用MyContext.Set ()。DoAnyThing(),所以我仍然更喜歡你的'protected set'解決方案。 – 2017-11-13 06:13:26

1

如果你想爲只讀整個實體,你可以做到這一點

/// Using a dbquery since this is readonly. 
/// </summary> 
public DbQuery<State> States 
{ 
    get 
    { 
    // Don't track changes to query results 
    return Set<State>().AsNoTracking(); 
} 
} 

http://www.adamtuliper.com/2012/12/read-only-entities-in-entity-framework.html

+4

將DbSet更改爲DbQuery。如上所述更改吸氣劑。編譯。都好。但是,當我去執行從視圖加載數據的頁面時,我得到一個運行時錯誤:「實體類型MyEntityName不是當前上下文模型的一部分。」所以,增加了'protected DbSet _hiddenMyEntitiesName {get;設置;}'然後事情奏效。將DbSet <>添加到上面的代碼中是值得的,所以人們不會遇到同樣的困惑......或者如果有另一種方式?但是,謝謝你讓我走上正確的道路。 – 2017-08-16 19:58:31

+0

有趣的是,我沒有得到那個錯誤。我正在映射到表格而不是視圖,也許這是區別? – reggaeguitar 2017-08-17 16:41:43

+0

嗯...所以,你的上下文中沒有DbSet 屬性,它仍然有效?奇怪的...也可能是一個版本問題。我回到了VS 2015和EF6。 – 2017-08-17 18:56:10