【问题标题】:DbContext not returning local objectsDbContext 不返回本地对象
【发布时间】:2018-02-21 10:06:27
【问题描述】:

我正在使用在 webapi 请求上执行所有操作后调用 dbcontext.SaveChanges 的工作单元模式。在请求的一部分中,我向 dbcontext 添加了一个新客户。

dbContext.Customers.Add(new Customer());

在请求的后期(通常在域事件处理程序内部),我使用相同的 dbcontext 将客户拉回。

_dbContext.Customers.FirstOrDefault(x => x.Id == id);


public abstract class Customer
{
    public Customer()
    {
        Id = Guid.NewGuid();
    }

}

我已验证 dbContext.Customers.Local 具有我所期望的对象,但它似乎并未提取本地对象。这可能是因为 Customer 是一个抽象类,由 DirectCustomer 和 InDirectCustomer 实现吗?

为什么?我可以通过配置更改此行为吗?也许我必须合并本地和数据库结果(有点 hacky)。

更新:

class Program
{
    static void Main(string[] args)
    {
        MyDbContext context = new MyDbContext();

        Guid customerGuid = Guid.NewGuid();

        context.Customers.Add(new DirectCustomer()
        {
            Id = customerGuid
        });

        // This does not work, customerFromLocal1 is null
        var customerFromLocal1 = context.Customers.FirstOrDefault(x => x.Id == customerGuid);

        // This does work, customerFromLocal2 is NOT null
        var customerFromLocal2 = context.Customers.Find(customerGuid);


    }
}


public class MyDbContext : Microsoft.EntityFrameworkCore.DbContext
{
    public DbSet<Customer> Customers { get; set; }


    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("server=.\\sqlexpress;integrated security=true;database=EFCoreDeepDive2");
        base.OnConfiguring(optionsBuilder);
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<DirectCustomer>();
        builder.Entity<IndirectCustomer>();
    }

}

public abstract class Customer
{
    public Guid Id { get; set; }
}

public class DirectCustomer : Customer
{

}

public class IndirectCustomer : Customer
{
    public Guid ParentCustomerId { get; set; }
}

【问题讨论】:

  • Customer 的定义是怎样的,id 是从哪里来的?我目前的怀疑是 EF 可能被设置为自动生成 Customer.Id,但如果是这种情况,在您保存更改之前它不会这样做。
  • @SamIam 不,它是在构造函数中生成的。本地集合中客户的 ID 也与我正在查询的 ID 匹配。
  • FirstOrDefault 将始终执行数据库查询以查找实体。如果您想先查看本地,请考虑使用Find
  • 但它似乎没有提取本地对象我不太明白你的意思。此外,查看显示发生情况而不是描述的代码会有所帮助。很难修复不可见的代码。
  • @Smit 我认为您需要将您的评论转换为答案。请参阅带有人为示例的更新问题

标签: c# entity-framework-core


【解决方案1】:

在 EF Core 中,Linq 运算符(如 FirstOrDefault()、ToList() 等以及它们在异步中的对应部分)会导致针对服务器评估查询。对于查询,服务器数据是事实的来源。如果它们已经加载到内存中,它会合并返回对象,但它会先检查服务器。

当您将新实体对象添加到上下文时,该对象存在于 changetracker 中,但在您调用 SaveChanges() 之前它不会保存到服务器。因此,在添加实体 & 之后,在调用 SaveChanges 之前将针对服务器进行评估的任何查询将没有关于新添加实体的信息,也不会返回任何与之相关的结果。

如果您试图通过当前上下文实例中的键值来查找实体对象,该实体对象可能已保存也可能未保存,则使用context.DbSet.Find() 方法(上下文中还定义了其他变体。查找方法首先检查ChangeTracker 查找对象,其中包含加载到内存中的所有对象和添加/修改的对象。如果找不到,那么它将从服务器加载对象。在您的情况下,因为您想查找已添加到上下文但未添加的实体保存,Find 会给你预期的结果。

注意:DbSet.Local 包含当前上下文跟踪的 DbSet 类型的所有实体。因此,添加的实体在那里可用,但不能直接在 DbSet 上使用。 DbSet 是 IQueryable 以便允许针对它编写服务器查询。

【讨论】:

    猜你喜欢
    • 2019-02-03
    • 2011-02-03
    • 2015-07-26
    • 1970-01-01
    • 2015-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多