似乎在我面前遇到了这个问题,但我没有在网上找到太多帮助,可能是因为我真的不知道要搜索什么。
我的问题很简单,就是我有一个数据库表。该表有5个键到其他表。
然后我有一个代表EF中这个表的模型。当然,表示db表的此对象具有List<T>
属性,这些属性是db中外键的表示形式。这似乎与具有此表格表示的EF模型以及其他模型的List<T>
属性一样多。
我遇到的问题是,调用存储过程来填充主模型会强制对db进行额外调用以填充相关的List<T>
模型。
我希望通过消除多次通话来提高性能。
我唯一想到的是修改存储过程以返回多个记录集,并将每个List<T>
属性与其对应的记录集匹配。
我的消毒结构是这样的。
DB:
sql_Id Int PK
sql_Status Int FK
sql_Reason Int FK
sql_GuestId Int
sql_Name varchar
sql_Created DateTime
sql_Original Int FK
EF:
public class OrderHeader : ClassBase
{
public OrderHeader()
{
TaskCodeAssignments = new List<OrderHeaderTaskCodeAssignment>();
StatusReasonCode = new OrderHeaderStatusReasonCode();
StatusCode = new OrderHeaderStatusCode();
Links = new OrderHeaderLinks();
}
public int OrderHeaderID { get; set; }
public short OrderHeaderStatusCodeID { get; set; }
public short? OrderHeaderStatusReasonCodeID { get; set; }
public short? OriginatingApplicationId { get; set; }
public string CustomerFirstName { get; set; }
public string CustomerLastName { get; set; }
public OrderHeaderStatusCode StatusCode { get; set; }
public OrderHeaderStatusReasonCode StatusReasonCode { get; set; }
public CustomerStatusCode CustomerStatusCode { get; set; }
public ICollection<OrderHeaderTaskCodeAssignment> TaskCodeAssignments { get; set; }
}
public class OrderHeaderStatusCode
{
public OrderHeaderStatusCode()
{
OrderHeaderStatusReasonCodes = new List<OrderHeaderStatusReasonCode>();
}
public ICollection<OrderHeaderStatusReasonCode> OrderHeaderStatusReasonCodes { get; set; }
public virtual ICollection<OrderHeader> OrderHeader { get; set; }
}
其他自定义类型如OrderHeaderStatusReasonCode
在设计上非常相似,所以我为了简洁而遗漏了。
C#Web API
public async Task<IHttpActionResult>GetOrdersHistory([FromUri]GetOrderRequestParameters orderParams)
{
....removed for brevity....
var query = await TheOrderRepository.GetOrderHistory(getOrder);
}
订单存储库:
public async Task<IQueryable<OrderHeader>> GetOrderHistory(GetOrderParameters orderParams)
{
// this is the call to stored procedure that I would modify to return multiple recordsets
var storedProcedure = StoredProcedure.Name.MyStoredProc.ToString();
var ordersHistory = await dbctx.Database.SqlQuery<OrderHeader>(...), storedProcParam).ToListAsync();
// now I jump off to fill in the other properties and their data has to come from the db
await GetOrdersData(ordersHistory, orderParams.Include);
}
private async Task GetOrdersData(List<OrderHeader> ordersHistory)
{
if (ordersHistory != null)
{
await LoadOrderStatusCodeForList(ordersHistory);
await LoadOrderStatusReasonCodeForList(ordersHistory);
await LoadCustomerStatusCodeForList(ordersHistory);
await LoadOrderHeaderTaskCodeAssignmentsForList(ordersHistory);
await LoadOrderHeaderTaskCodeForList(ordersHistory);
}
}
这些等待的大部分都是相似的,所以我只是举一个例子...
private async Task LoadOrderStatusCodeForList()
{
....snipped for brevity...
await LoadOrderStatusCode(order.OrderHeaderStatusCodeID));
}
private async Task<OrderHeaderStatusCode> LoadOrderStatusCode(short orderHeaderStatusCodeId)
{
....snipped brevity....
var storedProcedure = StoredProcedure.Name.MySprocStatusCode.ToString();
return await _dbctx.Database.SqlQuery<OrderHeaderStatusCode>(...), ...).FirstOrDefaultAsync();
}
修改:
关键是这个。 OrderHeader具有自定义类型的属性,基本上这些自定义类型必须填充List<T>
。我目前的设计是这样的,我反复点击数据库来填充那些自定义类型列表属性。
有没有办法让一次访问db来获取我的所有信息。如前所述,我能想到的唯一方法是修改存储过程以返回多个记录集,然后将它们匹配。
BTW架构可能是个缺陷......在这种情况下,请教我如何正确填充像这样的复杂对象。
TIA
答案 0 :(得分:2)
根本问题是存储过程不可组合。在SQL中,您无法使用任何内容(数据库表或其他存储过程)加入存储过程调用。因此,EF也无法做到这一点。
如果您想从数据库中获取已加载集合的数据,通常您必须使用Include
。 EF会将其转换为适当的join
,并找出如何从一个大结果集加载实体及其集合。但是,如上所述,联接在这里别无选择。
有一种方法可以加载multiple result sets from one stored procedure。 IMO它非常混乱,非常程序化。如果你想继续使用存储过程,我会像现在一样单独加载数据。其他人可能会建议您通过延迟加载来加载其他数据。不幸的是not as straightforward as it should be与SqlQuery
。
另一种选择当然是开始使用常规DbSet
s(Include
s),但我无法判断您是否可以使用。