简体   繁体   English

EF&Web API 2多次往返数据库以填充对象模型

[英]EF & Web API 2 Multiple Round trips to the database to populate object model

It seems this problem would have been encountered before me but I'm not finding much help online probably because I don't really know what to search for. 看来这个问题早已摆在我面前,但我在网上找不到太多帮助,可能是因为我真的不知道要搜索什么。

My problem in short is that I have a db table. 简而言之,我的问题是我有一个数据库表。 That table has 5 keys to other tables. 该表有5个指向其他表的键。

I then have a model that represents this table in EF. 然后,我有了一个表示EF中此表的模型。 Of course this object that represents the db table has List<T> properties that are representations of foreign keys in the db. 当然,表示数据库表的该对象具有List<T>属性,这些属性表示数据库中的外键。 That doesn't seem to be the problem as much as the EF model that has this table representation but also List<T> properties to other models. 与具有该表表示形式的EF模型以及其他模型的List<T>属性一样,这似乎不是问题。

The problem I am experiencing is that a call to a stored procedure to populate the main modelforces additional calls to the db to populate the related List<T> models. 我遇到的问题是对存储过程的调用以填充主模型会强制对数据库进行附加调用,以填充相关的List<T>模型。

I am looking to improve performance namely by eliminating the multiple calls. 我希望通过消除多个呼叫来提高性能。

My only thought to this point is to modify the stored procedure to return multiple recordsets and match each List<T> property to its corresponding recordset. 到目前为止,我唯一的想法是修改存储过程以返回多个记录集,并将每个List<T>属性与其对应的记录集进行匹配。

My sterilized structure is something like this. 我的消毒结构是这样的。

DB: D B:

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

The other custom types like OrderHeaderStatusReasonCode are pretty similar in design so I'm leaving out for brevity. 其他自定义类型(如OrderHeaderStatusReasonCode在设计上非常相似,因此为简洁起见,我OrderHeaderStatusReasonCode

C# Web API C#Web API

public async Task<IHttpActionResult>GetOrdersHistory([FromUri]GetOrderRequestParameters orderParams)
{
    ....removed for brevity....

    var query = await TheOrderRepository.GetOrderHistory(getOrder);

}

Order Repository: 订单资料库:

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

Again most of these awaits are similar so I'm just going to give an example of one... 同样,这些等待中的大多数类似,所以我仅举一个例子。

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

EDIT : 编辑

The crux is this. 关键是这个。 OrderHeader has properties with a custom type and basically those custom types have a List<T> that has to be populated. OrderHeader具有带有自定义类型的属性,基本上,这些自定义类型具有必须填充的List<T> My current design is such that I repeatedly hit the db to populate those custom types List properties. 我当前的设计是反复打数据库以填充那些自定义类型List属性。

Is there a way to make one trip to the db to get all my information. 有没有一种方法可以访问数据库以获取所有信息。 As mentioned earlier the only way I can think of is to modify the stored procedure to return multiple record sets and then match them up. 如前所述,我唯一想到的方法是修改存储过程以返回多个记录集,然后将它们匹配。

BTW the architecture may be the flaw...in which case educate me on how to properly populate a complex object like this. 顺便说一句,架构可能是一个缺陷……在这种情况下,我应该了解如何正确填充这样的复杂对象。

TIA TIA

The root problem is that stored procedures aren't composable. 根本问题是存储过程不可组合。 In SQL you can't join a stored procedure call with anything (a database table or another stored procedure). 在SQL中,您不能将存储过程调用与任何内容(数据库表或另一个存储过程)连接在一起。 So EF can't do that either. 因此,EF也无法做到这一点。

If you want to get data with loaded collections from the database, normally you'd have to use Include s. 如果要从数据库中获取具有加载的集合的数据,通常必须使用Include EF will translate that into the appropriate join s and figure out how to load the entities and their collections from one big result set. EF会将其转换为适当的join并找出如何从一个大结果集中加载实体及其集合。 But, as said, joins are no option here. 但是,正如前面所说,在这里联接是没有选择的。

There is a way to load multiple result sets from one stored procedure . 有一种方法可以从一个存储过程中加载多个结果集 IMO it's pretty messy and very procedural. 海事组织这是非常混乱和非常程序。 I would keep loading the data separately as you do now, if you want to keep using stored procedures. 如果要继续使用存储过程,我将像现在一样继续分别加载数据。 Others may suggest that you could load the additional data by lazy loading. 其他人可能建议您可以通过延迟加载来加载其他数据。 Unfortunately that's not as straightforward as it should be with SqlQuery . 不幸的是,这并不像使用SqlQuery 那样简单

Another option of course is to start using regular DbSet s (with Include s), but I can't judge if that's possible for you. 当然,另一个选择是开始使用常规的DbSet (与Include一起使用),但是我无法判断这是否对您可行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 实体框架 - 减少到数据库的往返行程 - Entity framework - Reducing round trips to the database 操纵实体框架以消除到数据库的往返 - Manipulating entity framework to eliminate round trips to the database 可以在一个控制器动作中进行多次数据库往返 - Is it OK to do many database round trips in one controller action 实体框架 - 为什么这个Linq查询会产生多次往返? - Entity Framework - Why does this Linq query generate multiple round trips? EF模型中的多个数据库架构优先 - Multiple database schemas in EF model first 如果使用存储的proc填充模型,如何在EF中填充参考对象? - How do I populate the reference object in EF if I populate the model using a stored proc? 如何首先在EF数据库中将DbEntities对象分配给我的模型对象 - how to assign DbEntities object to my model object in EF Database first 如何在单个语句中加载两个导航属性,以避免数据库往返(如果有) - How to load two navigation property in a single statement in order to avoid database round trips(if any) 使用JSON.Net(如果序列化Entity Framework对象),禁用数据库的访问 - With JSON.Net if serializing Entity Framework object, disable trips to the database EF 6自动生成的数据库模型不适用于Web API 2 - EF 6 auto-generated db Model not working with Web API 2
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM