How to convert a query with inner join in sql to linq - c#

How to convert this SQL in c# code
select t.Message
from [dbo].[tblA] t
inner join (
select Message, max(CreatedDate) as MaxDate
from [dbo].[tblA]
group by Message
) tm on t.Message = tm.Message and t.CreatedDate = tm.MaxDate
where Type='Enter'
Can you help me please .
I just created this ..but with inner join in more complicated for me.
var query = (from each in db.A
where each.StartDate == DateTime.Today
select each).FirstOrDefault();

If you want to get the whole message record in tblA with a max CreatedDate value, you can order the result and pick the first element, something like:
var query = from item in tblA
where item.Type = "Enter"
group item by item.Message into msgGroup
select msgGroup.OrderByDescending(t => t.CreatedDate).FirstOrDefault();

From what I understood, you want a message for which type is Enter and you want to get Max CreatedDate value for that message. If that's the requirement, i don't think you need inner join. You could use something like below in LINQ.
from m in tblA
where m.Type = "Enter"
group m by m.Message into temp
select new
{
Message = temp.Message,
CreatedDate = ( from temp2 in temp select temp.CreatedDate).max()
}

Related

How to add less than or equal to condition in linq inner join

We have two objects, Dates and ActiveEvents. Want to perform inner join on these with less than or equal to condition in linq. Same as ref of below SQL where consider #Tables are C# objects
Select A. from #Activities A
Inner Join #Dates D ON A.ActivityDate <= D.ProcessDate
Tried with below but it's not giving correct results.
var filteredActivity = (from e in ActiveEvents
from p in dates
where e.ActivityDate <= p.Date
select new ActiveEvent
{
ActivityDate = p.Date,
EventId = e.EventId
}).ToList();
And
var filteredActivity = (from e in ActiveEvents
from p in dates.Where(r => e.ActivityDate <= r)
select new ActiveEvent
{
ActivityDate = p.Date,
EventId = e.EventId
}).ToList();
Can you please suggest any better way to do this?
You can try this way
var filteredActivity = (from e in ActiveEvents
join p in dates
where e.ActivityDate <= p.ProcessDate
select new ActiveEvent
{
ActivityDate = p.Date,
EventId = e.EventId
}).ToList();
P/s: Ideally, between 2 tables should contain the foreign key to join like this join p in dates on e.Key equals p.ForeignKey
Based on your example, the query is filtering on ProcessDate but your linq query is filtering on p.Date. Are those the same field? The first example you gave should be correct.

How to check available hotel rooms

I am making a hotel reservation system in windows form by using SQL with LINQ. I have tables such as reservation tabel and room table. In reservation table I have checkin and checkout dates. I have no problem to show those rooms from reservation table in a specific date, but I don't know how to show rooms that are available on specific dates. I don't how to compare or filter out RoomsId from reservation table and room table.
Here is how I am getting rooms from reservation table on a specific date (checkin and checkout):
DateTime StartDateWantToBook = Convert.ToDateTime(dateTimePicker1.Value.ToString());
DateTime EndDateWantToBook = Convert.ToDateTime(dateTimePicker2.Value.ToString());
var ReservedRooms = (from u in db.Room join b in db.Reservation on u.RoomId equals b.RoomId join f in db.Floor on u.FloorId equals f.FloorId join ty in db.RoomType on u.RoomTypeId equals ty.RoomTypeId where StartDateWantToBook <= b.EndDate && b.StartDate <= EndDateWantToBook
select new {
RomId = b.RoomId,
Floor = f.FloorName,
RommsNr = u.RumNummer,
Room_Type = ty.AmountRomms
// But Here by somehow I think I have to run
// another Linq query to filter RoomsId and show only those who do not exists in Reservation table.
}
).ToList();
dataGridView1.DataSource = ReservedRooms;
So the question is How to show all rooms in Rooms table that do not exist in Reservartionroom in a specific dates. Thank you again!
This must work for you.
var AvailebleRooms = (from u in db.Room
where (!u.Reservation.Any(b => b.EndDate >= StartDateWantToBook && b.StartDate <= EndDateWantToBook))
select u).ToList();
i think you need left outer join AllRooms and ReservedRooms to get rooms only using where clause with specific dates
You need to select AllRooms, ReservedRooms in a specific date and filter AllRoom by list reservartion. That's my Idea, maybe contains is wrong.
DateTime StartDateWantToBook = Convert.ToDateTime(dateTimePicker1.Value.ToString());
DateTime EndDateWantToBook = Convert.ToDateTime(dateTimePicker2.Value.ToString());
var AllRooms = (from u in db.Room join b in db.Reservation on u.RoomId equals b.RoomId join f in db.Floor on u.FloorId equals f.FloorId join ty in db.RoomType on u.RoomTypeId equals ty.RoomTypeId select new {
RomId = b.RoomId,
Floor = f.FloorName,
RommsNr = u.RumNummer,
Room_Type = ty.AmountRomms
// But Here by somehow I think I have to run
// another Linq query to filter RoomsId and show only those who do not exists in Reservation table.
}).ToList();
var ReservedRooms = (from u in db.Room join b in db.Reservation on u.RoomId equals b.RoomId join f in db.Floor on u.FloorId equals f.FloorId join ty in db.RoomType on u.RoomTypeId equals ty.RoomTypeId where StartDateWantToBook <= b.EndDate && b.StartDate <= EndDateWantToBook select new {
RomId = b.RoomId,
Floor = f.FloorName,
RommsNr = u.RumNummer,
Room_Type = ty.AmountRomms
// But Here by somehow I think I have to run
// another Linq query to filter RoomsId and show only those who do not exists in Reservation table.
}).ToList();
var result = AllRoom.Except(ReservedRooms);
dataGridView1.DataSource = ReservedRooms;

Cannot make 5 consecutive "joins" in LINQ?

I have this rather complex query in SQL server 2008:
declare #LanguageID as int = 1
select k.datePublish, k.dateEditing, k.dateTables
from TableAreasLevel1 as areaL1
inner join TableAreasLevel2 as areaL2
on areaL1.LanguageID = areaL2.LanguageID and
areaL1.CodeAreaLevel1 = areaL2.CodeAreaLevel1
inner join TableAreasLink as link
on areaL2.CodeAreaLevel1 = link.CodeAreaLevel1 and
areaL2.CodeAreaLevel2 = link.CodeAreaLevel2 and
inner join TableProducts as tblProds
on tblProds.CodeAreaLevel1 = areaL1.CodeAreaLevel1 and
tblProds.CodeAreaLevel2 = areaL2.CodeAreaLevel2
inner join TableSI_Products as prod
on prod.SiAreaCode = link.SiAreaCode
inner join TableCalendar as k
on k.KodTableSI_Products = tblProds.KodTableSI_Products
where areaL1.LanguageID = #LanguageID and
prod.Code = 'some string' and
k.LanguageID = #LanguageID and
tblProds.LanguageID = #LanguageID;
I am trying to develop the same query in LINQ, but I get error when I try join the table TableProducts, i.e the third consecutive join.
Here is my LINQ query:
List<Tuple<DateTime, DateTime, DateTime>> dates = (from areaL1 in gpe.TableAreasLevel1
join areaL2 in gpe.TableAreasLevel2
on new { areaL1.CodeAreaLevel1, areaL1.LanguageID } equals
new { areaL2.CodeAreaLevel1, areaL2.LanguageID }
join link in gpe.TableAreasLink
on new { areaL2.CodeAreaLevel1, areaL2.CodeAreaLevel2, areaL2.RbrOblastNivo2} equals
new {link.CodeAreaLevel1, link.CodeAreaLevel2}
join tblProds in gpe.TableProducts
on tblProds. // The name tblProds is not in the scope of the left side of 'equals'
);
Is the problem connected with how the tables are designed or, something else I should check for?
Any ideas, why tblProds is not visible in the scope of the LINQ query?
You are using Query as your guide something like:
on k.KodTableSI_Products = tblProds.KodTableSI_Products
but take a look at your linq:
on new { areaL1.CodeAreaLevel1, areaL1.LanguageID } equals
it has two fields. I think its not a good idea.
linq join something like
var dates = (from areaL1 in gpe.TableAreasLevel1
join areaL2 in gpe.TableAreasLevel2
on areaL1.PKFields equals areaL2.PKFields
where areaL1.CodeAreaLevel1== areaL2.CodeAreaLevel1 && areaL1.LanguageID = areaL2.LanguageID
Select new YournewClass{YournewClass.Field1=areaL1.fields1, And so on}
)
You can do to join the other tables with aliases.
Sorry need to go for now.
I'm giving you an idea.
Hope it helps.

