实体框架代码First ReadOnly Entity

时间:2012-02-23 14:50:11

标签: entity-framework ef-code-first

有没有办法将实体标记为只读而不指定任何密钥?

4 个答案:

答案 0 :(得分:12)

您可以执行以下几项操作,以便在Code First中强制执行只读操作。第一种是在查询时使用AsNoTracking()

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

这告诉Code First不跟踪对这些实体的更改,因此当您调用SaveChanges()时,不会对这些对象进行任何更改。

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

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

这告诉Code First忽略对该实体所做的任何更改。

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

答案 1 :(得分:9)

在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(); }
    }
}

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

答案 2 :(得分: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

答案 3 :(得分:0)

您还可以将其设为只读,作为针对特定实体的更“全局”的规则(按类型)。如果您看到 EF 在保存期间尝试添加实体,只需覆盖相应的 SaveChanges* 方法并设置实体的状态。

public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)
{
    foreach (var entry in ChangeTracker.Entries())
    {
        if (entry.Entity.GetType() == typeof(<YOUR_TYPE_HERE>) && entry.State == EntityState.Added)
        {
            entry.State = EntityState.Detached;
        }
    }

    return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}