11

我在这个问题上打破了我的头。我在网上找到了关于它的东西,但没有一个明确的答案。我的问题:带EF代码优先的WebApi在生成父子关系时产生错误

我有类在MVC3 Web应用程序的模型部分: 父类和ChildClass 在父类有类型列表的属性Children

我使用EF代码首先,整齐地产生父表和我的数据库中的子表。

现在我需要一个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; 

    } 

callinh这项服务的时候我不会得到结果。我究竟做错了什么?

回答

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

这工作得很好了我。

+0

正是我在找的。你知道禁用这个的缺点吗? – hooked82

+1

代理有很多好处,记录更新等。忘记包含语句没有错误。我还没有序列化proxi实体的解决方案 –

0

它似乎是序列化你的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?

+1

我试过DataContractResolver,但没有帮助。 disableproxycreation确实有帮助。但是,如果我理解正确,我应该将从数据库填充的POCO从服务中使用的类中分离出来。但这并不意味着每个对象都需要被复制,这意味着在该站点中使用的ParentClass和业务逻辑以及用于该服务中的单独的ParentClass。那不是太多重复的代码? – Mounhim

+0

我们使用DTO和Automapper将我们的资源模型与我们的域模型分开。这有很多优点,包括单独的验证和单独的/不同的结构 – suing

+0

复制你的POCOs用于N种不同的用途往往是矫枉过正,包括叠加工作和维护maps/xlats。许多开发人员采取一次小心定义POCO的方法,然后将其用于数据传输和数据访问,特别是在较小的项目中。如果有一段时间这不再起作用(模式更改,重构等),那么应该定义新的POCO并根据需要执行映射。这种转换/重构根本不影响Web客户端,这对于类库的.NET使用者来说只是一个问题。例如。二进制依赖。 –

0

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

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

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