There is no need to convert the EntityLists to custom objects to be able to do joins, as long as you have lookups to join on since this is the key for doing joins in LINQ. In my demo fragments below I have few lists (Country, Supplier, Product, ProductCategory) with lookups between these lists.
using (var context = new DemoTeamSiteDataContext(SPContext.Current.Web.Url))
{
// get entity list
EntityList<SuppliersItem> suppliers = context.GetList<SuppliersItem>("Suppliers");
// retrieve list of distinct country titles over the supplier->country lookup
var query = suppliers.Select(s => s.Country.Title).Distinct();
// or in sql syntax
query = (from s in suppliers
select s.Country.Title).Distinct();
}
After you execute the actual query with a .ToList() or foreach iteration, you'll see following CAML generated if you output the context.Log property to a file. In this query you see that a join is created for you by LINQ without having to explicitly use the .Join() method.
<View>
<Query>
<Where>
<BeginsWith>
<FieldRef Name="ContentTypeId" />
<Value Type="ContentTypeId">0x0100</Value>
</BeginsWith>
</Where>
</Query>
<ViewFields>
<FieldRef Name="CountryTitle" />
</ViewFields>
<ProjectedFields>
<Field Name="CountryTitle" Type="Lookup" List="Country" ShowField="Title" />
</ProjectedFields>
<Joins>
<Join Type="LEFT" ListAlias="Country">
<!--List Name: Countries-->
<Eq>
<FieldRef Name="Country" RefType="ID" />
<FieldRef List="Country" Name="ID" />
</Eq>
</Join>
</Joins>
<RowLimit Paged="TRUE">2147483647</RowLimit>
</View>
Maybe another example with a bit more complexed join queries over multiple lookups. We start from the products list, query over 2 lookups to the country code of the supplier of the product and in the select we also retrieve the category title, which is yet another lookup to the Category list. You may notice I'm using the object oriented syntax over the sql syntax, but the same is possible in the sql syntax. Take the syntax you feel comfortable with.
var query = context.Products.Where(p => p.Supplier.Country.Code == "US")
.Select(p => new { Title = p.Title, Supplier = p.Supplier.Title,
Category = p.Category.Title });
foreach (var product in query)
{
Console.WriteLine(String.Format("Product: {0}\tSupplier:{1}\tCountry:{2}",
product.Title, product.Supplier, product.Category));
}
Also note that I'm directly querying context.Products, which drops the extra step to create an EntityList object first and then query on that object like in the 1st example.
Your example would convert to something like:
// name parameter Table2Title to prevent name collision between both titles
var result = context.Table1
.Where(a => a.LookupFieldToTable2.FieldInTable2 == inputFromUser)
.Select(a => new { a.Title, a.SomeOtherField, Table2Title = a.LookupFieldToTable2.Title });