C# 当不再有上下文引用时,如何从上下文中分离实体

C# 当不再有上下文引用时,如何从上下文中分离实体,c#,entity-framework,caching,entity-framework-6,datacontext,C#,Entity Framework,Caching,Entity Framework 6,Datacontext,我在我的网站上预加载产品数据,因为我需要它能够快速访问,我希望它在应用程序启动时加载一次,而不仅仅是在它的请求时加载。这是确保快速加载的一种方法。我通过将我的产品实体与其他实体一起加载并存储在内存中来实现这一点 然后,我可以使用类似以下的方法检索数据: public override IEnumerable<Product> Get() { var result = _cacheManager.Get(PreLoadCacheKey) as IEnumerable<Pr

我在我的网站上预加载产品数据,因为我需要它能够快速访问,我希望它在应用程序启动时加载一次,而不仅仅是在它的请求时加载。这是确保快速加载的一种方法。我通过将我的产品实体与其他实体一起加载并存储在内存中来实现这一点

然后,我可以使用类似以下的方法检索数据:

public override IEnumerable<Product> Get()
{
    var result = _cacheManager.Get(PreLoadCacheKey) as IEnumerable<Product>;
    if (result != null)
        return result;

    return base.Get();
}
尝试将从缓存检索的实体附加到我正在添加到数据库的新实体时

我尝试过的事情:

  • 使用
    AsNoTracking()检索数据
  • 在将所有结果添加到缓存之前循环所有结果,并从当前上下文中分离它们,然后在从缓存检索时将它们附加到新上下文
  • 理想情况下,我希望能够从实体的侧面分离实体的上下文,这样我就可以看到实体是否附加到当前上下文,如果没有,则将其从旧上下文分离并附加到新上下文。从我所看到的情况来看,唯一可以将其分离的方法是引用我没有的旧上下文

    我错过了什么明显的东西吗

    编辑

    这是一个将实体附加到另一个上下文的示例:

    var orderLine = order.Lines.FirstOrDefault(ol => ol.Product.Id == product.Id) ?? new SalesOrderLine();
    
    orderLine.Price = price.Price;
    orderLine.Product = product; //This is my cache'd entity.
    orderLine.ProductPriceType = price.ProductPriceType;
    orderLine.Quantity += qty;
    
    order.Customer = customer;
    order.Lines.Add(orderLine);
    order.Status = SalesOrderStatus.Current;
    
    Update(order);
    SaveChanges();
    

    目前,我正在强制加载一个未缓存的版本来解决这个问题。

    由于您无法控制上下文对象的生存时间,我认为在加载时始终分离产品对象并在保存它们时附加它们是有意义的

    因此,当您调用Get()方法而不是只检查缓存管理器时,如果找不到,请执行以下操作从base.Get()返回

        public override IEnumerable<Product> Get()
        {
            var result = _cacheManager.Get(PreLoadCacheKey) as IEnumerable<Product>;
            if (result != null)
                return result;
    
    
            return DetachAndReturn();
        }
    
        private IEnumerable<Product> DetachAndReturn()
        {
            foreach (var product in base.Get())
            {
                base.Detach(product);
                yield return product;
            }  
        }
    
    public override IEnumerable Get()
    {
    var result=_cacheManager.Get(preload cachekey)作为IEnumerable;
    如果(结果!=null)
    返回结果;
    返回并返回();
    }
    private IEnumerable DetactandReturn()
    {
    foreach(base.Get()中的var乘积)
    {
    底座。分离(产品);
    产品收益率;
    }  
    }
    
    使用
    AsNoTracking
    检索缓存数据是第一步。但是(显然)缓存中的对象是作为代理创建的,因此它们知道是由另一个上下文创建的

    因此,请确保缓存的不是代理,而是POCO,这是通过在将对象提取到缓存的上下文中禁用代理创建来实现的:

    db.Configuration.ProxyCreationEnabled = false;
    
    (其中
    db
    DbContext
    实例)

    然后确保在使用该对象之前将其附加到新上下文。这很重要,因为如果您
    Add()
    一个新的
    OrderLine
    ,EF可能也会尝试添加一个新的
    产品


    我想补充一点,如果您在实体模型中公开了
    OrderLine.ProductId
    ,那么这一切都会容易得多:只需设置Id值就足够了。

    感谢您的回复。在内存中,当我过去尝试过这个方法时,将检索到的缓存实体附加到我的当前上下文会导致缓存实体引用我的当前上下文,这意味着下次我从缓存中检索它时,它再次引用旧上下文。这听起来有可能吗?这可能是因为我误解了以前尝试此操作时遇到的问题。请显示引发此异常的代码。您在哪里将
    产品
    与其他实体关联?谢谢。关于你的最后一句话,在这种情况下,它非常有意义(我会这么做),但我有另一个允许编辑产品的区域,因此我将获得正在编辑的当前产品,更改值,然后调用
    Update(product)
    ,这样在这种情况下就没有帮助了。这个代理的东西听起来很有希望,所以我来看看(奇怪的是,我以前没见过)。
    db.Configuration.ProxyCreationEnabled = false;