score:1

This is an odd structure to map. Structurally it looks like a 1-to-0..1, but in concept it looks like it should be 1-to-many. For a 1-to-many I'd be expecting a table structure more like:

Applicant ( ApplicantId | Name )

ApplicantNote ( ApplicantNoteId | ApplicantId | Note )

This would be mapped in EF something like:

public class Applicant
{
    public int ApplicantId { get; set; }
    public string Name { get; set; }

    public virtual ICollection<ApplicantNote> { get; set; } = new List<ApplicantNote>();
}

public class ApplicantNote
{
    public int ApplicantNoteId { get; set; }
    public virtual Applicant Applicant { get; set; }
}

public class ApplicantConfig : EntityTypeConfiguration<Applicant>
{
    public ApplicantConfig()
    {
        ToTable("Applicant");
        HasKey(x => x.ApplicantId);

        HasMany(x => x.ApplicantNotes)
            .WithRequired(x => x.Applicant)
            .Map(x => x.MapKey("ApplicantId"));
    }
}
public class ApplicantNoteConfig : EntityTypeConfiguration<ApplicantNote>
{
    public ApplicantNoteConfig()
    {
        ToTable("ApplicantNote");
        HasKey(x => x.ApplicantNoteId);
    }
}

What you have is more like an Applicant table that contains a note, but then there is an additional table that can hold a single, additional extra note.

Applicant ( ApplicantId | Name | Note )

ExtraApplicantNote ( ApplicantId | Note ) // Name isn't required.

which in a 1-to-0..1 would look something like:

public class Applicant
{
    public int ApplicantId { get; set; }
    public string Name { get; set; }
    public string Note { get; set; }

    public ExtraApplicantNote ExtraApplicantNote { get; set; }
}

public class ExtraApplicantNote
{
    public int ApplicantId { get; set; }
    public string Note { get; set; }
    public virtual Applicant Applicant { get; set; }
}

public class ApplicantConfig : EntityTypeConfiguration<Applicant>
{
    public ApplicantConfig()
    {
        ToTable("Applicant");
        HasKey(x => x.ApplicantId);

        HasOptional(x => x.ExtraApplicantNote)
            .WithRequired(x => x.Applicant);
    }
}
public class ExtraApplicantNoteConfig : EntityTypeConfiguration<ExtraApplicantNote>
{
    public ExtraApplicantNoteConfig()
    {
        ToTable("ExtraApplicantNote");
        HasKey(x => x.ApplicantId);
    }
}

This joins this extra applicant note record to the Applicant as an optional associated entity. When selecting as an entity graph:

var applicant = context.Applicants
    .Include(x => x.ExtraApplicantNote)
    .Single(x => x.ApplicantId == applicantId);

for example... then access the note(s) via applicant.Note and applicant?.ExtraApplicantNote.Note to account for the fact that an extra applicant note is optional.

To produce an output of all notes with their applicant details, a 1-to-many structure is far, far simpler to produce:

var notes = context.ApplicantNotes.Select(x => new 
  {
    x.Applicant.ApplicantId,
    x.Applicant.Name,
    x.Note
  }).ToList();

To do the same thing with a 1-to-0..1 is a fair bit more involved:

var notes = context.Applicants.Select(x => new 
  {
    x.ApplicantId,
    x.Name,
    x.Note
  }).Union(context.ExtraApplicantNotes.Select(x => new
  {
    x.ApplicantId,
    x.Applicant.Name,
    x.Note
  })).ToList();

This involves first pulling the notes from the first table, then using a union to join the same details from the optional records in the second table.

** Edit ** Sorry, I re-read the question and you want the 2nd table to override the first.

In this case, similar to above:

var notes = context.ExtraApplicantNotes.Select(x => new 
  {
    x.ApplicantId,
    x.Applicant.Name,
    x.Note
  }).Union(context.Applicants
  .Where(x => x.ExtraApplicant == null)      
  .Select(x => new
  { 
    x.ApplicantId,
    x.Name,
    x.Note
  })).ToList();

score:1

I would go for an inner join with .Join():

var lst = applicantList.Join(GetNewNotes,
    (a) => a.APPLICANT_ID,
    (n) => n.APPLICANT_ID,
    (a, n) => return new
    {
        a.APPLICANT_ID,
        a.Applicant_Name,
        n.Notes
    });

/*
lst:
2 | BEN TULFO   | NoteA,
3 | ERNIE BARON | NoteB
*/

As a side note, is there any reason your second table contains ApplicantName? Why not keep this in Applicant table only?

EDIT: After re-reading the question, I realized that you need the unmatched entries from the left list too. So, that should be left outer join instead, which you achieve with .GroupJoin() and .SelectMany():

var lst = applicantList.GroupJoin(GetNewNotes,
    (a) => a.Id,
    (n) => n.Id,
    (a, n) => new
    {
        Id = a.Id,
        Name = a.Name,
        Notes = a.Notes,
        ApplicantNotes = n
    })
    .SelectMany(
        g => g.ApplicantNotes.DefaultIfEmpty(),
        (g, applicantNotes) => new
        {
            Id = g.Id,
            Name = g.Name,
            Notes = applicantNotes?.Notes ?? g.Notes
        });

/*
lst:
1 | RAY HEAVENS | Note1
2 | BEN TULFO   | NoteA
3 | ERNIE BARON | NoteB
4 | SUPERMAN    | Note4
5 | MARK LAPID  | Note5
*/

Related Articles