使用EF6查询多对多的性能

时间:2018-03-22 18:06:28

标签: entity-framework entity-framework-6

我们使用与单个表格使用少量M:M关系的查询遇到性能问题。

表格

Schema

目前,EF生成一个MONSTROUS查询,该查询使用UNION ALL 3次到Contact表。 Pastebin of SQL每次加入一次。我们的预测是这样的

var contacts = query.Select(contact => new Contact
            {
                Brands = contact.Brands.Select(b => new Brand
                {
                    Id = b.Id,
                    Name = b.Name,
                    Aliases = b.Aliases.Select(a => a.Value).ToList()
                }).ToList(),
                Categories = contact.Categories.Select(category => new Category
                {
                    Id = category.Id
                }).ToList(),
                ContactTypes = contact.ContactTypes.Select(ct => new ContactType
                {
                    Id = ct.Id
                }).ToList(),
                Disabled = contact.Disabled,
                Email = contact.Email,
                Fax = contact.Fax,
                Id = contact.Id,
                Latitude = contact.Coordinates != null ? contact.Coordinates.Latitude : 0,
                Longitude = contact.Coordinates != null ? contact.Coordinates.Longitude : 0,
                Distance = searchLocation != null && contact.Coordinates != null ? searchLocation.Distance(contact.Coordinates) * conversionFactor : 0,
                PostalCode = contact.PostalCode,
                PhoneSupport = contact.PhoneSupport,
                PhoneSales = contact.PhoneSales,
                PhoneAfterHoursSupport = contact.PhoneAfterHoursSupport,
                Phone = contact.Phone,
                Preferred = contact.Preferred,
                ShopOnlineImageUrl = contact.ShopOnlineImageUrl,
                ContactTranslations = contact.NameContent.TranslatedContents.Where(tc => tc.IsoLanguageCode == searchModel.IsoLanguageCode ||
                                                                                         tc.IsoLanguageCode == SearchContactsHelpers.ISO_LANGUAGE_CODE_ENGLISH)
                                                                            .Select(tc => new ContactTranslationImpl
                                                                            {
                                                                                Name = tc.Value,
                                                                                IsoLanguageCode = tc.IsoLanguageCode,
                                                                                NameId = tc.MasterContentId
                                                                            }).ToList(),
                AdditionalInformationContentId = contact.AdditionalInformationContentId,
                AddressLine1ContentId = contact.AddressLine1ContentId,
                AddressLine2ContentId = contact.AddressLine2ContentId,
                CityContentId = contact.CityContentId,
                StateOrProvinceContentId = contact.StateOrProvinceContentId,
                CountryContentId = contact.Country.NameContentId,
                HoursOfOperationContentId = contact.HoursOfOperationContentId,
                WebsiteContentId = contact.WebsiteContentId,
                OnlineSellerHomePageUrlContentId = contact.OnlineSellerHomePageUrlContentId,
                ContactFormUrlContentId = contact.ContactFormUrlContentId,
                RequestAQuoteUrlContentId = contact.RequestAQuoteUrlContentId,
                NameContentId = contact.NameContentId
            });

从查询中删除M:M关系会产生一个合理的单一查询(尽管有许多子选择)。只要将单个M:M关系添加到投影中,EF就会为结果生成2个带UNION ALL的查询。

以下是我们的配置:

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
            modelBuilder.Entity<Contact>()
                .HasMany(c => c.Brands)
                .WithMany(c => c.Contacts)
                .Map(mc =>
                {
                    mc.MapRightKey("BrandId");
                    mc.MapLeftKey("ContactId");
                    mc.ToTable("ContactBrands");
                });
            modelBuilder.Entity<Contact>()
                .HasMany(c => c.Categories)
                .WithMany(c => c.Contacts)
                .Map(mc =>
                {
                    mc.MapRightKey("CategoryId");
                    mc.MapLeftKey("ContactId");
                    mc.ToTable("ContactCategories");
                });
            modelBuilder.Entity<Contact>()
                .HasMany(c => c.ContactTypes)
                .WithMany(c => c.Contacts)
                .Map(mc =>
                {
                    mc.MapRightKey("ContactTypeId");
                    mc.MapLeftKey("ContactId");
                    mc.ToTable("ContactToContactType");
                });
        }

我不确定为什么EF会产生如此可怕的查询。任何有关如何改进查询的见解都非常有用。

0 个答案:

没有答案