Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 实体框架关系中存在异常的单个对象(ObjectDisposeException)_.net_Entity Framework_Include - Fatal编程技术网

.net 实体框架关系中存在异常的单个对象(ObjectDisposeException)

.net 实体框架关系中存在异常的单个对象(ObjectDisposeException),.net,entity-framework,include,.net,Entity Framework,Include,我首先使用EF数据库。当我尝试使用上下文从数据库中获取对象,并且不包含一些属性时,我希望返回null来代替这些对象(以前我在其他项目中使用EF时,存在null)。现在我在这些对象上出现了异常: 获取对象的代码: /// <summary> /// gets a wallet by id and/or user id /// </summary> /// <param name="id">Guid</param> /// <param name

我首先使用EF数据库。当我尝试使用上下文从数据库中获取对象,并且不包含一些属性时,我希望返回null来代替这些对象(以前我在其他项目中使用EF时,存在null)。现在我在这些对象上出现了异常:

获取对象的代码:

/// <summary>
/// gets a wallet by id and/or user id
/// </summary>
/// <param name="id">Guid</param>
/// <param name="userId">string</param>
/// <returns>FAWallet</returns>
public FAWallet GetWallet(Guid id, string userId = null)
{
    try
    {
        using (var context = new FinancialAssistantEntities())
        {
            return context.FAWallet
                .Include(x => x.AspNetUsers)
                .FirstOrDefault(x => x.WalletId == id && (!string.IsNullOrEmpty(userId) ? x.AspNetUsers.Id == userId : true));
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
}
//
///按id和/或用户id获取钱包
/// 
///指南
///串
///法瓦利特
公共FAWallet GetWallet(Guid id,字符串userId=null)
{
尝试
{
使用(var上下文=新的FinancialAsistantEntities())
{
return context.FAWallet
.Include(x=>x.AspNetUsers)
.FirstOrDefault(x=>x.WalletId==id&(!string.IsNullOrEmpty(userId)?x.AspNetUsers.id==userId:true));
}
}
捕获(例外情况除外)
{
掷骰子;
}
}
错误:


在这种情况下,我无法序列化此对象并将其从API发回。

您确实会得到null,这就是延迟加载的工作方式。但如果启用了代理生成和延迟加载,则在您首次引用该属性时将填充这些空值。当结果对象被发送回客户端并被序列化时,序列化引擎将遍历所有属性,这就是延迟加载开始的时候。但是到那时,您已经脱离了using块,因此上下文被释放,因此出现了异常。

一般来说,为了避免这样的问题,请尝试对代码进行结构化,以便您的实体永远不会超出DBContext的范围。在当前使用的结构中,可靠地避免该错误的唯一方法是急切地获取所有依赖项,这通常过于昂贵,并且在许多情况下都不是必需的

您的错误是,您试图在DBContext之外使用FAWallet,而它试图延迟加载FAEntry。临时修复方法是在加载FAWallet时,在FAEntry周围添加.Include()。最终,这会弄巧成拙,因为现在每次查询FAWallet时都要增加查询这些相关实体的成本。(无论是否需要)IMO延迟加载更像是一种诅咒,因为人们很容易被次优代码困住。它们要么放弃并急切地加载所有内容,(昂贵的)添加参数并尝试指示急切地获取什么,(复杂且仍然容易出错),要么向上移动DBContext,以便惰性加载“工作”而不会出错。(慢)

我能提供的最佳解决方案是使用工作单元模式,并确保数据检索逻辑(存储库等)返回
IQueryable
。您的消费代码可以使用任何适合的Linq操作,包括选择子实体或自定义数据结构,以及通过使用.Any()、.SingleOrDefault()、.FirstOrDefault()、.Take()等执行优化查询。这些都是在您希望将数据传递到表示层之前的级别上完成的,组合视图模型。如果您的代码返回IQueryable,您的消费代码将执行以下操作:

using (var unitOfWork = new UnitOfWork()) // Insert whichever unit of work pattern...
{
  var wallets = WalletRepository.GetWalletById(unitOfWork, walletId, userId);
  var viewModel = wallets.Select(w=> new { w.WalletId, w.WalletName, Entries = w.FAEntries.Select(e=> new {e.EntryId, e.EntryAmount}) }).SingleOrDefault();
  return viewModel;
}
GetWalletById返回的是
iQualable
,而不是FAWallet。这样做的原因是,它让我能够灵活地控制如何使用这个结果。本例中的下一行允许我进一步组合查询,EF最终将运行该查询,以仅检索我关心的视图模型的详细信息。如果我使用了一个返回FAWallet的方法,我要么显式地急切地获取相关的实体,然后从数据库返回所有内容,即使我不需要它,要么我最终会延迟加载对DB的调用。
IQueryable
也给了我灵活性。我可以对.Any()使用相同的方法来检查行是否存在,使用不同的.Select()表达式来服务于应用程序的其他区域,支持使用Take()和Skip()进行分页,等等

看看工作单元模式。关于如何使用它,有几个实现和示例。我为EF提升的模式是Mehdime的DbContext范围。其思想是包装DbContext,让与域交互的最外层建立工作单元,而处理业务逻辑和数据检索的服务等通过工作单元访问DbContext。任何往返于视图的内容都将转换为视图模型,而不是依赖于实体。这样做的好处是确保您不会拉取超过需要的数据(更快),而且与处理分离/重新连接的实体相比,它更不容易出现问题