6
Answers

what is more suitable looping or db calls

Photo of umair mohsin

umair mohsin

Oct 01
725
1

this is the extension of my previous question if for any reason i have to join multiple tables( 7 to 8) and if use linq in an mvc app like this:

 

 var data = (from a in context.GetModel()
                            join ad in aContext.GetModel() on a.CanId equals ad.CanId
                            join b in bContext.GetModel() on a.CanId equals b.CanId
                            join c in clContext.GetModel() on a.CanId equals b.CanId
                            join d in dContext.GetModel() on a.CanId equals d.CanId

                            where a.Id == id
                            select new
                            {

                                ac = ad,
                                ce = b,
                                skill = c,
                                exp = d

                            }).ToList() ;

 so it proves that its a huge query which has a bulky out put as each join table has multple rows related to a candidate

 

i have to loop through data variable to fetch data from anonymous variables(ce,skill exp,....). for this i have to run 4 loops.

is there any other way to get these values without looping 

OR

should i use db calls four times. what is more feasible or i must say best  industry practices?

Answers (6)

6
Photo of Anupam Maiti
184 10.7k 3.5m Oct 02
Below are the common best practices:
  • Avoid multiple DB calls if possible; prefer a single optimized query.
  • Use projections and grouping to reduce unnecessary data fetching and looping.
  • Consider using Include and ThenInclude to automatically load related entities without having to explicitly join them  (Look at the Example 1).
  • If the result set is too large, consider using pagination or filtering techniques to reduce the amount of data processed at once (Look at the Example 2).
  • Move the logic to stored procedures for heavy and complex queries if performance is an issue.

Example 1:

var candidate = context.Candidates
                       .Include(c => c.Ad)
                       .Include(c => c.B)
                       .Include(c => c.Skill)
                       .Include(c => c.Exp)
                       .FirstOrDefault(c => c.Id == id);

Example 2 :

var data = context.GetModel()
                  .Where(x => x.Id == id)
                  .Skip(pageSize * pageIndex)
                  .Take(pageSize)
                  .ToList();
3
Photo of Jignesh Kumar
30 39.7k 2.9m Oct 03

Hello Umair,

Please use Include to do eager loading and select only specific fields which you need

var data = context.GetModel()
    .Include(a => a.Ad) 
    .Include(a => a.B) 
    .Include(a => a.C) 
    .Include(a => a.D) 
    .Where(a => a.Id == id) // Apply where condition if you have any filter or you can remove
    .Select(a => new
    {
        ac = a.Ad.Select(ad => new { ad.SomeField1, ad.SomeField2 }), // Replace with actual properties and use fetch only specific fields you need
        ce = a.B.Select(b => new { b.SomeField1, b.SomeField2 }),
        skill = a.C.Select(c => new { c.SomeField1, c.SomeField2 }),
        exp = a.D.Select(d => new { d.SomeField1, d.SomeField2 })
    }).ToList();
3
Photo of Jayraj Chhaya
307 6k 100.2k Oct 03

In scenarios where you are joining multiple tables and retrieving a large dataset, as illustrated in your LINQ query, it is generally more efficient to minimize database calls. Instead of executing multiple database calls, which can lead to performance bottlenecks, consider leveraging the power of LINQ to project the necessary data in a single query.

If you find yourself needing to loop through the results to access specific properties, you can utilize LINQ's SelectMany or GroupBy methods to flatten the data structure, reducing the need for nested loops.

var result = data.SelectMany(x => new[] { x.ce, x.skill, x.exp }).ToList();

This approach allows you to access the required data without excessive looping. However, if the dataset is too large and performance is a concern, consider implementing pagination or filtering to limit the data returned from the database.

3
Photo of Tahir Ansari
255 7.6k 232.9k Oct 02

Hi Umair,

You can use Navigation property.

var data = context.Candidates
                 .Include(c => c.Applications)
                 .Include(c => c.Skills)
                 .Include(c => c.Experience)
                 .Where(c => c.Id == id)
                 .Select(c => new
                 {
                     Candidate = c,
                     Applications = c.Applications,
                     Skills = c.Skills,
                     Experience = c.Experience
                 })
                 .ToList();

Project into a DTO

public class CandidateDto
{
    public Candidate Candidate { get; set; }
    public IEnumerable<Application> Applications { get; set; }
    public IEnumerable<Skill> Skills { get; set; }
    public IEnumerable<Experience> Experience { get; set; }
}

// In your query
var data = context.Candidates
                 .Include(c => c.Applications)
                 .Include(c => c.Skills)
                 .Include(c => c.Experience)
                 .Where(c => c.Id == id)
                 .Select(c => new CandidateDto
                 {
                     Candidate = c,
                     Applications = c.Applications,
                     Skills = c.Skills,
                     Experience = c.Experience
                 })
                 .ToList();

The best approach depends on your specific use case, including how often you need the related data, the size of the data sets, and performance considerations. Using navigation properties and DTOs tends to be cleaner and often performs well.

2
Photo of umair mohsin
1.2k 405 76.6k Oct 03

i am really thankful to all of you for sucha qucik response to my question.one more pain i wnt to give that i am sending this data to a view and my view is not ienumrable type.i declare these fields as iCollection in my candidate model and this model passed to view  and i use this code:

 var data = (from x in db.Candidates.Include("Academics").
                          Include("Certifications").
                          Include("Skills").
                          Include("Experiences")
                        where x.Id == id
                        select new
                        {
                            a = x.Skills,
                            b = x.Academics,
                            c = x.Experience,
                            d = x.Certifications,
                            e = x
                        }).ToList().Select(c => new Candidate
                        {

                            Academics = c.b,
                            Skills = c.a,
                            Experience = c.c,
                            Certifications = c.d,
                          profile=c.e

                        }).FirstOrDefault() ;

 

if i do not use second select statement in which there is a new Candidate{}, i can't get candidate table values which are stored in annonymous variable e i have debug this i got candidate table null . what i did in my candidate model i declare a field of candidate type and store candidate table values in it, then pass this whole var data to my view as this  variable is of type candidate now so i can pass it to my view by doing this i got whole my candidate table values and other related values.

 

i want to ask that declaring candidate type field in a candidate model is ok or not.is thisa good practice.

1
Photo of Tuhin Paul
37 35.6k 319k Oct 12

declaring a Candidate type field within the Candidate model itself is not a good practice. By having a Candidate property within the Candidate model, you're creating a circular dependency. This can lead to serialization issues, infinite loops, and difficulties in mapping data.

Better approach, Remove the self-referential composition and flatten the data into separate properties within the Candidate model.

public class Candidate
{
    public int Id { get; set; }
   
    public ICollection<Academic> Academics { get; set; }
    public ICollection<Skill> Skills { get; set; }
    public ICollection<Experience> Experiences { get; set; }
    public ICollection<Certification> Certifications { get; set; }
}

Create a separate view model that contains the required properties from the Candidate model and related entities.

public class CandidateViewModel
{
    public Candidate Candidate { get; set; }
    public ICollection<Academic> Academics { get; set; }
    public ICollection<Skill> Skills { get; set; }
    public ICollection<Experience> Experiences { get; set; }
    public ICollection<Certification> Certifications { get; set; }
}