Convert simple t-sql query to linq - c#

I'm struggleing with a query. I know how to write it in SQL, but after looking at many examples and useing Linqer, I haven't had any success converting this to linq. Could someone point me in the right direction...
SELECT contacts.firstname, contacts.lastname
FROM businesscontacts INNER JOIN
contacts ON businesscontacts.contactsid = contacts.contactsid INNER JOIN
contactscontactcodes ON contacts.contactsid = contactscontactcodes.contactsid
This is, I believe, very close, but contacts is of course not defined...
string sendto = from businesscontacts in db.businesscontacts
from t in contacts.contactcodes
select new {
businesscontacts.contacts.firstname,
businesscontacts.contacts.lastname
};
If I prepend the db context...
string sendto = from businesscontacts in db.businesscontacts
from t in db.contacts.contactcodes
select new {
businesscontacts.contacts.firstname,
businesscontacts.contacts.lastname
};
Then contact codes is not available

You need to use the Linq join keyword to join the tables, just like you would in sql.
Here is a great resource to get you on your way with Line. 101 LINQ Samples
var results = from bc in db.businesscontacts
join c in db.contacts
on bc.contactsid equals c.contactsid
join cc in db.contacts.contactcodes
on c.contactsid = cc.contactsid
select new { FirstName = c.FirstName, LastName = c.LastName;

If you have foreign key constraints set up on your database you don't need to do any joins at all. Note that I changed the declaration of sendto since string doesn't make sense here.
var sendto = from businesscontact in db.businesscontacts.Include(bc => bc.contact)
select new {
businesscontact.contact.firstname,
businesscontact.contact.lastname
};

Try:
var names = from bContacts in db.businesscontacts
join contacts in db.contacts on bContacts.contactsid equals ontacts.contactsid
join cCodes in db.contacts.contactcodes on contacts.contactsid equals cCodes.contactsid
select new
{
FirstName = contacts.firstname,
LastName = contacts.lastname
};

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var businesscontacts = new List<businesscontacts>();
var contacts = new List<contacts>();
var contactcodes = new List<contactcodes>();
var sendto = from bc in businesscontacts
from c in contacts
from cc in contactcodes
where bc.Contactid == c.Contactid && cc.Contactid == c.Contactid
select new
{
c.FirstName,
c.LastName
};
}
}
class businesscontacts
{
public int Contactid { get; set; }
}
class contacts
{
public int Contactid { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
class contactcodes
{
public int Contactid { get; set; }
}
}

Related

how to write an EF query to join three tables and order by a field?

I have the following 3 tables structured in the way as shown below. I am trying to write an entity framework join query among the 3 tables
to
Select joblink, usersubmitted, runstatus, submitted_time, changelist
orderby submitted time
I was able to join and retrieve data from 2 tables but cant figure out
on how to join 3 tables, can anyone provide guidance on how to do this?
lookahead_run (Table#1)
+-------------------+--------+----------------+-------------------+----------+
lookahead_run_id(PK)|joblink | usersubmitted |submitted_time |runstatus
+-------------------+--------+----------------+-------------------+----------+
15963---------------+link1---+---username1----+2017-03-17 22:28:53--Fail-----
lookahead_run_change_list (Table#2)
+---------------+----------------+-----------------+
changelistid(PK)|lookahead_run_id|change_list_id
+---------------+----------------+-----------------+
38591-----------+15963-----------+34022
38590-----------+15963-----------+34021
38589-----------+15963-----------+34020
change_lists (Table#3)
+-------------+-----------+
change_list_id|changelist
+-------------+-----------+
34022-------- 1823900
34021-------- 1819483
34020-------- 1818572
UPDATED CODE;-
namespace Dashboard.Model.ApiModels
{
public class LookaheadRunInfo
{
public string ECJobLink { get; set; }
public List<String> gerrits { get; set; }
public string UserSubmitted { get; set; }
public string SubmittedTime { get; set; }
public string RunStatus { get; set; }
}
}
public IEnumerable<LookaheadRunInfo> GetLookaheadRunInfoSearch(LookaheadRunsFilterCriteria filterCriteria)
{
List<LookaheadRunInfo> lookaheadRunsInfo = new List<LookaheadRunInfo>();
var lookaheadRunData = bitDB.lookahead_run.OrderBy(x => x.lookahead_run_id).Skip(filterCriteria.PageNumber * filterCriteria.PageSize).Take(filterCriteria.PageSize).ToList();
foreach (var lookaheadRunRow in lookaheadRunData)
{
var lookaheadRunId = lookaheadRunRow.lookahead_run_id;
lookaheadRunsInfo = (from lrcl in bitDB.lookahead_run_change_list
join cl in bitDB.change_lists on lrcl.change_list_id equals cl.change_list_id
join lr in bitDB.lookahead_run on lrcl.lookahead_run_id equals lr.lookahead_run_id
where lrcl.lookahead_run_id == lookaheadRunId
orderby lr.submission_time
select new LookaheadRunInfo
{
lr.ec_job_link,
cl.change_requests,
lr.submitted_by,
lr.submission_time,
lr.lookahead_run_status,
}).ToList();
}
return lookaheadRunsInfo;
}
Error:-
Error 1 Cannot initialize type 'Dashboard.Model.ApiModels.LookaheadRunInfo' with a collection initializer because it does not implement 'System.Collections.IEnumerable'
You can put as many joins as you like in a query. if you want to select fields from multiple entities, you need to select a new object. I would suggest you to create a holder class to contain the joined contents, but i'm gonna show you how to do it with an anonymous type:
var lookaheadRunChangeListIds = (from lrcl in bitDB.lookahead_run_change_list
join cl in bitDB.change_lists on lrcl.change_list_id equals cl.change_list_id
join lr in bitDB.lookahead_run on lrcl.lookahead_run_id equals lr.lookahead_run_id
where lrcl.lookahead_run_id == lookaheadRunId
orderby lr.submitted_time
select new LookaheadRunInfo {
ECJobLink = lr.joblink,
UserSubmitted = lr.usersubmitted,
RunStatus = lr.runstatus,
SubmittedTime = lr.submitted_time,
gerrits = cl.changelist
}).ToList();
Note that the new { ... } can be replaced by a new NewClass { ... } where the NewClass contains all the selected fields.
Edit above: name your properties as you instanciate your LookAheadRun since the names are different, you should map them.

foreach on IEnumerable or IList

I am using LINQ with Entity framework to joining three tables and I am returning IList interface.
I want to apply foreach loop on this returned value so I can populate values in my model.
This is how I am joining:
public IList GetData(long Id)
{
//var q = dataContext.tblUsers.AsEnumerable().Join(dataContext.tblUsersProfiles.AsEnumerable(),)
var query = from u in dataContext.tblUsers
join p in dataContext.tblUsersProfiles on u.ProfileId equals p.Id
join c in dataContext.tblComments on u.Id equals c.Commentedby
where c.Id == Id
select new { u.Firstname, u.Lastname, p.ProfilePicPath, c.Comment, c.CommentDate };
return query.ToList();
}
I want to populate these values in my List of Model. I have tried this:
var lst = repository.GetDate(Id);
foreach (var item in lst)
{
}
But I am unable to access item Firstname/Lastname etc.
I also tried using object item and object[] item but they both are not working too.
How can I apply a foreachonIList`?
It will work fine If I'm be able to return DataTable instead of IList in this case.
You are creating an anonymous type. Just define a class for the result of your query, then the return type of your function should be like this:
public IList<YourClassName> GetData(long Id)
{
}
Finally set class values:
select new YourClassName
{
Firstname = u.Firstname,
Lastname = u.Lastname,
ProfilePicPath = p.ProfilePicPath,
Comment = c.Comment,
CommentDate = c.CommentDate
};
You're returning an anonymous list of objects in the method. You can access the properties by using reflection but this is abit slow at runtime. Easiest to get type information is by defining a class and use that in the select statement.
public class Person
{
public string Firstname { get; set; }
public string Lastname { get; set; }
/* ... */
}
public IList<Person> GetData(long Id)
{
var query = from u in dataContext.tblUsers
join p in dataContext.tblUsersProfiles on u.ProfileId equals p.Id
join c in dataContext.tblComments on u.Id equals c.Commentedby
where c.Id == Id
select new Person { u.Firstname, u.Lastname /* ... */ };
return query.ToList();
}
You should return not just IList interface but parametrised interface with your type. Now you returtint anounymouse object.
So what i want to suggest. Create this class:
public class MyCustomContainer
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public string ProfilePicPath { get; set; }
public string Comment { get; set; }
public string CommentDate { get; set; }
}
And the change your method like this:
public IList<MyCustomContainer> GetData(long Id)
{
//var q = dataContext.tblUsers.AsEnumerable().Join(dataContext.tblUsersProfiles.AsEnumerable(),)
var query = from u in dataContext.tblUsers
join p in dataContext.tblUsersProfiles on u.ProfileId equals p.Id
join c in dataContext.tblComments on u.Id equals c.Commentedby
where c.Id == Id
select new MyCustomContainer
{
Firstname = u.Firstname,
Lastname = u.Lastname,
ProfilePicPath = p.ProfilePicPath,
Comment = c.Comment,
CommentDate = c.CommentDate
};
return query.ToList();
}
Now you returning not anonymouse object within List so you can get all properties you need
You are creating an anonymous type:
select new { u.Firstname, u.Lastname, p.ProfilePicPath, c.Comment, c.CommentDate };
If you want to pass this data to other methods etc. you need to create a real class.
public class DataClass
{
public string Firstname { get; set; }
public string LastName{ get; set; }
public string ProfilePicPath { get; set; }
public string Comment { get; set; }
public DateTime CommentDate { get; set; }
}
and use it:
public IList<DataClass> GetData(long Id)
{
var query = from u in dataContext.tblUsers
join p in dataContext.tblUsersProfiles on u.ProfileId equals p.Id
join c in dataContext.tblComments on u.Id equals c.Commentedby
where c.Id == Id
select new DataClass
{
Firstname = u.Firstname,
Lastname = u.Lastname,
ProfilePicPath = p.ProfilePicPath,
Comment = c.Comment,
CommentDate = c.CommentDate
};
return query.ToList();
}
You must change GetData return type. Please try this:
public List<tblUsers> GetData(long Id)
{
//var q = dataContext.tblUsers.AsEnumerable().Join(dataContext.tblUsersProfiles.AsEnumerable(),)
var query = from u in dataContext.tblUsers
join p in dataContext.tblUsersProfiles on u.ProfileId equals p.Id
join c in dataContext.tblComments on u.Id equals c.Commentedby
where c.Id == Id
select new tblUsers { u.Firstname, u.Lastname, p.ProfilePicPath, c.Comment, c.CommentDate };
return query.ToList();
}
You're using an anonymous type so you can't cast it to anything when looping through your list. You could try using dynamic instead of var which means you can call any property on it as long as it exists at runtime:
foreach (dynamic item in lst)
{
string firstName = item.FirstName;
}
or explicitly defining a class for the result item like the other answers are suggesting.

Linq - Join where ID's !=, select new + distinct?

I have the following classes.
Course;
public class Course
{
//pk
public int Id{ get; set; }
public int SourceCourseId { get; set; }
public string Name { get; set; }
}
Registration
public class Registration
{
//primary key
public int Id { get; set; }
//...more fields
public int CourseId { get; set; }
}
I want to obtain a collection of annonymous objects with the two fields below for all Courses that are Distinct in the registrations table that are not in the Courses table.
var distinctCourses = (from registration in db.Registrations
join courses in db.Courses on registration.CourseId equals courses.SourceCourseId
where registration.CourseId != courses.SourceCourseId
select new
{
SourceCourseId = registration.CourseId,
Name = registration.CourseName,
}).Distinct().ToList();
For some reason the above is returning 0... Any suggestions?
try a left join:
var query = from r in registrations
join c in courses on r.CourseId equals c.id into newCourses
from nullCourse in newCourses.DefaultIfEmpty()
where nullCourse == null
select new { }
Edit - per comment from Alex :
Also, your where clause needs to change to
where nullCourse == null
Edit - changed join columns and added correct where clause.
Edit - group registrations on CourseID so they will be distinct
var distinctCourses =
(from registration in db.Registrations
group registration by registration.CourseId into grp
from reg in grp
join courses in db.Courses on reg.CourseId equals courses.SourceCourseId into newCourses
from nullCourse in newCourses.DefaultIfEmpty()
where nullCourse == null
select new
{
SourceCourseId = reg.CourseId,
Name = reg.CourseName,
}).ToList();
Try this
var result = Registrations.GroupJoin(Courses,r=>r.CourseId,c=>c.SourceCourseId,
(k,g) => new {k,g})
.Where(x=>x.g.Count()==0)
.Select(s=> new {id=s.k.CourseId,name=s.k.CourseName});

c# mvc apicontroller five table join and return value

can anyone please tell me, I have already joined five tables and I have tested join is correct. When I debug up to "Location1" values return.
Also I added return Location1, It says
"Error 1 Cannot implicitly convert type
'System.Collections.Generic.List' to
'System.Collections.Generic.IEnumerable'.
An explicit conversion exists (are you missing a cast?)"
My question is how can I display return valve?
This is my ApiController and class code.
public class Posts
{
public Suburb suburb { get; set; }
public SubRegion subRegion { get; set; }
public SubRegionDeliveryTime subRegionDeliveryTime { get; set; }
public DeliveryTime deliveryTime { get; set; }
public DeliveryPeriod deliveryPeriod { get; set; }
}
public IEnumerable<Posts> Get()
{
using (ApplicationDbContext db = new ApplicationDbContext())
{
var Location1 = (from su in db.TLCSuburb
join Subr in db.TLCSubRegion on
su.SubRegionID equals Subr.SubregionID
join srdt in db.TLCSubRegionDeliveryTime on
Subr.SubregionID equals srdt.SubregionID
join DT in db.TLCDeliveryTime on
srdt.DeliveryTimeId equals DT.DeliveryTimeId
join DP in db.TLCDeliveryPeriod on
DT.DeliveryPeriodID equals DP.DeliveryPeriodID
orderby Subr.SubregionID
select new
{
su.name,
su.postcode,
su.AuState,
su.Latitude,
su.Longitude,
DT.DeliveryDay,
DP.PeriodType,
Subr.CloseDayId,
Subr.SubregionName,
}).ToList();
//return null;
return Location1;
}
}
Write like this:
var Location1 = (from su in db.TLCSuburb
join Subr in db.TLCSubRegion on
su.SubRegionID equals Subr.SubregionID
join srdt in db.TLCSubRegionDeliveryTime on
Subr.SubregionID equals srdt.SubregionID
join DT in db.TLCDeliveryTime on
srdt.DeliveryTimeId equals DT.DeliveryTimeId
join DP in db.TLCDeliveryPeriod on
DT.DeliveryPeriodID equals DP.DeliveryPeriodID
orderby Subr.SubregionID
select new Post
{
suburb = new Suburb(){
Name = su.name,
PostCode = su.postcode,
AuState = su.AuState,
Latitude = su.Latitude,
Longitude = su.Longitude
},
deliveryTime = DT.DeliveryDay,
deliveryPeriod = new DeliveryPeriod(){
PeriodType = DP.PeriodType
},
subRegion = new SubRegion(){
CloseDayId = Subr.CloseDayId,
SubRegionName = Subr.SubregionName
}
}).ToList();
You'll have to explicitly convert it to IEnumerable<Post> instead of an anonymous type.

Join clause incorrect on multiple join LINQ

I have a multiple join query like this:
public static List<Answer> GetDetailedAnswers(string Tag)
{
using (Database db = new Database())
{
List<Answer> answer =
from quest in db.Question
join answ in db.Answer on quest.ID equals answ.QuestionID
join deal in db.Dealer on answ.DealerID equals deal.ID
join country in db.Country on deal.CountryID equals country.CountryID
where quest.ParentSection == Tag
select new
{
ParentSection = quest.ParentSection,
Section = quest.Section,
Dealer = deal.Name,
OriginalAnswer = answ.Original,
EngAnswer = answ.English,
Region = country.Country
}.ToList();
return answer;
}
}
And i have an internal class like this:
public class Answer
{
public string ParentSection { get; set; }
public string Section { get; set; }
public string Dealer { get; set; }
public string OriginalAnswer { get; set; }
public string EngAnswer { get; set; }
public string Region { get; set; }
}
I get an error on the last join. It says "the type of one of the expressions in the join clause is incorrect. Type inference failed in the call to 'Join'"
What did i miss? Thx
For the error: "AnonymousType#1 does not contain a definition for 'ToList' and no extension method 'ToList'", You can do following.
public static List<Answer> GetDetailedAnswers(string Tag)
{
using (Database db = new Database())
{
List<Answer> answer =
(from quest in db.Question
join answ in db.Answer on quest.ID equals answ.QuestionID
join deal in db.Dealer on answ.DealerID equals deal.ID
join country in db.Country on deal.CountryID equals country.CountryID
where quest.ParentSection == Tag
select new Answer
{
ParentSection = quest.ParentSection,
Section = quest.Section,
Dealer = deal.Name,
OriginalAnswer = answ.Original,
EngAnswer = answ.English,
Region = country.Country
}).ToList();
return answer;
}
}
You need to surround you query within round brackets and then apply .ToList() method to it.
Please check the data type of
deal.CountryID and country.CountryID. this should be same

Categories