1

我有一个应用程序使用 Entity Framework 5 Database First、VB.net、Linq、SQL Server 2008 R2 和断开连接的存储库模式。

我使用了 EF5.x dbContext 生成器来创建我的 POCO,并修改了 T4 模板以添加各种额外的内容,包括我的 INotifiyPropertyChanged 事件引发。

我有各种链接表,我需要以“友好”的方式显示数据。

例如,我有以下两个表;

颜色:

Colour_ID    |  Colour_Name    | Created_By | Creation_Date | Modified_By |  Modification_Date
----------------------------------------------------------------------------------------------
   1         |     Blue        |     1      |    22-01-13   |     1       |       23-01-13

用户:

User_ID  |  First_Name  | Last_Name  |
--------------------------------------
   1     |    Peter     | Gallagher  |

为了在我的 DataGrids 中显示“友好数据”,我正在提取数据,并使用以下代码创建“友好实体”;

Using CriticalPathDBContext As CriticalPathEntities = ConnectToDatabase()

        Dim query = (From Colour In CriticalPathDBContext.Colours _
                     .Include(Function(x) x.CreationUser) _
                     .Include(Function(x) x.LastUpdateUser).AsNoTracking.ToList
                     Select New FriendlyColours With {.CreatedBy = If(Colour.CreationUserCode Is Nothing, "", Colour.CreationUser.First_Name & " " & Colour.CreationUser.Last_Name),
                                                      .CreationDate = Colour.CreationDate,
                                                      .CreationUserCode = Colour.CreationUserCode,
                                                      .LastUpdateDate = Colour.LastUpdateDate,
                                                      .LastUpdatedBy = If(Colour.LastUpdateUserCode Is Nothing, "", Colour.LastUpdateUser.First_Name & " " & Colour.LastUpdateUser.Last_Name),
                                                      .LastUpdateUserCode = Colour.LastUpdateUserCode,
                                                      .Colour_ID = Colour.Colour_ID,
                                                      .Colour_Name = Colour.Colour_Name}).OrderBy(Function(x) x.Colour_Name)

        Return New ObservableCollection(Of FriendlyColours)(query)

End Using

我对上面的问题是,对于更复杂的连接实体,这种类型的查询需要太长时间。

我考虑过使用我的好友类来提取相关数据,但是在断开连接的模式下,这对我不起作用。

显然,在断开连接时,延迟加载不是一种选择......

所以,我的问题是......有没有更好的方法来做到这一点?为了更好...阅读更快!

任何帮助将不胜感激!也许我错过了一些明显的东西!

编辑...进一步解释:

  • 我有一个查询,它返回所有产品,以及它们的组件和产品库存项目......
  • 返回了 4 种不同类型的组件列表,以及产品库存项目列表。
  • 我获取每组组件和产品库存项目,并用结果填充关联的网格。
  • 用户能够从各种组件或产品库存项目中添加、编辑或删除项目。

查询是(对不起大小!);

