2012-02-23 118 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