I'm using C#, .NET Core and the entity framework and am currently working on optimizing various functions for better performance.
One of the main functions is getting a calculation based on two indexes; a product and machine. The records in this database table is currently at 500 rows but can go upwards to 10.000.
My code for finding a record in this table is as follows:
public Calculation GetCalculationByProduct(Machine currentMachine, Product currentProduct)
{
IList<Calculation> calculations = _calculationRepository.Index().ToList();
for (int i = 0; i < calculations.Count(); i++)
{
if (calculations[i].MachineForeignKey == currentMachine.ID && calculations[i].ProductRef.ID == currentProduct.ID)
{
return calculations[i];
}
}
return null;
}
The function searches for the relative calculation based on both the product and the machine; since a machine and a product can both have multiple calculations.
The actual model looks like this:
public class Calculation
{
public int ID { get; set; }
public int MachineForeignKey { get; set; }
public Machine MachineRef { get; set; }
public Product ProductRef {get; set; }
public double Value { get; set; }
}
A product model and Machine model both use this like so:
public class Product
{
[Key]
public int ID { get; set; }
[Required]
public string ProductName { get; set; }
public string Name { get; set; }
public IEnumerable<Calculation> Calculations { get; set; }
}
public class Machine
{
[Key]
public int ID { get; set; }
public string OrderNo { get; set; }
public IEnumerable<Calculation> Calculations { get; set; }
}
The repository used is a basic linq implementation using generics like so:
public IEnumerable<TEntity> Index()
{
return _context.Set<TEntity>();
}
And the relations for the calculation / model have been set with a modelbuilder like this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Machine>()
.HasMany(m => m.Calculations)
.WithOne(s => s.MachineRef)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Product>()
.HasMany(m => m.CalculatedValues)
.WithOne(s => s.ProductRef)
.OnDelete(DeleteBehavior.Cascade);
}
I first used LINQ like so:
_calculationRepository.Index().Where(c => c.MachineForeignKey == Current_Machine.ID && c.ProductRef.ID == Current_Product.ID).FirstOrDefault();
But that caused quite bad performance; where it was around 2000ms
Currently, it goes through 500 records in about 900ms. Using visual studio's diagnostic tools I could see that this function was slowing everything down quite a lot; especially since the function is used for nearly every calculation done.
I'm looking to optimize the code, but any other advice is welcome.
IEnumerable<TEntity> Index()
toIQueryable<TEntity> Index()
. As a result, the linq query withFirstOrDefault
should work with lightning speed. \$\endgroup\$