I am having a problem getting some LinQ to work inside a WCF service operation:
[WebGet]
public IQueryable<StockItem> AllStockableItems(int LocationAddressId)
{
StockEntities svc = this.CurrentDataSource;
//get all the stock at a location
var StockAtLocation = from s in svc.Stock
where s.Location == Location
select s;
//weave it into the list of all stockable items
var StockableItems = from si in svc.StockableItems
join s in StockAtLocation on si.ItemId equals s.ItemId into tmp
select si <and somehow expand> si.Stock;
return StockableItems;
}
Problem is, I don't know how to expand the stock in the returned data?
A url like the following:
....my.svc/AllStockableItems?LocationAddressId=3&$expand=Stock
Will expand the stock for all locations, rather than just the location needed. Is this possible or is my best bet to make 2 seperate requests from the Silverlight client and do the joining client side?
Any help greatly appreciated.
Yes, example data, sorry for not putting it in first time around:
example stock data:
ItemId Location Quantity
1 1 4
1 2 3
1 3 2
2 2 6
3 3 0
7 1 3
7 2 0
example stockableItems data
ItemId <other columns>..
1
2
3
4
5
6
7
8
Say the locationAddressId paramter =2, I'm trying get the service operation to return (not literally, but in the Atom/Pub equivalent):
StockableItem { ItemId :1
Stock {
entry {
Stock {LocationId : 2, Qty :4}
}
}
}
StockableItem { ItemId :2 }
StockableItem { ItemId :3 }
StockableItem { ItemId :4 }
StockableItem { ItemId :5 }
StockableItem { ItemId :6 }
StockableItem { ItemId :7
Stock {
entry {
Stock {LocationId : 2, Qty :0}
}
}
}
StockableItem { ItemId :8 }
Thank you.
[Update 2]
Ok, I've tried a couple fo things; first off I gave this a go:
var StockableItems = from si in svc.AllStockableItems
join s in svc.Stock on si.ItemId equals s.ItemId
where s.Location == Location
select new StockableItem
{
ItemId = s.ItemId,
Stock = new EntityCollection<Stock>
{
new Stock()
{
Location = s.Location,
Quantity= s.Quantity
}
}
};
Which gave me:
The entity or complex type '...' cannot be constructed in a LINQ to Entities query
Which led me to here:
The entity cannot be constructed in a LINQ to Entities query
Which led me to re-write the query to this:
var StockableItems = svc.AllStockableItems
.Join(svc.Stock, si => si.ItemId, s => s.ItemId, (si, s) => si)
.ToList()
.Select(si => new StockableItem
{
ItemId = si.ItemId,
Stock = new EntityCollection<Stock>
{
new Stock()
{
Location = si.Stock.First().Location,
Quantity= si.Stock.First().Quantity
}
}
})
.AsQueryable();
Which returns all the StockableItems but, somewhat frustratingly, doesn't include any Stock. Have I simply made a boo boo in this last query? I suspect my inner projection of the Stock entity is incorrect?
Thanks Again
I think you're looking for something like this:
var StockableItems = from si in svc.StockableItems
join s in StockAtLocation on si.ItemId equals s.ItemId
select new
{
StockableItem = si,
Stock = s
};
You can choose how you project your output in the select clause. You can select the entire object, like above, or you can also select fields in your objects. For example:
select new
{
ItemId = si.ItemId,
Stock = s,
Qty = s.Quantity
};
Also, you may want to consider combining your two queries into a single query:
var StockableItems = from si in svc.StockableItems
join s in svc.Stock on si.ItemId equals s.ItemId
where s.Location == Location
select new
{
StockableItem = si,
Stock = s
};
And now one more example that shows you something really close to your example output:
var StockableItems = from si in svc.StockableItems
join s in svc.Stock on si.ItemId equals s.ItemId
where s.Location == Location
select new
{
StockableItem = new
{
ItemId = s.ItemId,
Stock = new
{
LocationId = s.Location,
Qty = s.Quantity
}
}
};
Update
I've made some adjustments to your modified query which uses the Join to create the data that is passed onto the rest of the query. I also put your Where clause back in there (if you want to use it there) to filter on Location. I also took the ToList() out of there because I'm not sure if it's necessary.
var StockableItems = svc.AllStockableItems
.Join(svc.Stock, si => si.ItemId, s => s.ItemId,
(si, s) => new
{
ItemId = si.ItemId,
Location = s.Location,
Quantity = s.Quantity
})
.Where(x => x.Location == Location)
//.ToList()
.Select(x => new StockableItem
{
ItemId = x.ItemId,
Stock = new EntityCollection<Stock>
{
new Stock()
{
Location = x.Location,
Quantity= x.Quantity
}
}
})
.AsQueryable();
Related
I've currently got the SQL code below:
WITH region_list
AS (SELECT r.StateProvinceRegion,
r.CafeId,
s.Longitude,
s.Latitude,
ROW_NUMBER() OVER(PARTITION BY r.StateProvinceRegion
ORDER BY s.Longitude DESC) AS row_no
FROM CafeAddress r
inner join Restaurant s on s.CafeId = r.CafeId
)
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS ID,
StateProvinceRegion,
Longitude,
Latitude
FROM region_list
WHERE row_no = 1;
How would I go about adding this query? In my method below I've implemented something similar but I don't understand how to add the WITH clause in.
public VersionResponse GetCafeRegion()
{
var regionList = from cafeAddress in _context.CafeAddress
join cafe in _context.Cafe on cafeAddress.CafeId equals cafe.CafeId
select new { cafeAddress.StateProvinceRegion, cafeAddress.CafeId, cafe.Longitude, cafe.Latitude };
return new VersionResponse()
{
Data = regionList
};
}
Try the below code once.
public VersionResponse GetCafeRegion()
{
var CafeAddress = new List<CafeAddress>();
var Cafe = new List<Cafe>();
var regionList = from cafeAddress in _context.CafeAddress
join cafe in _context.Cafe on cafeAddress.CafeId equals cafe.CafeId
group new { cafeAddress.StateProvinceRegion, cafeAddress.CafeId, cafe.Longitude, cafe.Latitude } by cafeAddress.StateProvinceRegion into g
select g;
List<object> finalResult = new List<object>();
int index = 1;
foreach(var gg in regionList)
{
var groupRecord = gg.OrderByDescending(x => x.Longitude).FirstOrDefault();
finalResult.Add(new
{
ID = index++,
groupRecord.StateProvinceRegion,
groupRecord.CafeId,
groupRecord.Latitude,
groupRecord.Longitude
});
}
return new VersionResponse()
{
Data = finalResult
};
}
I'm doing a sample project where it counts the total issues per month that is to be displayed in a bar graph..
Here is my working SQL query
SELECT
SUM(CASE datepart(month,D_ISSUE) WHEN 1 THEN 1 ELSE 0 END) AS 'Jan',
SUM(CASE datepart(month,D_ISSUE) WHEN 2 THEN 1 ELSE 0 END) AS 'Feb',
so on...
FROM EMP_MEMOS
Can someone help me transpose this SQL Query into a LinQ code. i'm still trying to understand how it works
Here is my code so far, but i still can't get it to work.
public ActionResult MonthCount()
{
var Monthly = (from f in db.EMP_MEMOS
group f by new { month = f.D_ISSUE, year = f.D_ISSUE } into g
orderby g.Key.year
select new
{
dt = string.Format("{0}/{1}", g.Key.month, g.Key.year),
}).ToList();
return Json(new { result = Monthly }, JsonRequestBehavior.AllowGet);
}
I already got the answer, gonna share it here:
public ActionResult CountMonth()
{
var memo = from t in db.EMP_MEMOS
select new
{
t.D_ISSUE.Value.Month,
t.D_ISSUE.Value.Year
};
var res = from s in memo
group s by new { s.Year, s.Month } into g
select new
{
Period = g.Key,
MemoCount = g.Count(),
};
return Json(new { result = res }, JsonRequestBehavior.AllowGet);
}
I have this SQL query that I want to translate into Linq-to-SQL:
Now here's the beginning of the Linq-to-SQL code but I'm stuck on how to group fields and get SUM :
private void GetDatas()
{
DateTime d = DateTime.Now;
using (DataClasses1DataContext dc = new DataClasses1DataContext())
{
var query = from ent in dc.STK_ABC_ENT
join det in dc.STK_ABC_DET on ent.ENT_ID equals det.ENT_ID
join art in dc.FICHES_ARTICLES on ent.ART_CODE equals art.ART_CODE
where !ent.ENT_NUM_PAL.Contains("FDR_")
&& ent.ENT_OUTDATE == null
&& ent.ENT_PICKING == null
&& ent.ENT_DATE_ENT != d
// How to group here ?
// How to get SUM ??
}
}
You can use group x by ColumnName into z to group a column.
When you want to group multiple columns you can use group x by new { x.Column1, x.Column2 } into z.
When you want to group multiple columns in multiple tables you can use group new { x, y } by new { x.Column, y.Column } into z.
With Sum, just call it in select with lamda expression.
Example:
var query = from ent in dc.STK_ABC_ENT
join det in dc.STK_ABC_DET on ent.ENT_ID equals det.ENT_ID
join art in dc.FICHES_ARTICLES on ent.ART_CODE equals art.ART_CODE
where !ent.ENT_NUM_PAL.Contains("FDR_") && ent.ENT_OUTDATE == null
&& ent.ENT_PICKING == null && ent.ENT_DATE_ENT != d
group new { art, ent } by new {
art.ART_CODE,
...,
ent.ENT_DATE_ENT,
...
} into grouped
select new {
ArtCode = grouped.Key.ART_CODE,
SumPdsNet = grouped.Sum(x => x.DET_PNET),
...
}
I hope it can work for you.
I have a function as below :
IEnumerable<Group> GetAllChildren(int parentID)
{
using (Entities db = new Entities())
{
var result = (from x in db.Groups
where x.ParentID == parentID
select x).ToList();
foreach (Group child in result.ToList())
{
result.AddRange(GetAllChildren(child.GroupID));
}
return result;
}
}
In the above function if I pass a group name I get all the children at all levels.
It works as expected.
Now my query looks like something like :
GroupNamesWithCorrespondingEffects
= new ObservableCollection<GroupNameWithCorrespondingEffect>
(from g in db.Groups
select new GroupNameWithCorrespondingEffect
{
GroupID = g.GroupID,
GroupName = g.GroupName,
CorrespondingEffect = g.Master_Effects.Effect
}
);
The above query will give me all the groups.
Now I want to remove all the groups from GroupNamesWithCorrespondingEffects that are children of a group with id == 25.
I have tried .Remove(GetAllChildren(25)) in 2nd query. but I get following error.
Collection.Remove(GroupNameWithCorrespondingEffect) has some invalid arguments.
hope this help you:
var childs = GetAllChildren(25).ToList();
var childIDList = childs.select(u => u.GroupID).ToList();
GroupNamesWithCorrespondingEffects = GroupNamesWithCorrespondingEffects
.Where(u => !childIDList.Contains(u.GroupID)).ToList();
I have a Table(Send) with columns(Id, UserId,SendDate) and another table(Receive) with columns(Id,SendId,UserName).
I want show all records in SendTable with all RecieveUserName.
for example.
(Send)
1 1 2013
2 2 2013
(Recieve)
1 1 Jack
2 1 Ema
3 2 Alex
4 2 Sara
Result
1 1 2013 Jack, Ema
2 2 2013 Alex, Sara
I use this query in SqlServer (The DISTINCT keyword eliminates duplicate rows from the results of a SELECT statement)
SELECT DISTINCT c2.Id,
(SELECT STR( UserName )+ ','
FROM dbo.Reciver c1
WHERE c1.SendId = c2.id FOR XML PATH('')) Concatenated, c2.SendDate, c2.UserId
FROM dbo.Send AS c2 INNER JOIN
dbo.Reciver ON c2.Id = dbo.Reciver.SendId
How do this query in Linq?
Distinct is also available in LINQ.
For example
public class Product
{
public string Name { get; set; }
public int Code { get; set; }
}
Product[] products = { new Product { Name = "apple", Code = 9 },
new Product { Name = "orange", Code = 4 },
new Product { Name = "apple", Code = 10 },
new Product { Name = "lemon", Code = 9 } };
var lstDistProduct = products.Distinct();
foreach (Product p in list1)
{
Console.WriteLine(p.Code + " : " + p.Name);
}
Will return all rows.
var list1 = products.DistinctBy(x=> x.Code);
foreach (Product p in list1)
{
Console.WriteLine(p.Code + " : " + p.Name);
}
will return 9 and 4
It doesn't seem to me that you need to use Distinct in this Linq query. Assuming you have the relationships between tables set up on your linq datacontext, you can do something like this:
var result = from s in context.Send
select new {
id = s.Id,
userId = s.UserId,
date = s.SendDate,
users = s.Receive.Select(u => u.UserName)
}
Note: users will an IEnumerable<String> - you can use string.Join() on the client to join the names into a string.
Update
To return users as a string to first need to 'switch' to Linq To Objects by calling AsEnumerable() or ToList() and the Linq to Sql query.
var output = from s in result.AsEnumerable()
select new {
id = s.id,
userId = s.userId,
date = s.date,
users = string.Join(", ", s.users)
}
Also see Gert Arnolds answer for a good explanation.
What you want can only be done in two steps. Not because of the DISTINCT, but because of the FOR XML. The C# equivalent of the latter is String.Join(), but you can't use that in a linq to entities statement directly. So you must collect the required data first, then switch to linq to objects (by applying AsEnumerable) and then do the concatenation and distinct:
db.Sends
.Where(s => s.Receivers.Any())
.Select(s => new {
s.Id,
Concatenated = s.Receivers.Select(r => r.UserName)
s.SendDate,
s.UserId
})
.AsEnumerable()
.Select(x => new {
s.Id,
Concatenated = String.Join(", ", x.Concatenated)
s.SendDate,
s.UserId
})
.Distinct()