Entity framework 实体框架代码第一个只读实体

Entity framework 实体框架代码第一个只读实体,entity-framework,ef-code-first,Entity Framework,Ef Code First,有没有办法将一个实体标记为只读,而不为其指定任何键?首先可以在代码中强制执行只读。第一种方法是在查询时使用AsNoTracking() var readOnlyPeople = (from p in context.People where p.LastName == "Smith" select p).AsNoTracking(); 这会告诉代码首先不要跟踪对这些实体的更改,因此当您调用SaveC

有没有办法将一个实体标记为只读,而不为其指定任何键?

首先可以在代码中强制执行只读。第一种方法是在查询时使用
AsNoTracking()

var readOnlyPeople = (from p in context.People
                        where p.LastName == "Smith"
                        select p).AsNoTracking();
这会告诉代码首先不要跟踪对这些实体的更改,因此当您调用SaveChanges()时,不会保留对这些对象所做的更改

第二件事是在调用
SaveChanges()
之前将状态设置为
Unchanged

这告诉代码首先忽略对该实体所做的任何更改


只要没有密钥,所有实体都必须有密钥。这可能不一定映射到数据库中的主键,但它“必须唯一地标识实体集中的实体类型实例”。

首先在EF6中使用代码,我创建了一些反映视图的实体,这些实体显然不应该修改或保存。为了防止实体被更改,我使用了保护集属性:

public class TransplantCenterView
{
    public string TransplantsThisYear { get; protected set; }
}
EntityFramework仍然能够设置此属性,但其他开发人员无法在没有编译时错误的情况下意外地设置此属性。这非常有效,但似乎更好的解决方案是完全消除跟踪


感谢,似乎有一个答案(如果以下内容有用,请也投票支持他的答案),这使我可以将代码从:

public class MyContext : DbContext
{
    public DbSet<TransplantCenterVeiw> TransplantCenterViews {get; set;}
}
公共类MyContext:DbContext
{
公共数据库集中心视图{get;set;}
}
致:

公共类MyContext:DbContext
{
//似乎仍然需要DbSet才能使Set()正常工作
受保护的DbSet\u中心视图{get;set;}
//此.AsNoTracking()禁用对我们的DbSet的跟踪。
公共数据库查询中心视图{
获取{return Set().AsNoTracking();}
}
}

我不知道这有什么优点和缺点,但我现有的代码继续工作,没有任何问题,因此似乎是一个胜利。

如果您希望整个实体都是只读的,您可以这样做

/// Using a dbquery since this is readonly.
/// </summary>
public DbQuery<State> States
{
  get
  {
    // Don't track changes to query results
    return Set<State>().AsNoTracking();
 }
}
///使用dbquery,因为它是只读的。
/// 
公共数据库查询状态
{
得到
{
//不跟踪对查询结果的更改
返回集().AsNoTracking();
}
}

源代码优先和只读是相互排斥的。出于好奇,您为什么不需要主键?Enttity映射到一个视图,我不想对其进行更新/插入,因为它也没有主键。默认情况下,EF不会对视图进行更新。@GertArnold,这是错误的。您可以在EF中更新/插入视图。这是否过时?可能是,EF发展得很快。嗨,Brice,你的建议对我来说不是理想的解决方案(我真的更喜欢将该实体标记为只读-它存在于NH中),但我不认为我想要的是EF中一个简洁的解决方案。根据“所有实体都必须有一个键”,我有点同意你的观点,但有时你必须使用一些视图,而它们没有任何键,如果我可以将entitiy标记为只读,为什么我需要一个键。实际上,你可以使用类似于此处建议的ICacheableEntity接口的IReadOnlyEntity标记接口(有一些博客文章描述了这一点,我最初发现的代码,但我找不到它们)有一些与他们之间的关系,你应该考虑(如果有人感兴趣让我知道)最后,我们只是以更自动化的方式执行Brice建议的操作。如果您的视图没有自然键,则可以添加一个以帮助EntityFramework。在视图定义中:在实体的映射中选择NEWID()作为[VirtualKey]……this.HasKey(t=>t.VirtualKey);有关禁用实体跟踪的方法,请参阅我的答案。Devs仍然可以调用MyContext.Set().DoAnyThing(),因此我仍然更喜欢您的
受保护集
解决方案。将DbSet更改为DbQuery。将getter更改为如上所述。已编译。一切正常。但是,当我执行从视图加载数据的页面时,我得到一个运行时错误:“实体类型
MyEntityName
不是当前上下文的模型的一部分。”因此,添加了
protecteddbset\u hiddenmeyentiesname{get;set;}
然后事情就开始了。将数据库集添加到上面的代码中是值得的,这样人们就不会遇到同样的困惑…或者如果有其他方法的话?但是感谢你让我走上正确的道路。有趣的是,我没有遇到这个错误。我映射到表而不是视图,也许这就是区别?嗯…所以,你没有数据库集pProperty在您的上下文中的任何位置,它仍然有效?奇怪…可能也是版本问题。我回到VS 2015和EF6上。我没有只使用DbSet的DbQuery,我的旧LINQ查询工作正常。我也在VS 2015 EF6上,而不是将受保护的DbSet(hiddenMyEntitiesName{get set;}添加到您的上下文中添加modelBuilder.Entity();到onmodel创建方法。
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(); }
    }
}
/// Using a dbquery since this is readonly.
/// </summary>
public DbQuery<State> States
{
  get
  {
    // Don't track changes to query results
    return Set<State>().AsNoTracking();
 }
}