3

我一直在寻找这个问题很长一段时间。当Web API返回IQueryable时,EF引用会丢失

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

我有一个获取所有CustomerCards的方法。

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次。 对于我的第一个通行证,它工作正常。但是当我进入第二页时,他也得到了正确的通行证,但对用户的引用已经消失。

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

所以这个调用加载从通用户: 'API/V1 /通行证/所有$顶部= 1?' 但是当我打电话给这一个,用户实例是NULL:“API/V1 /通过/全部?$ top = 1 & $ skip = 1'。

但是,当我打电话给'api/v1/passes/all?$ top = 2'时,第二遍用户被加载。 所以这是我的头脑被炸毁的地方!我不明白吗?为什么没有用户引用与第二个一起?它可能与EF的延迟加载功能有关吗?

EDIT 当我使用扩展方法包括上context.passes,则会引发错误:

A中规定的包含路径是无效的。 EntityType'LCS_Model.Pass' 未声明名为'User'的导航属性。

这是因为通过作为dbset,包含CustomerCard以及凭证。有什么方法可以告诉我的上下文期望或将其转换为CustomerCard?

有人可以帮助我。如果你不明白我的问题,就问问吧!

谢谢!

EDIT 2

的方法我API控制器上现在

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

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

+0

您能否为Method“all”添加控制器代码? – 2013-04-09 14:17:42

+0

第二个代码块是控制器代码。路径'api/{version}/passes/all'路由到action =“GetAllPasses”。 – SandersD 2013-04-09 14:37:08

回答

2

是的,您需要确保在执行查询时包含任何相关记录。有关示例,请参阅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); 
} 
+1

这也是我最初的解决方案。问题是我的EF模型只创建了一个dbset。 Users属性仅适用于子类型CustomerCard(在我的db [dbo]。[Passes_CustomerCard]中生成的单独表格。因此,当我想在Include中使用您的建议方法时,出现错误,指出用户不是财产,这是我最大的问题,我可以告诉我的上下文,它需要从CustomerCard或什么? – SandersD 2013-04-09 15:41:02

+0

它看起来像你可以,让我知道如果这不起作用 – JayC 2013-04-09 16:17:12

+0

谢谢,我会尝试第一件事在早上!我会让你知道 – SandersD 2013-04-09 22:07:58

相关问题