asp.net-mvc - 当 Web API 返回 IQueryable 时 EF 引用丢失

标签 asp.net-mvc entity-framework asp.net-web-api lazy-loading iqueryable

我已经在这个问题上寻找了很长一段时间了。

这是交易。 我正在构建一个调用 Web API 来获取其数据的网站。我的 Web API 使用一个库,使用存储库模式。我的数据库模型(EF Model-first)是在库中构建的。在该模型中,我有一个基类 Pass。然后我有两个派生类,CustomerCard:Pass 和 Voucher:Pass。 My model from EF Designer

我有一个方法来获取所有客户卡。

public IQueryable<CustomerCard> GetAllPasses() {
        IList<CustomerCard> allCards = new List<CustomerCard>();

        var c_cards = context.Passes;
        foreach (var c_card in c_cards) {
            if (c_card is CustomerCard) {
                allCards.Add((CustomerCard)c_card);
            }
        }
        return allCards.AsQueryable<CustomerCard>();
    }

在我的 ApiController 中,我使用此方法来获取通行证并将其返回到网站,如下所示:

    [HttpGet]
    [Queryable]
    public IQueryable<CustomerCard> GetAllPasses(string version) {
        return passRepo.GetAllPasses().AsQueryable();
    }

我的 Web API 返回 JSON 格式。这是我保留引用和内容的配置:

        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling =
            Newtonsoft.Json.PreserveReferencesHandling.Objects;
        json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
        config.Formatters.Remove(config.Formatters.XmlFormatter);

我使用 IQueryable 是因为我希望能够在我的网站上对数据进行分页。 api 方法位于“/api/v1/passes/all”。

这是奇怪的部分。为了测试我的分页,我每页调用 1 次。 对于我的第一个通行证来说,效果很好。但是当我转到第二页时,他也获得了正确的通行证,但对 User 的引用消失了。

正如您在 my model 中看到的那样,CustomerCard 类有一个属性 User。这表明谁拥有客户卡。

因此,此调用从传递中加载用户:'api/v1/passes/all?$top=1' 但是当我调用这个时,用户实例为NULL:'api/v1/passes/all?$top=1&$skip=1'。

但是,当我调用“api/v1/passes/all?$top=2”时,会加载第二遍的用户。 所以这就是我心碎的地方!我不明白?为什么用户引用不与第二个一起出现?难道和EF的延迟加载特性有关系?

编辑 当我在 context.passes 上使用扩展方法 Include 时,会引发错误:

A specified Include path is not valid. The EntityType 'LCS_Model.Pass' does not declare a navigation property with the name 'User'.

这是因为作为数据库集传递,包含 CustomerCard 以及 Voucher。有没有办法告诉我的上下文期望它或将其转换为 CustomerCard?

有人可以帮助我吗?如果您不明白我的问题,请继续提问!

谢谢大家了!

编辑2

我的 API Controller 上的方法现在是

[HttpGet]
[Queryable]
public IQueryable<CustomerCard> GetAllPasses(string version) {
     return context.Passes.Include("User").OfType<CustomerCard>();
}

这给了我正确的项目。我的数据库中有 2 张客户卡。两者都来自同一用户。我的 API 仍然加载了用户。当我的网站收到响应时,User 属性就变为 null。我的猜测是,这是因为它仍然从数组的第一个元素引用同一用户。那可能吗?如果是,我怎样才能防止这种情况发生?

最佳答案

是的,您需要确保在进行查询时包含所有相关记录。请参阅this举一些例子。其次...我不明白为什么你要使用 for 循环做所有这些工作...如果你想做任何分页,这对服务器来说是很多绝对不必要和浪费的工作。我想,除了您可能想要应用的任何其他过滤器之外,您的 GetAllPasses 应该如下所示。

public IQueryable<CustomerCard> GetAllPasses() {
    return context.Passes.Include(r => r.User);
}

编辑(2):我需要更好地阅读。我必须承认,我对 EF 中的类型继承并不熟悉。我发现一些可能在这里工作的东西:table per hierarchy , table per concrete type ,另请参阅 MSDN Queryable.OfType<TResult> 。这是一个猜测,但让我们尝试一下:

public IQueryable<CustomerCard> GetAllPasses() {
    return context.Passes.OfType<CustomerCard>().Include(r => r.User);
}

关于asp.net-mvc - 当 Web API 返回 IQueryable 时 EF 引用丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15904302/

相关文章:

c# - 成员表达式无法从可为空的十进制转换为对象

asp.net-mvc - ASP.NET MVC 4 "DictionaryValueProvider<T>.ContainsPrefix()"方法错误

c# - 为什么此代码会抛出 InvalidOperationException?

c# - EF 代码第一个一对多

javascript - 使用 Web API 从数据库中检索图像,然后在 angularJS 中显示它

c# - 为什么在 MVC 应用程序中使用 IoC?

c# - 首先在 Entity Framework 代码中定义外键

c# - 未使用OWIN承载 token 对用户登录进行身份验证

javascript - 将 URL 作为字符串传递—— '&' 之后的所有内容都会丢失

.net - OData 和 Entity Framework 向所有查询添加额外的 where 子句