Я новичок в структуре сущностей и люблю простоту, но у меня есть проблемы со скоростью. Я думаю, что я мог бы использовать ленивую загрузку неправильно, но с трудом обнимал ее вокруг себя. Я разделил слой модели данных и уровень бизнес-сущности и использовал функцию для создания бизнес-объекта из моей модели данных. В этой функции я перебираю различные вложенные объекты для создания соответствующих моделей. Хорошо, достаточно хаотичный здесь некоторый код:Запрос структуры Entity Framework слишком медленный
IM_ITEM.cs (модель данных продукта)
public partial class IM_ITEM
{
public IM_ITEM()
{
this.IM_INV = new HashSet<IM_INV>();
this.IM_BARCOD = new HashSet<IM_BARCOD>();
this.IM_GRID_DIM_1 = new HashSet<IM_GRID_DIM_1>();
this.IM_GRID_DIM_2 = new HashSet<IM_GRID_DIM_2>();
this.IM_GRID_DIM_3 = new HashSet<IM_GRID_DIM_3>();
this.IM_PRC = new HashSet<IM_PRC>();
}
public string ITEM_NO { get; set; }
public string DESCR { get; set; }
// many more properties...
public virtual ICollection<IM_INV> IM_INV { get; set; }
public virtual ICollection<IM_BARCOD> IM_BARCOD { get; set; }
public virtual ICollection<IM_GRID_DIM_1> IM_GRID_DIM_1 { get; set; }
public virtual ICollection<IM_GRID_DIM_2> IM_GRID_DIM_2 { get; set; }
public virtual ICollection<IM_GRID_DIM_3> IM_GRID_DIM_3 { get; set; }
public virtual ICollection<IM_PRC> IM_PRC { get; set; }
}
метод создания бизнес-объект:
public static ProductEntity FromEfObject(IM_ITEM obj) {
var product = new ProductEntity {
ItemNumber = obj.ITEM_NO,
StyleNumber = obj.VEND_ITEM_NO,
Title = obj.DESCR_UPR,
LongName = obj.ADDL_DESCR_1,
ShortDescription = obj.DESCR,
VendorCode = obj.ITEM_VEND_NO,
Quarter = obj.ATTR_COD_2,
Color = obj.PROF_ALPHA_2,
Markdown = obj.PRC_1,
Price = obj.REG_PRC ?? 0,
Status = obj.STAT,
DepartmentCode = obj.ATTR_COD_1,
DepartmentDigit = obj.ATTR_COD_1.Substring(0, 1),
MixAndMatch = obj.MIX_MATCH_COD,
Inventory = new Inventory(obj.IM_INV),
Sizes = new List<ProductSize>(),
Widths = new List<ProductSize>(),
Lengths = new List<ProductSize>(),
Barcodes = new Dictionary<string, string>()
};
if (obj.IM_PRC.Any()) {
var price = obj.IM_PRC.First();
product.DnsPrice2 = price.PRC_2.GetValueOrDefault();
product.DnsPrice3 = price.PRC_3.GetValueOrDefault();
}
foreach (var barcode in obj.IM_BARCOD) {
product.Barcodes.Add(barcode.DIM_1_UPR, barcode.BARCOD);
}
foreach (var size in obj.IM_GRID_DIM_1) {
product.Sizes.Add(ProductSize.FromEfObject(size));
}
foreach (var width in obj.IM_GRID_DIM_2) {
product.Widths.Add(ProductSize.FromEfObject(width));
}
foreach (var length in obj.IM_GRID_DIM_3) {
product.Lengths.Add(ProductSize.FromEfObject(length));
}
if (!product.Sizes.Any()) {
product.Sizes.Add(new ProductSize());
}
if (!product.Widths.Any()) {
product.Widths.Add(new ProductSize());
}
if (!product.Lengths.Any()) {
product.Lengths.Add(new ProductSize());
}
return product;
}
И мой метод, чтобы получить модель:
public ProductEntity GetProductById(string itemNumber, int storeNumber) {
var product = _unitOfWork
.GetProductRepository(storeNumber)
.GetQueryable()
.FirstOrDefault(p => p.ITEM_NO == itemNumber);
return product == null ? null : ProductEntity.FromEfObject(product);
}
И метод GetQueryable:
internal DbSet<TEntity> DbSet;
public GenericRepository(TContext context)
{
Context = context;
DbSet = context.Set<TEntity>();
}
public virtual IQueryable<TEntity> GetQueryable()
{
IQueryable<TEntity> query = DbSet;
return query;
}
Немного больше информации .. Я использовал первое моделирование базы данных для создания моей модели данных, а база данных, на которую я тестирую, не содержит тонны данных. Кроме того, я попытался использовать .Include()
в моем методе GetProductById
для загрузки (с нетерпением я верю), но замедлил его еще дальше.
Я делаю что-то принципиально неправильно? Или используется EF, чтобы быть медленным для такого запроса.
EDIT: Для того, чтобы предотвратить отложенную загрузку Я обновил свой запрос:
public ProductEntity GetProductById(string itemNumber, int storeNumber) {
var product = _unitOfWork
.GetProductRepository(storeNumber)
.GetQueryable()
.Include(p => p.IM_INV.Select(i => i.IM_INV_CELL))
.Include(p => p.IM_BARCOD)
.Include(p => p.IM_GRID_DIM_1)
.Include(p => p.IM_GRID_DIM_2)
.Include(p => p.IM_GRID_DIM_3)
.Include(p => p.IM_PRC)
.FirstOrDefault(p => p.ITEM_NO == itemNumber);
return product == null ? null : ProductEntity.FromEfObject(product);
}
При трассировке, это дает мне только один большой неприятный запрос, который занимает больше времени, чем при использовании отложенной загрузки http://pastebin.com/LT1vTETb
Какова ваша реализация '_unitOfWork.GetProductRepository (storeNumber) .GetQueryable()', потому что если эта часть не так, это может быть, что EF запрашивает всю таблицу продукта в памяти перед выполнением «FirstOrDefault» и тем самым замедлить ее. – SynerCoder
Обновлено с помощью этого кода .. спасибо! –
Является ли Sql Server вашим репозиторием на заднем конце? Если это так, используйте Sql Server Profiler, чтобы узнать, что на самом деле выполняется на сервере. Если имеется несколько операторов (например, предложенный @SynerCoder), то это может быть часть кода, который вы не показываете нам, который будет реализовывать всю таблицу перед выполнением FirstOrDefault. В любом случае используйте это, чтобы увидеть, что выполняется. Если это выглядит правильно, начните анализ (настройку) запроса, если он выглядит неправильно, начните копать через код. – Igor