I'm trying to convert the next query with left joins in order to get a IList of one of my model objects.
This is the query:
select M.MilestoneID, MT.MilestoneTypeID, M.RCCAID
from Sourcing.MilestoneType MT
left join Sourcing.Milestone M on M.MilestoneTypeID = MT.MilestoneTypeID
where M.MilestoneID is null or (M.RCCAID = 1)
Output I get in SQL
MilestoneID | TypeID | RCCAID
------------+--------+--------
1 | 1 | 1
NULL | 1 | NULL
I have tried with this
var list = from mt in db.MilestoneType
join m in db.Milestone on mt.MilestoneTypeID equals m.MilestoneTypeID
where m.RCCAID == id || m.MilestoneID == 0
select new Milestone
{
MilestoneID = m.MilestoneID,
RCCAID = m.RCCAID,
MilestoneTypeID = mt.MilestoneTypeID
};
var list1 = db.MilestoneType.Join(db.Milestone,
mt => mt.MilestoneTypeID,
m => m.MilestoneTypeID,
(mt, m) => new Milestone()
{
MilestoneID = m.MilestoneID,
RCCAID = m.RCCAID,
MilestoneTypeID = mt.MilestoneTypeID
}).Where(a => a.RCCAID == id ||a.MilestoneID==0).ToList();
The first one does not work.
And I get this error in the second one:
The entity or complex type 'Model.Milestone' cannot be constructed in a LINQ to Entities query
I'm trying to get all the milestone per RCCA with all the milestone types even if a milestone type is not created yet.
I expect to get an IList<Milestone>.
Related
I have two Lists:
using (DBEntities context = new DBEntities()) {
var userInfoList = context.UsersInfoes.ToList();
var membersList = context.Members.ToList();
}
These two list are represented on tables as below;
I want to be able to iterate through both lists WHERE THE TEAMID is equal to '10' and add FKUserID and Name to a third list where FKUserID is matching in both tables.
Is there anyway I can do this as efficiently as possible and produce these results in the third list?
You could use a linq join clause as follows:
var ThirdList =
from member in MembersList
join userInfo in UserInfoList on member.FKUserID equals userInfo.FKUserID
where member.TeamID == 12 // change 12 to the TeamID needed
select new { TeamID = member.TeamID, FKUserID = member.FKUserID, Name = userInfo.Name};
foreach(var tlist in ThirdList)
{
Console.WriteLine("{0} | {1} | {2}", tlist.TeamID, tlist.FKUserID, tlist.Name);
}
Output:
12 | 6 | kjh
12 | 7 | ghg
12 | 8 | dfi
I haven't tested this LINQ but it should work. You said you wanted TeamID = 10, but used 12 in your tables. Obviously, just change the 12 to whatever you want the TeamID to be.
var ThirdList = (from y in userInfoList join z in membersList on y.FKUserID equals z.FKUserID
where z.TeamID == 12
select new {
TeamID = z.TeamID,
FKUserID = z.FKUserID,
Name = y.Name
} ).ToList();
I am having a "Type expected" error which I have no idea why.
My query simply link 3 tables together while trying to get the distinct package and average number of rating.
The outcome should be like this
| PackageName | Average Rating |
| SG | 4 |
| USA | 4 |
IQueryable<Recommendation> recommendationQuery = db.Recommendations;
IQueryable<Booking> bookingQuery = db.Bookings;
IQueryable<Package> packageQuery = db.Packages;
recommendationQuery = (from recommendationItem in recommendationQuery
join bookingItem in bookingQuery
on recommendationItem.BookingId equals bookingItem.BookingId
join packageItem in packageQuery
on recommendationItem.Booking.PackageId equals packageItem.PackageId
select recommendationItem).GroupBy(c => c.Booking.Package.PackageTitle)
.Select(c => new ( c.Key, c.Average(d=>d.Rating)));
The type expected occurs in the .Select(c => new (.....
May I know if I have query it wrongly?
Because
1) I inner joined all my 3 tables together
2) Assuming I have all the table joined, I tried to group them by PackageName to distinct the name to one name
3) I tried to select the average sum of the rating of the same package.
any idea if there's a better solution for this?
database class diagram
Solution error
You need to store results back into a new variable to match your new type:
var results = from recommendationItem in recommendationQuery
join bookingItem in bookingQuery
on recommendationItem.BookingId equals bookingItem.BookingId
join packageItem in packageQuery
on recommendationItem.Booking.PackageId equals packageItem.PackageId
group recommendationItem
by recommendationItem.Booking.Package.PackageTitle
into grp
select new
{
PackageName = grp.Key,
AverageRating = grp.Average(d => d.Rating)
};
Here is my code:
var context = new InventoryContext();
var res = from i in context.Inventories
select new FullInventory
{
InventoryID = i.InventoryID,
ItemModelID = i.ItemModelID,
ModelName = i.ItemModel.ModelName,
...
Quantity = context.Inventories.Select(x => x.ItemModelID).Count()
};
return res.ToList();
The code I have works great, however the results look like this:
CATEGORY | MANUFACTURER | MODEL | QUANTITY
1. Hard drive | Dell | 250GB | 2
2. Hard drive | Dell | 250GB | 2
As you can see, I have 2 entries in the table and since those entries are exactly the same, I would like them to be grouped together. To group them together I need to group by ItemModelID, however I still need to put all of the data into a list of FullInventory classes.
How can I group my data together while still "selecting" the data into a list of FullInventory classes?
Group by that value and then just select out the first item from each group using let.
var res = from inventory in context.Inventories
group inventory by inventory.ItemModelID into model
let i = model.FirstOrDefault()
select [...]
I would attempt the Group By after retrieving the full list with a Lambda expression:
var context = new InventoryContext();
return (from i in context.Inventories
select new FullInventory
{
InventoryID = i.InventoryID,
ItemModelID = i.ItemModelID,
ModelName = i.ItemModel.ModelName,
...
Quantity = context.Inventories.Select(x => x.ItemModelID).Count()
}).GroupBy(g => g.ItemModelID).ToList();
You may use Distinct()
return res.Distinct().ToList()
My database has a sales table with entries like so:
_____________________________________
| id | title_id | qty |
-------------------------------------
| 0 | 6 | 10 |
-------------------------------------
| 1 | 5 | 5 |
-------------------------------------
| 2 | 6 | 2 |
-------------------------------------
Title_id is Foreign key pointing to Titles table which is as follows:
_____________________________________
| id | title_id | title |
-------------------------------------
| 0 | 5 | Soda |
-------------------------------------
| 1 | 6 | Coffee |
-------------------------------------
I want to find top 5 sold products wich means i need to calculate the qty value for each product for all it's entried in sales table then order the result by qty in descending order and limit the select to 5.
However I'm new to C# ASP.NET and somewhat new to SQL. I dont know how to do this with LINQ.
This is my code so far:
var getIds = (from sale in db.sales
join tit in db.titles on sale.title_id equals tit.title_id
group sale by sale.qty into result
orderby result.Sum(i => i.qty) descending
select new Publication
{
PubID = sales.title_id, Title = tit.title
}
).Take(5);
Assuming you have a navigation property Sale.Title, something like this should do:
var tops =
db.Sales
.GroupBy( o => o.Title )
.Select( o => new { Title = o.Key, Sum = o.Sum( x => x.Quantity ) } )
.OrderByDescending( o => o.Sum )
.Take( 5 )
.ToList();
tops is then a list of an anonymous type with two properties: the Title object and the sum of the quantities.
You can then get the values like this:
foreach( var top in tops )
{
int titleId = top.Title.title_id;
string title = top.Title.title;
int sumOfQuantities = top.Sum;
...
If you just want the top Title objects, can can select them like this:
List<Title> topTitles = tops.Select( o => o.Title ).ToList();
var result= (from p in sales
let k = new
{
Name = p.Name
}
group p by k into t
orderby Name descending
select new
{
Name = t.Name,
Qty = t.Sum(p => p.Qty)
}).Take(5);
If the entries in the Sales table are more than one per item (ie: in your example you have 'Soda' 10 + 'Soda' 2, then you need to GroupBy(), using the name as the key (or it's related id if it's in another table), but not the qty.
var topSales = db.sales.GroupBy(x => x.title)
.Select(g => new
{
Title = g.Key,
Qty = g.Sum(x => x.qty)
})
.OrderByDescending(x => x.Qty)
.Select(x => new Publication
{
PubID = x.Title.title_id,
Title = x.Title.title1
})
.Take(5)
.ToList();
Note that I've omitted the join statement assuming that you have a foreign key between sales.title_id -> title.id, and you are using LINQ to SQL. Also note that I've avoided using the query syntax in favor of the chained method syntax, I think it's much clear in this use case (although not always true, ie: cross-joins).
Also, SQL and LINQ have some similarities but don't let the names of clauses/methods fool you, LINQ is not SQL, IMHO, Microsoft just tried to make people comfortable by making it look similar ;)
EDIT: fixed GroupBy()
var result= (from p in sales
let k = new
{
Name = p.Name
}
group p by k into t
select new
{
Name = t.Name,
Qty = t.Sum(p => p.Qty)
}).OrderByDescending(i => i.Qty).Take(5);
You need to look at GroupBy; this will give you what you need
http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
I've currently got this sample table of data:
ID | Policy ID | History ID | Policy name
1 | 1 | 0 | Test
2 | 1 | 1 | Test
3 | 2 | 0 | Test1
4 | 2 | 1 | Test1
Out of this, I want to group by the Policy ID and History ID (MAX), so the records I want to be kept are ID's 2 and 4:
ID | Policy ID | History ID | Policy name
2 | 1 | 1 | Test
4 | 2 | 1 | Test1
I've tried to do this in LINQ and stumbling on the same issue every time. I can group my entities, but always into a group where I have to re-define the properties, rather than have them kept from my Policy objects. Such as:
var policies = _context.Policies.GroupBy(a => a.intPolicyId)
.Select(group => new {
PolicyID = group.Key,
HistoryID = group.Max(a => a.intHistoryID)
});
This simply just brings out a list of objects which have "Policy ID" and "History ID" within them. I want all the properties returned from the Policies object, without having to redefine them all, as there are around 50+ properties in this object.
I tried:
var policies = _context.Policies.GroupBy(a => a.intPolicyId)
.Select(group => new {
PolicyID = group.Key,
HistoryID = group.Max(a => a.intHistoryID)
PolicyObject = group;
});
But this errors out.
Any ideas?
Group by composite key
_context.Policies.GroupBy(a => new {a.intPolicyId, *other fields*}).Select(
group=> new {
PolicyId = group.Key.intPolicyId,
HistoryId = group.Max(intHistoryId),
*other fields*
}
);
Another way - grab histories, than join back with the rest of the data, something like this (won't work out of the box, will require some refining)
var historyIDs = _context.Policies.GroupBy(a=>a.intPolicyId).Select(group => new {
PolicyID = group.Key,
HistoryID = group.Max(a => a.intHistoryID)
});
var finalData = from h in historyIDs
join p in _context.Policies on h.intPolicyId equals p.intPolicyId
select new {h.HistoryId, *all other policy fields*}
And yet another way, even simpler and not require a lot of typing :):
var historyIDs = _context.Policies.GroupBy(a=>a.intPolicyId).Select(group => new {
PolicyID = group.Key,
HistoryID = group.Max(a => a.intHistoryID)
});
var finalData = from h in historyIDs
join p in _context.Policies on h.PolicyId equals p.intPolicyId && h.HistoryId equals p.HistoryId
select p
Basically it's somewhat equivalent to the following SQL query:
select p.*
from Policy p
inner join (
select pi.policyId, max(pi.historyId)
from Policy pi
group by pi.policyId
) pp on pp.policyId = p.policyId and pp.historyId = p.historyId
In LINQ to Objects, I'd do this as
var policies = _context.Policies
.GroupBy(a => a.intPolicyId)
.Select(g => g.OrderByDescending(p => p.intHistoryID).First());
but your _context impleis there might be a database involved and I'm not 100% sure this will translate.
Basically it groups by the policy ID as you'd expect, then within each group orders by history ID and from each group selects the row with the highest history ID. It returns exactly the same type as is found in Policies.