Dim query = (From ProductList In _DBContext.Products _
             .Include(Function(x) x.CreationUser) _
             .Include(Function(x) x.LastUpdateUser) _
             .Include(Function(x) x.Colour) _
             .Include(Function(x) x.License) _
             .Include(Function(x) x.Pack_Size) _
             .Include(Function(x) x.Customer) _
             .Include(Function(x) x.Supplier) _
             .Include(Function(x) x.ProductComponents) _
             .Include(Function(x) x.ProductComponents.Select(Function(y) y.ApprovalType)) _
             .Include(Function(x) x.ProductComponents.Select(Function(y) y.Component)) _
             .Include(Function(x) x.ProductComponents.Select(Function(y) y.Component).Select(Function(z) z.ComponentType)) _
             .Include(Function(x) x.Product_Stock_Item) _
             .Include(Function(x) x.Product_Stock_Item.Select(Function(y) y.Pack_Type)) _
             .Include(Function(x) x.Product_Stock_Item.Select(Function(y) y.Product_Sizing)) _
             .Include(Function(x) x.Product_Stock_Item.Select(Function(y) y.Units_Of_Measure)) _
             .Include(Function(x) x.ProductType) _
             .Include(Function(x) x.ProductClassification) _
             .Include(Function(x) x.ProductType.ProductDepts) _
             .Include(Function(x) x.Season).AsNoTracking().OrderBy(Function(x) x.Product_Code).ToList
             Select New FriendlyProducts With {.Colour_ID = ProductList.Colour_ID,
                                               .Colour_Name = If(ProductList.Colour_ID Is Nothing, "", ProductList.Colour.Colour_Name),
                                               .CreatedBy = If(ProductList.CreationUserCode Is Nothing, "", ProductList.CreationUser.First_Name & " " & ProductList.CreationUser.Last_Name),
                                               .CreationDate = ProductList.CreationDate,
                                               .CreationUserCode = ProductList.CreationUserCode,
                                               .FriendlyCreationUser = ProductList.CreationUser,
                                               .Cust_Product_Desc_24 = ProductList.Cust_Product_Desc_24,
                                               .Cust_Product_Desc_48 = ProductList.Cust_Product_Desc_48,
                                               .Customer_Code = ProductList.Customer_Code,
                                               .Customer_Name = If(ProductList.Customer_Code Is Nothing, "", ProductList.Customer.NAME),
                                               .Description = ProductList.Description,
                                               .DesignNo = ProductList.DesignNo,
                                               .Gender_ID = ProductList.Gender_ID,
                                               .Gender_Name = If(ProductList.Gender_ID Is Nothing, "", ProductList.Gender.Gender_Name),
                                               .LicenseCode = ProductList.LicenseCode,
                                               .License_Name = If(ProductList.LicenseCode Is Nothing, "", ProductList.License.NAME),
                                               .Pack_Size_ID = ProductList.Pack_Size_ID,
                                               .Pack_Size_Name = If(ProductList.Pack_Size_ID Is Nothing, "", ProductList.Pack_Size.Pack_Size_Name),
                                               .PackagingNR = ProductList.PackagingNR,
                                               .ProductClassification_ID = ProductList.ProductClassification_ID,
                                               .Product_Classification_Name = If(ProductList.ProductClassification_ID Is Nothing, "", ProductList.ProductClassification.ProductClassification_Name),
                                               .Product_Code = ProductList.Product_Code,
                                               .Product_Picture_Path = ProductList.Product_Picture_Path,
                                               .ProductComponentsNR = ProductList.ProductComponentsNR,
                                               .ProductType_ID = ProductList.ProductType_ID,
                                               .ProductType_Name = If(ProductList.ProductType_ID Is Nothing, "", ProductList.ProductType.NAME),
                                               .ProductDept_ID = If(ProductList.ProductType Is Nothing, Nothing, ProductList.ProductType.ProductDept),
                                               .ProductDept_Name = If(ProductList.ProductType Is Nothing, "", (If(ProductList.ProductType.ProductDepts Is Nothing, "", ProductList.ProductType.ProductDepts.NAME))),
                                               .SageDescription = ProductList.SageDescription,
                                               .SeasonCode = ProductList.SeasonCode,
                                               .Season_Name = If(ProductList.SeasonCode Is Nothing, "", ProductList.Season.NAME),
                                               .StrikeOffNR = ProductList.StrikeOffNR,
                                               .Supplier_Code = ProductList.Supplier_Code,
                                               .Supplier_Name = If(ProductList.Supplier_Code Is Nothing, "", ProductList.Supplier.NAME),
                                               .TransfersNR = ProductList.TransfersNR,
                                               .Deleted = ProductList.Deleted,
                                               .LastUpdateDate = ProductList.LastUpdateDate,
                                               .LastUpdatedBy = If(ProductList.LastUpdateUserCode Is Nothing, "", ProductList.LastUpdateUser.First_Name & " " & ProductList.LastUpdateUser.Last_Name),
                                               .LastUpdateUserCode = ProductList.LastUpdateUserCode,
                                               .ProductComponents = If(ProductList.ProductComponents.Count > 0, GetProductComponentsByPrimaryName(ProductList.ProductComponents, "Component"), New ObservableCollection(Of FriendlyProductComponents)),
                                               .ProductPackaging = If(ProductList.ProductComponents.Count > 0, GetProductComponentsByPrimaryName(ProductList.ProductComponents, "Packaging"), New ObservableCollection(Of FriendlyProductComponents)),
                                               .ProductStrikeOffs = If(ProductList.ProductComponents.Count > 0, GetProductComponentsByPrimaryName(ProductList.ProductComponents, "Strike Off"), New ObservableCollection(Of FriendlyProductComponents)),
                                               .ProductTransfers = If(ProductList.ProductComponents.Count > 0, GetProductComponentsByPrimaryName(ProductList.ProductComponents, "Transfers"), New ObservableCollection(Of FriendlyProductComponents)),
                                               .ProductStockItems = If(ProductList.Product_Stock_Item.Count > 0, GetProductStockItems(ProductList.Product_Stock_Item), New ObservableCollection(Of FriendlyProductStockItems))
                                               }).Where(Function(x) x.Deleted = False Or x.Deleted Is Nothing)

WhereGetProductComponentsByPrimaryName调用了一个函数,该函数简单地按组件的类型过滤组件并返回一个友好的 ObservableCollection。

因此,每个相关的组件集和产品库存项目都作为 ObservableCollection 返回,我可以与之交互...

对不起,很长的帖子!

编辑 - 08-03-13:

我还没有解决上面的这个问题,但我设法说服客户他们不应该检索所有结果,然后依靠用户进行过滤。

这也导致我重新调整我的过滤例程,以便在数据库上而不是在本地执行过滤。这两个因素都意味着下面的查询现在以合理的速度运行。

我尝试手动填充我的实体,但这比 Linq 为我生成的查询花费的时间要长得多。

在这些日子里,也许我会重新审视这个问题,看看我能学到什么。但就目前而言,我已经避开了它!

4

2 回答 2

1

该查询将通过网络产生大量数据。您可能应该首先投影到仅包含您需要的数据的实体。也许这在这里无济于事,但取决于您的数据需求。

SQL 通常在运行简单查询方面速度极快,因此您可以尝试单独加载每个集合,然后在代码中将实体缝合在一起。这将大大减少传输的数据量。

为了解释为什么像这样加入会破坏你的表现,这里有一个简单的例子:

在我的测试数据库中,我有三个数据非常少的表,但您仍然应该看到这种模式。

首先是个人查询

SELECT *  FROM [OPath-dev].[dbo].[Groups] g

1;Hästhovarna;nzb5x50vibb;0;NULL;NULL;0

单排。根据记事本++ 39 个字符

SELECT * FROM [OPath-dev].[dbo].[GroupMemberships]

1;1;1
2;1;0

两排。12 个字符

SELECT * FROM [OPath-dev].[dbo].[Blogs] where id > 5

3行带字段;

  • 标题;
  • 介绍;
  • 身体;
  • 发布日期;
  • 创建;
  • 创作者IP;
  • 创造者;
  • 已编辑;
  • 编辑;
  • 编辑IP

5907 个字符

连接两个简单的表

  SELECT *
  FROM [OPath-dev].[dbo].[Groups] g
  JOIN [OPath-dev].[dbo].[GroupMemberships] gm on gm.GroupId = g.Id

1;Hästhovarna;nzb5x50vibb;0;NULL;NULL;0;1;1;1
1;Hästhovarna;nzb5x50vibb;0;NULL;NULL;0;2;1;0

现在长度为 96 个字符。如果在单独的查询中运行这两个,它将是 39 + 12 = 51(这可能更快,因为差异很小)。

加入所有三个表

SELECT *
  FROM [OPath-dev].[dbo].[Groups] g
  JOIN [OPath-dev].[dbo].[GroupMemberships] gm on gm.GroupId = g.Id
  JOIN [OPath-dev].[dbo].[Blogs] b on b.Id > 5

响应为 6 行,列:

  • ID;
  • 姓名;
  • 加入代码;
  • IsCompetitionClub;
  • 源系统密钥_系统密钥;
  • SourceSystemKey_EntityId;
  • SourceSystemKey_HasValue;
  • 用户身份;
  • 组别;
  • 是管理员
  • ID;
  • 标题;
  • 介绍;
  • 身体;
  • 发布日期;
  • 创建;
  • 创作者IP;
  • 创造者;
  • 已编辑;
  • 编辑;
  • 编辑IP

现在的响应是 11954 个字符长,我们突然为连接付出了相当大的代价。特别是如果数据库位于同一台机器上或位于非常快速的网络上。

现在这甚至是一个坏例子。我有更好的数据集,可以在我的另一台计算机上显示更糟糕的增长。请记住,您正在加入更多列,这些列最终将传输大量数据。如果它是一个 Windows 应用程序,并且您通过 WAN 连接到数据库,这将是一个严重的问题,但即使在本地计算机上,如果您进行配置,您也可以看到传输不是免费的。

于 2013-03-02T06:31:00.533 回答
1

创建一个执行相同查询的存储过程,并将结果作为新实体类型或 FriendlyColours(如果可以摆动)返回。你是对的,这样做是一头猪。不知道我还能添加什么。

于 2013-03-02T02:10:20.110 回答