Asp.net mvc 3 具有EF代码的WebApi在具有父子关系时首先生成错误
我在这个问题上伤了脑筋。我确实在网上找到了一些关于它的信息,但没有一个明确的答案。我的问题是: 我必须在MVC3 web应用程序的模型部分学习以下课程: 父级和子级 在ParentClass上有一个类型为List的属性Children 我首先使用EF代码,它在数据库中为我整洁地生成一个父表和一个子表 现在我需要一个REST服务,它返回一个列表或一个父类 当我从父类中删除属性Children时,没有问题。但在那里的孩子们中,我总是犯错误 错误:Asp.net mvc 3 具有EF代码的WebApi在具有父子关系时首先生成错误,asp.net-mvc-3,entity-framework,rest,ef-code-first,wcf-web-api,Asp.net Mvc 3,Entity Framework,Rest,Ef Code First,Wcf Web Api,我在这个问题上伤了脑筋。我确实在网上找到了一些关于它的信息,但没有一个明确的答案。我的问题是: 我必须在MVC3 web应用程序的模型部分学习以下课程: 父级和子级 在ParentClass上有一个类型为List的属性Children 我首先使用EF代码,它在数据库中为我整洁地生成一个父表和一个子表 现在我需要一个REST服务,它返回一个列表或一个父类 当我从父类中删除属性Children时,没有问题。但在那里的孩子们中,我总是犯错误 错误:“类型System.Data.Entity.Dynam
“类型System.Data.Entity.DynamicProxies.ParentClass_A0EBE0D1022D01EB84B81873D49DEEC60879FC4152BB115C3EC16FB8003A不是预期的。请使用XmlInclude或SoapInclude属性指定静态未知的类型。”}
一些代码:
课程:
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; }
}
公共类父类
{
公共int ID{get;set;}
公共字符串名称{get;set;}
公共虚拟列表子项{get;set;}
}
公营儿童班
{
公共int ID{get;set;}
公共字符串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;
}
[服务合同]
[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
公共类MyService
{
静态MyContext数据库;
public MyService(){db=new MyContext();}
[WebGet(UriTemplate=”“)]
公共列表GetParents()
{
var result=db.Parents.ToList();
返回结果;
}
调用此服务时,我不会得到结果。我做错了什么?似乎正在序列化POCO的代理类,我的第一个建议是使用proxydatacontractresolver: 此外,我还将致力于在加载通过web服务发送的数据时将事情明确地表达出来 将父类更改为
public class ParentClass
{
public int ID { get; set; }
public string Name {get;set;}
public List<ChildrenClass> Children { get; set; }
}
公共类父类
{
公共int ID{get;set;}
公共字符串名称{get;set;}
公共列表子项{get;set;}
}
更改内容以关闭延迟加载:
并明确指定在返回通过导线发送的数据时要加载的内容
[WebGet(UriTemplate = "")]
public List<ParentClass> GetParents()
{
var result = db.Parents.Include("Children").ToList();
return result;
}
[WebGet(UriTemplate=”“)]
公共列表GetParents()
{
var result=db.Parents.Include(“Children”).ToList();
返回结果;
}
看看下面的答案:对于更高级的Include调用
另外一条经验建议是,我不会通过网络返回数据类,因为它们为web服务的消费者形成了一个契约。您最好拥有另一组将数据值映射到其中的类
这样,如果您的数据类发生更改,除非明确要求,否则不必更改web服务客户机
如果您希望父类或子类中有1000行,则使用分页非常重要,否则最终将使用N+1 select,请参见:。我必须在上下文配置中禁用ProxyCreation:
[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;
}
}
[运营合同]
[WebGet(UriTemplate=”“)]
公共列表GetParents()
{
使用(DBContext context=new DBContext())
{
context.Configuration.ProxyCreationEnabled=false;
List parents=context.parents
.包括(“儿童”)
.ToList();
返回父母;
}
}
这对我来说很好。在某些情况下,一个简单的解决方案是使用包装器类,以便公开的所有属性都是已知类型 通常,您不会在控制器类中使用ObjectContext或DbContext,所以在早期的层(业务层或服务层)中也是如此您可以将来自DB的对象快速转换为ViewModel样式的对象,这与您在MVC应用程序中所做的类似,但您不需要将它们传递到视图,而是将它们返回给调用者
也许你不能在所有情况下都使用它,但通常这是一个可行的折衷办法。我尝试过DataContractResolver,但没有用。disableproxycreation确实有用。但是如果我理解正确,我应该将POCO的填充从数据库中分离出来,并将其与服务中使用的类分开。但这不意味着每个对象都需要被复制,意味着在站点和业务逻辑中使用父类,在服务中使用单独的父类。这不是太多重复代码吗?我们使用DTO和Automapper将我们的资源模型从域模型中分离出来。这有很多优点,包括单独验证和单独/不同t structuresIt为N种不同的用途复制POCO通常是过分的,包括添加工作和维护maps/XLAT。许多开发人员采取的方法是仔细定义POCO一次,然后将其用于数据传输和数据访问,尤其是在较小的项目上。如果有一天这种情况不再发生r工作(模式更改、重构等)然后,应该定义新的POCO,并根据需要执行映射。这种转换/重构根本不会影响web客户端,它只会对类库的.NET使用者造成问题。例如,二进制依赖项。我同意复制POCO会适得其反。使用POCO背后的潜在意图是不同的你应该有一个不同的POCO。根据经验,我知道数据层的类不应该作为数据契约通过网络公开。一旦你改变了数据库层,就推断数据契约已经改变,所有消费客户端也应该改变。因此,重用数据POCO不允许你灵活地对数据进行版本化客户端的ata/服务接口。正是我想要的。你知道禁用此功能有什么缺点吗?代理、跟踪更新等都有很多好处。