【发布时间】:2018-09-03 13:49:20
【问题描述】:
我需要从 odata 控制器返回实体列表(提案),但它还需要返回另一个属性实体(摘要)以及从 Summarize 方法填充的实体。这个其他实体既不持久也不存在于 dbcontext 中(builder.Ignore(p => p.Summary))。
问题是它不能成为我使用的复杂类型,因此我尝试将其添加为构建器上的 EntitySet 和父级上的自动扩展(因为我无法将其添加到扩展查询中) ,但是每次我尝试查询它时,都会引发以下异常。
System.Runtime.Serialization.SerializationException: Cannot serialize a null 'ResourceSet'.
at Microsoft.AspNet.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteObjectInline(Object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext) [...]
我想知道这是否是因为实体不存在于上下文中。
那么有没有办法让这个工作?不保留此其他实体,而是将其与其父级的 odata 查询一起返回?
结果:
{"@odata.context":"http://localhost:57450/OData/$metadata#Proposal","value":[{"ProposalID":"e91cacfc-f345-4617-bd54-b1f440e4fd65","CustomerNumber":null,"Description":"","ServiceType":"LeaseReturn","Currency":null,"PartnerName":null,"QuoteDate":"0001-01-01T00:00:00-02:00","CreatedOn":"2018-08-06T16:27:52.8169404-03:00","CreatedBy":"Admin","UpdatedOn":null,"UpdatedBy":null,"ProposalServiceFees":[]},{"ProposalID":"28ddfea6-2ac9-4898-b72f-d5e284d5072f","CustomerNumber":"2","Description":"a","ServiceType":"ResaleAndRecycle","Currency":null,"PartnerName":null,"QuoteDate":"0001-01-01T00:00:00-02:00","CreatedOn":"2018-08-15T15:11:07.531755-03:00","CreatedBy":"Admin","UpdatedOn":null,"UpdatedBy":null,"ProposalServiceFees":[]}]}
预期:
{"@odata.context":"http://localhost:57450/OData/$metadata#Proposal","value":[{"ProposalID":"e91cacfc-f345-4617-bd54-b1f440e4fd65","CustomerNumber":null,"Description":"","ServiceType":"LeaseReturn","Currency":null,"PartnerName":null,"QuoteDate":"0001-01-01T00:00:00-02:00","CreatedOn":"2018-08-06T16:27:52.8169404-03:00","CreatedBy":"Admin","UpdatedOn":null,"UpdatedBy":null,"Summary":{"SummaryId":"e91cacfc-f345-4617-bd54-b1f440e4fd65","Items":[{"Type":"workstation","Price":0.00}],"Fees":[]},"ProposalServiceFees":[]},{"ProposalID":"28ddfea6-2ac9-4898-b72f-d5e284d5072f","CustomerNumber":"2","Description":"a","ServiceType":"ResaleAndRecycle","Currency":null,"PartnerName":null,"QuoteDate":"0001-01-01T00:00:00-02:00","CreatedOn":"2018-08-15T15:11:07.531755-03:00","CreatedBy":"Admin","UpdatedOn":null,"UpdatedBy":null,"Summary":{"SummaryId":"28ddfea6-2ac9-4898-b72f-d5e284d5072f","Items":[{"Type":"strings","Price":0.00}],"Fees":[]},"ProposalServiceFees":[]}]}
实体:
public class Proposal : EntityBase {
public Guid ProposalID { get; set; }
public string CustomerNumber { get; set; }
public string Description { get; set; }
public string ServiceType { get; set; }
public string Currency { get; set; }
public Summary Summary { get; set; }
public string PartnerName { get; set; }
public DateTime QuoteDate { get; set; }
[...]
public void Summarize()
=> Summary = new Summary(Assets, ProposalServiceFees.Select(f=>f.ServiceFee), ProposalID);
}
public class Summary
{
public Guid SummaryId { get; set; }
public IEnumerable<SummaryItem> Items { get; private set; }
public IEnumerable<SummaryItem> Fees { get; private set; }
internal Summary(IEnumerable<Asset> assets, IEnumerable<ServiceFee> fees, Guid id)
{
SummaryId = id; //dummy for test
Items = assets
.GroupBy(asset => asset.ProductType, GroupIntoSummaryItem)
.ToList();
Fees = fees
.Select(f=> FeeToSummaryItem(f.ApplyServiceFee(assets.Count())))
.ToList();
}
[...]
}
控制器:
[EnableQuery]
[ODataRoute()]
public IQueryable<Proposal.Domain.Entities.Proposal> Get(ODataQueryOptions opts)
{
opts.Validate(settings);
IQueryable results = opts.ApplyTo(_context.Proposal.Include(x => x.Assets)).AsQueryable();
var values = (results as IQueryable<Proposal.Domain.Entities.Proposal>)?.ToList();
values?.ForEach(x => x.Summarize());
return values?.AsQueryable();
}
OdataConventionModelBuilder:
EntitySet<Summary>(nameof(Summary))
.EntityType
.HasKey(p => p.SummaryId)
.Filter()
.Count()
.Expand()
.OrderBy()
.Page()
.Select();
EntitySet<Domain.Entities.Proposal>(nameof(Domain.Entities.Proposal))
.EntityType
.HasKey(p => p.ProposalID)
.Expand(SelectExpandType.Automatic, nameof(Summary))
.Filter()
.Count()
.Expand()
.OrderBy()
.Page()
.Select();
【问题讨论】: