具有EF Code First的Web Api在具有父子关系时会生成错误

时间:2011-11-17 20:04:51

标签: asp.net-mvc-3 entity-framework rest ef-code-first wcf-web-api

我对这个问题感到不满。我确实在互联网上找到了一些关于它的内容,但不是一个明确的答案。我的问题:

我必须在MVC3 Web应用程序的Model部分中编写类: ParentClass和ChildClass 在ParentClass上有一个属性类型为List

的子属性

我使用了EF Code First,它在数据库中为我整齐地生成了父表和子表。

现在我需要一个REST服务,它返回一个List或一个ParentClass。

当我从ParentClass中删除属性Children时没有问题。但随着孩子们在那里,我不断收到错误。

错误:"The type System.Data.Entity.DynamicProxies.ParentClass_A0EBE0D1022D01EB84B81873D49DEECC60879FC4152BB115215C3EC16FB8003A was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."}

一些代码:

类:

     public class ParentClass
{
    public int ID { get; set; }
    public string Name {get;set;}
    public virtual List<ChildrenClass> Children { get; set; }

}

public class ChildrenClass
{
    public int ID { get; set; }
    public string MyProperty { get; set; }
}

服务:

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)] 
public class MyService
{

    static MyContext db;
    public MyService() { db = new MyContext(); }


    [WebGet(UriTemplate = "")]
    public List<ParentClass> GetParents()
    {
        var result = db.Parents.ToList();
        return result;

    }

当我打电话给这项服务时,我不会得到结果。我做错了什么?

3 个答案:

答案 0 :(得分:12)

我不得不在上下文配置中使用DisableProxyCreation:

[OperationContract] 
[WebGet(UriTemplate = "")] 
public List<ParentClass> GetParents() 
{ 
     using (DBContext context = new DBContext()) 
     {
         context.Configuration.ProxyCreationEnabled = false; 
         List<ParentClass> parents = context.Parents
             .Include("Children") 
             .ToList();
         return parents; 
      }
}

这对我来说很好。

答案 1 :(得分:0)

它似乎是为您的POCO序列化代理类,我的第一个建议是使用proxydatacontractresolver:http://msdn.microsoft.com/en-us/library/system.data.objects.proxydatacontractresolver.aspx

此外,我还会在加载通过网络服务发送的数据时明确说明事情......即

将父类更改为

public class ParentClass
{
    public int ID { get; set; }
    public string Name {get;set;}
    public List<ChildrenClass> Children { get; set; }

}

更改您的内容以关闭延迟加载: Disable lazy loading by default in Entity Framework 4

并在返回通过网络发送的数据时明确指定要加载的内容。

[WebGet(UriTemplate = "")]
public List<ParentClass> GetParents()
{
    var result = db.Parents.Include("Children").ToList();
    return result;

}

请查看以下答案:Entity Framework Code First - Eager Loading not working as expected?以获取更高级的包含电话。

另外,根据经验提供的建议,我不会通过网络返回您的数据类,因为它们构成了Web服务的使用者的合同。您最好使用另一组类来将数据值映射到。

这样,如果数据类发生更改,除非明确要求,否则不必更改Web服务客户端。

如果您希望在Parent或Child类中有1000行,则使用分页很重要,否则您最终会选择N + 1,请参阅:What is SELECT N+1?

答案 2 :(得分:0)

在某些情况下,一个简单的解决方案是使用包装类,以便公开的所有属性都是已知类型。

通常,您不会在控制器类中使用ObjectContext或DbContext,因此在早期层(业务层或服务层)中,您可以从来自DB的对象快速转换为ViewModel样式对象,类似你在MVC应用程序中做了什么,但不是将它们传递给View,而是将它们返回给调用者。

也许你不能在所有情况下使用它,但通常这是一个可行的妥协。