【问题标题】:WebApi with EF Code First generates error when having parent child relation具有父子关系时,带有 EF Code First 的 WebApi 会生成错误
【发布时间】:2011-12-31 16:36:20
【问题描述】:

我对这个问题感到头疼。我确实在互联网上找到了一些关于它的东西,但没有一个明确的答案。我的问题:

我必须在 MVC3 网络应用的模型部分上课: 父类和子类 在 ParentClass 上有一个 List 类型的属性 Children

我使用了EF Code First,它在数据库中巧妙地为我生成了一个父表和一个子表。

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

当我从 ParentClass 中删除属性 Children 时,没有问题。但是对于那里的propoerty 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;

    }

调用此服务时我不会得到结果。我做错了什么?

【问题讨论】:

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


    【解决方案1】:

    我必须在上下文配置中禁用代理创建:

    [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; 
          }
    }
    

    这对我来说很好。

    【讨论】:

    • 正是我想要的。你知道禁用这个有什么缺点吗?
    • Proxies 有很多好东西,跟踪更新等等。忘记包含语句没有错误。我仍然没有序列化代理实体的解决方案
    【解决方案2】:

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

    另外,我会努力在加载数据以通过 Web 服务发送时明确说明内容......即

    将父类更改为

    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?

    【讨论】:

    • 我已经尝试过 DataContractResolver,但这没有帮助。 disableproxycreation 确实有帮助。但是,如果我理解正确,我应该将从数据库中填充的 POCO 与要在服务中使用的类分开。但这并不意味着每个对象都需要复制,这意味着在站点和业务逻辑中使用一个 ParentClass,在服务中使用一个单独的 ParentClass。是不是重复代码太多了?
    • 我们正在使用 DTO 和 Automapper 将我们的资源模型与域模型分开。这有很多优点,包括单独的验证和单独/不同的结构
    • 复制您的 POCO 用于 N 种不同用途通常是矫枉过正的,包括地图/xlats 的附加工作和维护。许多开发人员采取的方法是仔细定义他们的 POCO 一次,然后将它们用于数据传输和数据访问,尤其是在较小的项目中。如果有一段时间不再起作用(模式更改、重构等),则应定义新的 POCO 并根据需要执行映射。这种转变/重构根本不会影响 Web 客户端,对于类库的 .NET 使用者来说,这才是真正的问题。例如。二元依赖。
    • 我同意复制 POCO 会适得其反。如果使用 POCO 背后的潜在意图不同,您应该有不同的 POCO。根据经验,我知道数据层的类不应该作为数据契约通过网络公开。一旦您更改推断数据合同已更改的数据库层,并且所有消费客户端也应更改。因此,重用数据 POCO 不允许您灵活地为客户端版本化数据/服务接口。
    【解决方案3】:

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

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

    也许您不能在所有情况下都使用它,但通常这是一种可行的折衷方案。

    【讨论】:

      猜你喜欢
      • 2014-10-02
      • 2011-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多