Subquery in Linq query giving A query body must end with a select clause or a group clause

booked - below - should be the sum of the NumberBooked column from the Bookings table - which has a link to the TourDates table on the TourDateId.
However I'm getting the error A query body must end with a select clause or a group clause
Can anyone please help me fix this query?
Thank you,
Mark
var tours = from t in Tours
join d in TourDates on t.TourId equals d.TourId
where d.Date == dt
select new
{
t.TourId,
d.TourDateId,
booked = (from b in Bookings where d.TourDateId == b.TourDateId)
Select new {bk.Sum(b.NumberBooked()}
};
I believe this:
booked = (from b in Bookings where d.TourDateId == b.TourDateId) // oops
Select new {bk.Sum(b.NumberBooked()}
should be this:
booked = (from b in Bookings where d.TourDateId == b.TourDateId // move from here
select new {bk.Sum(b.NumberBooked()}) // to here
Note that I moved the end parenthesis ) so that it comes after the select, not after TourDateId
The closing round paranthesis ends the query which needs a select at the end.
Why don't you use method syntax? It is much better readable in this case. Also, a Select is optional with .Where and method syntax:
join d in TourDates on t.TourId equals d.TourId
where d.Date == dt
select new
{
t.TourId,
d.TourDateId,
booked = Bookings.Where(b => d.TourDateId == b.TourDateId)
.Sum(b => b.NumberBooked())
};
Note that i have removed the anonymous type since you just want the sum of that column
should be the sum of the NumberBooked column from the Bookings table -
which has a link to the TourDates table on the TourDateId.

nhibernate - getting having count working with a subquery

So I have a many to many relationship between something known as Specialism and SpecialismCombo. What I'm trying to do is take an int[] of ids and check if there is a combo already that contains the specialisms with those ids.
I was close but not quite right.
Say I have specialisms with Ids 1 and 3 and I create a combo with those specialisms.
If I pass in 3 & 1 then it returns the expected combo id.
If I pass in 1 then it returns the combo id that has both 1 and 3.
I can't just rely on total number of specialisms associated with the combo. Because if a combo has two items, 1 and 4 and the items being matched on are 1 and 3 I don't want this coming back as a matched combo.
So it's like I do need the count of this result, and match the count of total specialisms associated to the combo. I don't quite get whether I'm after a subquery or detatchedcriteria or how to get the result I want using nhibernate criteria. Thanks for your help!
int[] SpecialismIds = ArrayExtensions.ConvertArray<int>(idCollection.Split(new char[] { '|' }));
ICriteria query = m_SpecialismComboRepository.QueryAlias("sc");
query.CreateAlias("sc.Specialisms", "s", NHibernate.SqlCommand.JoinType.InnerJoin);
ICriterion lastCriteria = null;
foreach(int i in SpecialismIds)
{
ICriterion currentCriteria = Restrictions.Eq("s.SpecialismId", i);
if (lastCriteria != null)
lastCriteria = Restrictions.Or(lastCriteria, currentCriteria);
else
lastCriteria = currentCriteria;
}
if (lastCriteria != null)
query.Add(lastCriteria);
IProjection IdCount = Projections.Count("s.SpecialismId").As("IdCount");
query.SetProjection(
Projections.GroupProperty("sc.SpecialismComboId"),
IdCount
);
query.Add(Restrictions.Eq(IdCount, SpecialismIds.Count()));
var comboId = query.List();
The sql being generated is:
SELECT this_.SpecialismComboId as y0_, count(s1_.SpecialismId) as y1_
FROM dbo.SpecialismCombo this_
inner join SpecialismComboSpecialism specialism3_ on this_.SpecialismComboId=specialism3_.SpecialismId
inner join dbo.Specialism s1_ on specialism3_.SpecialismComboId=s1_.SpecialismId WHERE s1_.SpecialismId = #p0
GROUP BY this_.SpecialismComboId HAVING count(s1_.SpecialismId) = #p1',N'#p0 int,#p1 int',#p0=3,#p1=1
EDIT - It seems like I either need the having to be something like...
HAVING count(s1_.SpecialismId) = (select count(SpecialismId)
from specialismComboSpecialism
where SpecialismComboId = y0
group by SpecialismComboId) == #p2
Or maybe it's simpler than that and I need to exclude SpecalismCombos where the combo.specialisms are not in the collection of ids.
Ie. if the combo has specialisms 1 and 3 but the collection only has 1.. then we could exclude this combo based on 3 not being in the collection…
Edit 8/8/2011
Went back to focusing on how to get the result I needed in SQL - and I believe this query works.
WITH CustomQuery AS
(
SELECT sc.SpecialismComboId,
count(s.SpecialismId) AS ItemCount
FROM SpecialismCombo sc
inner join SpecialismComboSpecialism scs on sc.SpecialismComboId = scs.SpecialismComboId
inner join Specialism s on s.SpecialismId = scs.SpecialismId
GROUP BY sc.SpecialismComboId
HAVING count(s.SpecialismId) = 2
)
SELECT CustomQuery.SpecialismComboId FROM CustomQuery
INNER JOIN SpecialismComboSpecialism scs on CustomQuery.SpecialismComboId = scs.SpecialismComboId
WHERE scs.SpecialismId in (1,4)
GROUP BY CustomQuery.SpecialismComboId
HAVING count(scs.SpecialismId) = 2
So now I just need to figure out how to call this procedure from my nhibernate code passing in the appropriate values :)
I also discovered in the process that my mapping class was wrong - as it was putting the wrong values in the mapping table (ie. the specialismid was ending up in the specialismcomboid field !)
Your solution should actually work well. The specialisms are filtered by id and there shouldn't be anything left that is not searched for, so count should work. Unless you have the same specialism joined more the once. This currentCriteria lastCriteria stuff looks a bit strange, may be there is an error. Just use Expression.In or Conjunction.
IProjection IdCount = Projections.Count("s.SpecialismId").As("IdCount");
IQuery query = session
.CreateCriteria<SpecialismCombo>("sc")
.CreateCriteria("Specialism", "s");
.Add(Expression.In("s.SpecialismId", SpecialismIds));
.SetProjection(
Projections.GroupProperty("sc.SpecialismComboId"),
IdCount);
.Add(Restrictions.Eq(IdCount, SpecialismIds.Count()));
Should result in a query like this:
select ...
from
SpecialismCombo sc
inner join -- linktable ...
inner join Specialism s on ...
where
s.SpecialismId in (1, 4)
Group By sc.SpecialismComboId
having count(*) = 2
The same in HQL
from SpecialismCombo sc
join sc.Specialism s
where s.id in (:ids)
group by sc
having count(*) = :numberOfIds
You could also join the specialism as many times as you have ids to find:
IQuery query = session.CreateCriteria<SpecialismCombo>("sc")
int counter = 0;
foreach(int id in ids)
{
string alias = "s" + counter++;
query
.CreateCriteria("Specialism", alias);
.Add(Expression.Eq(alias + ".SpecialismId", id));
}
should create a query like this:
select ...
from
SpecialismCombo sc
inner join -- linktable ...
inner join Specialism s0 on ...
inner join -- linktable ...
inner join Specialism s1 on ...
where
s0.SpecialismId = 1
and s1.SpecialismId = 4
So I ended up creating a stored proc and using SQL CTE in order to get only the specialism combos with the correct count of specialisms. Posting this in case someone else comes across a similar issue.
Rediscovered after 8 months of using nhibernate that I'd forgotten a lot of SQL stuff :)
DECLARE #IdCollectionCount INT
, #IdCollection VARCHAR(250)
, #CollectionDelimiter NVARCHAR
SET #IdCollectionCount = 2;
SET #IdCollection = '1,4';
SET #CollectionDelimiter= ',';
WITH CustomQuery AS
(
SELECT sc.SpecialismComboId,
count(s.SpecialismId) AS ItemCount
FROM SpecialismCombo sc
inner join SpecialismComboSpecialism scs on sc.SpecialismComboId = scs.SpecialismComboId
inner join Specialism s on s.SpecialismId = scs.SpecialismId
GROUP BY sc.SpecialismComboId
HAVING count(s.SpecialismId) = #IdCollectionCount
)
SELECT Top 1 CustomQuery.SpecialismComboId FROM CustomQuery
INNER JOIN SpecialismComboSpecialism scs on CustomQuery.SpecialismComboId = scs.SpecialismComboId
INNER JOIN dbo.fn_SplitDelimited(#IdCollection,#CollectionDelimiter) AS ids
ON scs.SpecialismId = CAST(ids.ListValue AS INT)
GROUP BY CustomQuery.SpecialismComboId
HAVING count(scs.SpecialismId) = #IdCollectionCount

Categories