Search code examples
c#entity-frameworklinqjet-ef-provider

How do I do an inner join on two entities and output to another class type


I am creating an entity framework wrapper around an Access DB, and I can't modify the schema.

I have an entity called Component and an entity called TerminalInfo. The relationship is 1:0..1. I want to map the results to a 3rd class called Terminal.

This is what I have so far.

I am receiving the following syntax error.

Predefined type 'System.ValueTuple`2' is not defined or imported

public class TerminalUtility
{
    public ProjectContext context { get; private set; }

    public TerminalUtility(ProjectContext context)
    {
        this.context = context;
    }

    public IQueryable<Terminal> GetTerminals()
    {
            IQueryable<Terminal> terminals = context.TerminalInfos
            .Join(
                context.Components,
                C => C.Id,
                TI => TI.Id,
                (C, TI), 
                new Terminal(C,TI)
            );

        return terminals;
    }
}


[Table("Component")]
public class Component
{
    [Key]
    [Column("Counter")]
    public int Id { get; set; }

    [Column("Name")]
    public string Name { get; set; }

    public string HigherName { get; set; }

    public string LowerName { get; set; }

    public int SortOrder { get; set; }
    /*Various other not relavent properties */
}

[Table("CompPart")]
public class TerminalInfo
{
    [Key]
    [Column("Counter")]
    public int Id { get; set; }
    [Column("CompPartName")]
    public string LevelName { get; set; }
    [Column("CompPartSort")]
    public short LevelSorting { get; set; }
    /*Various other not relavent properties */
}

public class Terminal
{
    private Component _comp;
    private TerminalInfo _term;

    public Terminal(Component comp, TerminalInfo term)
    {
        _comp = comp;
        _term = term;

    }

    private int _Id;
    public int Id { get => _Id; set { _Id = value; _comp.Id = value; _term.Id = value; } }

    public string ProductName => _comp.Name; //** Name - Component

    public string TerminalBlock { get => _comp.HigherName; set => _comp.HigherName = value; } //** HigherName in Component

    public string TerminalNumber { get => _comp.LowerName; set => _comp.LowerName = value; } //* LowerName in Component

    public int TerminalSortOrder { get => _comp.SortOrder; set=> _comp.SortOrder = value; } //** SortOrder in Component

    public string LevelName { get=> _term.LevelName; set => _term.LevelName = value; } //** CompPartName in CompPart

    public short LevelSorting { get => _term.LevelSorting; set => _term.LevelSorting = value; } //** CompPartSort in CompPart

}

ETA: This is not related to Predefined type 'System.ValueTuple´2´ is not defined or imported

The problem was a typo in the Lambda expression.


Solution

  • Looks like you just have an easily overlooked typo. According to MSDN, the Join method syntax takes three lambdas as its last three arguments but you are passing two lambdas, a tuple, and a new object.

    Your GetTerminals method should read:

    public IQueryable<Terminal> GetTerminals()
    {
            IQueryable<Terminal> terminals = context.TerminalInfos
            .Join(
                context.Components,
                C => C.Id,
                TI => TI.Id,
                (C, TI) => new Terminal(C,TI) //This is a lambda expression
            );
    
        return terminals;
    }
    

    Keeping the third lambda expression on one line might help clarify the code next time you look at it, even though MSDN does actually add a line break after the =>.