Tom*_* L. 0 sql sql-server entity-framework ef-code-first
我可能不是SQL专家,但在进行性能测试时,我看到EF6(Code-First)生成以下语句:
SELECT
[UnionAll3].[C2] AS [C1],
[UnionAll3].[C3] AS [C2],
[UnionAll3].[C4] AS [C3],
[UnionAll3].[C5] AS [C4],
[UnionAll3].[C6] AS [C5],
[UnionAll3].[C7] AS [C6],
[UnionAll3].[C8] AS [C7],
[UnionAll3].[C1] AS [C8],
[UnionAll3].[C9] AS [C9],
[UnionAll3].[C10] AS [C10],
[UnionAll3].[C11] AS [C11],
[UnionAll3].[C12] AS [C12],
[UnionAll3].[C13] AS [C13],
[UnionAll3].[C14] AS [C14],
[UnionAll3].[C15] AS [C15],
[UnionAll3].[C16] AS [C16],
[UnionAll3].[C17] AS [C17],
[UnionAll3].[C18] AS [C18],
[UnionAll3].[C19] AS [C19],
[UnionAll3].[C20] AS [C20],
[UnionAll3].[C21] AS [C21],
[UnionAll3].[C22] AS [C22],
[UnionAll3].[C23] AS [C23],
[UnionAll3].[C24] AS [C24],
[UnionAll3].[C25] AS [C25],
[UnionAll3].[C26] AS [C26],
[UnionAll3].[C27] AS [C27],
[UnionAll3].[C28] AS [C28],
[UnionAll3].[C29] AS [C29]
FROM (SELECT
[UnionAll2].[C1] AS [C1],
[UnionAll2].[C2] AS [C2],
[UnionAll2].[C3] AS [C3],
[UnionAll2].[C4] AS [C4],
[UnionAll2].[C5] AS [C5],
[UnionAll2].[C6] AS [C6],
[UnionAll2].[C7] AS [C7],
[UnionAll2].[C8] AS [C8],
[UnionAll2].[C9] AS [C9],
[UnionAll2].[C10] AS [C10],
[UnionAll2].[C11] AS [C11],
[UnionAll2].[C12] AS [C12],
[UnionAll2].[C13] AS [C13],
[UnionAll2].[C14] AS [C14],
[UnionAll2].[C15] AS [C15],
[UnionAll2].[C16] AS [C16],
[UnionAll2].[C17] AS [C17],
[UnionAll2].[C18] AS [C18],
[UnionAll2].[C19] AS [C19],
[UnionAll2].[C20] AS [C20],
[UnionAll2].[C21] AS [C21],
[UnionAll2].[C22] AS [C22],
[UnionAll2].[C23] AS [C23],
[UnionAll2].[C24] AS [C24],
[UnionAll2].[C25] AS [C25],
[UnionAll2].[C26] AS [C26],
[UnionAll2].[C27] AS [C27],
[UnionAll2].[C28] AS [C28],
[UnionAll2].[C29] AS [C29]
FROM (SELECT
[UnionAll1].[C1] AS [C1],
[UnionAll1].[Id] AS [C2],
[UnionAll1].[Id1] AS [C3],
[UnionAll1].[Ident] AS [C4],
[UnionAll1].[DescriptionLong] AS [C5],
[UnionAll1].[DescriptionShort1] AS [C6],
[UnionAll1].[DescriptionShort2] AS [C7],
[UnionAll1].[ArticleGroup] AS [C8],
[UnionAll1].[Id2] AS [C9],
[UnionAll1].[Id3] AS [C10],
[UnionAll1].[Barcode] AS [C11],
[UnionAll1].[Amount] AS [C12],
[UnionAll1].[StorageLocation] AS [C13],
[UnionAll1].[Article_Id] AS [C14],
[UnionAll1].[C2] AS [C15],
[UnionAll1].[C3] AS [C16],
[UnionAll1].[C4] AS [C17],
[UnionAll1].[C5] AS [C18],
[UnionAll1].[C6] AS [C19],
[UnionAll1].[C7] AS [C20],
[UnionAll1].[C8] AS [C21],
[UnionAll1].[C9] AS [C22],
[UnionAll1].[C10] AS [C23],
[UnionAll1].[C11] AS [C24],
[UnionAll1].[C12] AS [C25],
[UnionAll1].[C13] AS [C26],
[UnionAll1].[C14] AS [C27],
[UnionAll1].[C15] AS [C28],
[UnionAll1].[C16] AS [C29]
FROM (SELECT
CASE WHEN ([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1],
[Extent1].[Id] AS [Id],
[Extent1].[Id] AS [Id1],
[Extent1].[Ident] AS [Ident],
[Extent1].[DescriptionLong] AS [DescriptionLong],
[Extent1].[DescriptionShort1] AS [DescriptionShort1],
[Extent1].[DescriptionShort2] AS [DescriptionShort2],
[Extent1].[ArticleGroup] AS [ArticleGroup],
[Extent2].[Id] AS [Id2],
[Extent2].[Id] AS [Id3],
[Extent2].[Barcode] AS [Barcode],
[Extent2].[Amount] AS [Amount],
[Extent2].[StorageLocation] AS [StorageLocation],
[Extent2].[Article_Id] AS [Article_Id],
CAST(NULL AS int) AS [C2],
CAST(NULL AS int) AS [C3],
CAST(NULL AS int) AS [C4],
CAST(NULL AS decimal(18,2)) AS [C5],
CAST(NULL AS int) AS [C6],
CAST(NULL AS int) AS [C7],
CAST(NULL AS int) AS [C8],
CAST(NULL AS int) AS [C9],
CAST(NULL AS decimal(18,2)) AS [C10],
CAST(NULL AS datetime2) AS [C11],
CAST(NULL AS int) AS [C12],
CAST(NULL AS int) AS [C13],
CAST(NULL AS int) AS [C14],
CAST(NULL AS varchar(1)) AS [C15],
CAST(NULL AS int) AS [C16]
FROM [dbo].[Articles] AS [Extent1]
LEFT OUTER JOIN [dbo].[Batches] AS [Extent2] ON [Extent1].[Id] = [Extent2].[Article_Id]
UNION ALL
SELECT
2 AS [C1],
[Extent3].[Id] AS [Id],
[Extent3].[Id] AS [Id1],
[Extent3].[Ident] AS [Ident],
[Extent3].[DescriptionLong] AS [DescriptionLong],
[Extent3].[DescriptionShort1] AS [DescriptionShort1],
[Extent3].[DescriptionShort2] AS [DescriptionShort2],
[Extent3].[ArticleGroup] AS [ArticleGroup],
CAST(NULL AS int) AS [C2],
CAST(NULL AS int) AS [C3],
CAST(NULL AS varchar(1)) AS [C4],
CAST(NULL AS decimal(18,2)) AS [C5],
CAST(NULL AS int) AS [C6],
CAST(NULL AS int) AS [C7],
[Extent4].[Id] AS [Id2],
[Extent4].[Id] AS [Id3],
[Extent4].[Amount] AS [Amount],
[Extent4].[PricePerUncorrectedUnit] AS [PricePerUncorrectedUnit],
[Extent4].[Type] AS [Type],
[Extent4].[Article_Id] AS [Article_Id],
CAST(NULL AS int) AS [C8],
CAST(NULL AS int) AS [C9],
CAST(NULL AS decimal(18,2)) AS [C10],
CAST(NULL AS datetime2) AS [C11],
CAST(NULL AS int) AS [C12],
CAST(NULL AS int) AS [C13],
CAST(NULL AS int) AS [C14],
CAST(NULL AS varchar(1)) AS [C15],
CAST(NULL AS int) AS [C16]
FROM [dbo].[Articles] AS [Extent3]
INNER JOIN [dbo].[ScalePrices] AS [Extent4] ON [Extent3].[Id] = [Extent4].[Article_Id]) AS [UnionAll1]
UNION ALL
SELECT
3 AS [C1],
[Extent5].[Id] AS [Id],
[Extent5].[Id] AS [Id1],
[Extent5].[Ident] AS [Ident],
[Extent5].[DescriptionLong] AS [DescriptionLong],
[Extent5].[DescriptionShort1] AS [DescriptionShort1],
[Extent5].[DescriptionShort2] AS [DescriptionShort2],
[Extent5].[ArticleGroup] AS [ArticleGroup],
CAST(NULL AS int) AS [C2],
CAST(NULL AS int) AS [C3],
CAST(NULL AS varchar(1)) AS [C4],
CAST(NULL AS decimal(18,2)) AS [C5],
CAST(NULL AS int) AS [C6],
CAST(NULL AS int) AS [C7],
CAST(NULL AS int) AS [C8],
CAST(NULL AS int) AS [C9],
CAST(NULL AS int) AS [C10],
CAST(NULL AS decimal(18,2)) AS [C11],
CAST(NULL AS int) AS [C12],
CAST(NULL AS int) AS [C13],
[Extent6].[Id] AS [Id2],
[Extent6].[Id] AS [Id3],
[Extent6].[Amount] AS [Amount],
[Extent6].[Date] AS [Date],
[Extent6].[Article_Id] AS [Article_Id],
CAST(NULL AS int) AS [C14],
CAST(NULL AS int) AS [C15],
CAST(NULL AS varchar(1)) AS [C16],
CAST(NULL AS int) AS [C17]
FROM [dbo].[Articles] AS [Extent5]
INNER JOIN [dbo].[Demands] AS [Extent6] ON [Extent5].[Id] = [Extent6].[Article_Id]) AS [UnionAll2]
UNION ALL
SELECT
4 AS [C1],
[Extent7].[Id] AS [Id],
[Extent7].[Id] AS [Id1],
[Extent7].[Ident] AS [Ident],
[Extent7].[DescriptionLong] AS [DescriptionLong],
[Extent7].[DescriptionShort1] AS [DescriptionShort1],
[Extent7].[DescriptionShort2] AS [DescriptionShort2],
[Extent7].[ArticleGroup] AS [ArticleGroup],
CAST(NULL AS int) AS [C2],
CAST(NULL AS int) AS [C3],
CAST(NULL AS varchar(1)) AS [C4],
CAST(NULL AS decimal(18,2)) AS [C5],
CAST(NULL AS int) AS [C6],
CAST(NULL AS int) AS [C7],
CAST(NULL AS int) AS [C8],
CAST(NULL AS int) AS [C9],
CAST(NULL AS int) AS [C10],
CAST(NULL AS decimal(18,2)) AS [C11],
CAST(NULL AS int) AS [C12],
CAST(NULL AS int) AS [C13],
CAST(NULL AS int) AS [C14],
CAST(NULL AS int) AS [C15],
CAST(NULL AS decimal(18,2)) AS [C16],
CAST(NULL AS datetime2) AS [C17],
CAST(NULL AS int) AS [C18],
[Extent8].[ProjectUsageId] AS [ProjectUsageId],
[Extent8].[ProjectUsageId] AS [ProjectUsageId1],
[Extent8].[ProjectUsageName] AS [ProjectUsageName],
[Extent8].[Article_Id] AS [Article_Id]
FROM [dbo].[Articles] AS [Extent7]
INNER JOIN [dbo].[ProjectUsages] AS [Extent8] ON [Extent7].[Id] = [Extent8].[Article_Id]) AS [UnionAll3]
ORDER BY [UnionAll3].[C3] ASC, [UnionAll3].[C1] ASC
Run Code Online (Sandbox Code Playgroud)
我不敢相信,当它只是从5个表中获取数据时(这可以很好地连接并且定义了主键+关系),这在任何方面都是有效的.以下是导致此SQL语句的语句:
IQueryable<Article> articles = context.Articles
.Include("Batches")
.Include("ScalePrices")
.Include("Demands")
.Include("ProjectUsages");
var actualQuery = context.Articles.Where(d => d.DescriptionLong.Contains(searchTermList[0]) || d.Ident.Contains(searchTermList[0]));
Run Code Online (Sandbox Code Playgroud)
表格定义如下(示例):
[Table("Articles")]
public class Article
{
[Key]
public int Id { get; set; }
[Display(Name = "Article", ResourceType = typeof(Resources))]
[StringLength(32), Required]
public string Ident { get; set; }
[Display(Name = "Description", ResourceType = typeof(Resources))]
[StringLength(4000)]
public string DescriptionLong { get; set; }
}
[Serializable]
[Table ("Batches")]
public class ArticleBatch
{
[Key]
public int Id { get; set; }
[StringLength(32)]
public string Barcode { get; set; }
public decimal Amount { get; set; }
public ArticleStorageLocation StorageLocation { get; set; }
public override string ToString()
{
return String.Format("{0} ({1}/{2})", Barcode, Amount, StorageLocation);
}
}
Run Code Online (Sandbox Code Playgroud)
DbContext看起来像这样:
public class ArticleDataDbContext : DbContext
{
public ArticleDataDbContext(string connectionString) : base(connectionString)
{
Database.SetInitializer(new CreateDatabaseIfNotExists<ArticleDataDbContext>());
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}
public DbSet<Article> Articles { get; set; }
public DbSet<ArticleBatch> Batches { get; set; }
public DbSet<ArticleDemand> Demands { get; set; }
public DbSet<ArticleScalePrice> ScalePrices { get; set; }
public DbSet<ProjectUsage> ProjectUsages { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Article>().HasMany(d => d.Batches).WithRequired();
modelBuilder.Entity<Article>().HasMany(d => d.Demands).WithRequired();
modelBuilder.Entity<Article>().HasMany(d => d.ScalePrices).WithRequired();
modelBuilder.Entity<Article>().HasMany(d => d.ProjectUsages).WithRequired();
}
}
Run Code Online (Sandbox Code Playgroud)
这是SQL Management Studio中的ER模型图:

您是否知道此声明是"正确"还是完全无稽之谈?我究竟做错了什么?
小智 7
实体框架创建了这样一个复杂的查询,因为简单查询返回了大量重复数据.假设每个子表包含特定文章的10条记录,并假设您在文章ID上左连接所有四个子表.您现在得到的结果集为10*10*10*10 = 10000行.实体框架的查询仅提供1 + 10 + 10 + 10 + 10 = 41行,但仍然为您提供所需的所有数据.
根据注释,如果查询确实导致性能问题,您可以将其拆分为多个单独的简单查询:
var articles = context.Articles.Where(d =>
d.DescriptionLong.Contains(searchTermList[0])
|| d.Ident.Contains(searchTermList[0])).ToList();
// Either loop, or find one specific article for which
// you want to load the details. I'll use a loop.
foreach (var article in articles) {
article.Batches.Load();
article.ScalePrices.Load();
article.Demands.Load();
article.ProjectUsages.Load();
}
Run Code Online (Sandbox Code Playgroud)
您甚至可以将其包装在可序列化/快照事务中以确保数据一致性.
| 归档时间: |
|
| 查看次数: |
412 次 |
| 最近记录: |