2013-03-02 85 views
1

我有一个应用程序利用实体框架5数据库优先,VB.net,Linq,SQL Server 2008 R2和断开存储库模式。从断开的EF5实现“友好”实体上下文

我已经使用了EF5.x的dbContext生成器来创建我的POCO并修改了T4模板来添加各种额外的位和bobs,包括我的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 | 

为了在我的DataGrid中显示的 “友谊赛资料”,我拉中的数据,并创建“友好实体“使用代码,如;

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) 

GetProductComponentsByPrimaryName调用它简单地过滤按类型的组件,并返回一个友好的ObservableCollection的功能。

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

对不起,很长的文章!

编辑 - 13年8月3日:

我还没有解决这个问题上面,但我已成功地说服客户,他们不应该被检索所有结果,然后依靠用户以后过滤。

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

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

其中一天,也许我会重温这个问题,看看我能学到什么。但现在,我已经回避了它!

回答

1

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

+1

@Trey ...非常感谢您的回复...我已经更新了我的OP,以提供更多细节....我不确定SP可以在这里工作...如果可以的话,我很想知道方法论! – PGallagher 2013-03-02 02:37:27

+2

包括会杀了你。有一些是可以的,但是这么多只会杀死结果sql的性能。根据我的Twitter评论,我同意Trey。如果可能的话,你绝对应该考虑一个sproc。但问题是,谓词是动态的还是你总是在相同的字段上过滤? – 2013-03-02 03:28:47

+0

啊,刚刚在我身上发现这必须是一个桌面应用程序而不是网络。想知道为什么是VB。大声笑。 – 2013-03-02 03:39:38

1

该查询将导致大量的数据通过电线。您应该首先投射到只包含您需要的数据的实体。虽然取决于您的数据需求,但这可能对此无济于事。

SQL在运行简单查询时通常很快速,因此您可以尝试单独加载每个集合,然后使用Stich将实体放在代码中。这将大大减少传输的数据量。

要解释为什么参加这样的会在这里杀了你的表现是一个简单的例子:

在我的测试数据库中,我有很少的数据三张表,但你还是应该看到的格局。

首先各个查询

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行的字段;

  • 标题;
  • 简介;
  • 身体;
  • PublishDate;
  • 创建;
  • CreatorIP;
  • 创作者;
  • 已编辑;
  • 编辑;
  • EditorIP

在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行与列:

  • 标识;
  • 名称;
  • JoinCode;
  • IsCompetitionClub;
  • SourceSystemKey_SystemKey;
  • SourceSystemKey_EntityId;
  • SourceSystemKey_HasValue;
  • UserId;
  • GroupId;
  • IsAdministrator
  • ID;
  • 标题;
  • 简介;
  • 身体;
  • PublishDate;
  • 创建;
  • CreatorIP;
  • 创作者;
  • 已编辑;
  • 编辑;
  • EditorIP

响应现在长11954个字符,我们突然付出相当收费的联接。特别是如果数据库位于同一台机器上或者在一个非常快的网络上。

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

+0

非常感谢彻底的@Mikael!所以,我认为我最好在上面的查询中加入一个加入基本数据的Sproc。然后运行单个查询(可能是sproc的aswell),以获取连接的数据(如组件等),并手动填充我的连接集合? – PGallagher 2013-03-02 10:12:29

+0

根据我的经验,多次运行“平坦”查询的速度更快。这取决于客户端和数据库之间的连接有多快。你将不得不尝试一下。也许你甚至可以在需要时回收一些收藏品? – 2013-03-03 16:24:41

+0

嗨Mikael ...感谢您的评论。我为友好数据创建了一个SP,这很容易......但是我找不到一个好的方法来填充相关集合,比EF能够做得更快......事实上,速度更慢......我缺乏的SQL专业知识!任何想法如何去做? – PGallagher 2013-03-03 18:47:43