Here's the DB setup of 3 tables:
Template
-----------
TemplateId (Pk Identity)
Name
Example Data:
TemplateId Name
1 Homepage
2 Generic Landing Page
TemplateArea (Bridge table to keep track of each template type's list of areas)
----------------
TemplateAreaId (Pk Identity)
TemplateId (Fk)
AreaId (Fk)
Example Data:
TemplateAreaId TemplateId AreaId
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
So every template has 3 areas (you're seeing a set of templateIds (e.g. 2) and related set of AreaIds (1 & 2))
Area
-----
AreaId (Pk Name)
Name
Example Data:
AreaId Name
1 Top
2 Middle
3 Bottom
I'm trying to get a list of Areas based on a list of TemplateAreas keyed off of AreaId in my list of TemplateAreas:
so for example I should get this list of content areas for a TemplateId 2:
AreaId Name
1 Top
2 Middle
int templateId = 2;
List<TemplateArea> templateAreas = TemplateAreas.Where(ta => ta.TemplateId == templateId).ToList();
List<Area> areas = Areas.Where()); // this is where I'm stuck, how to get the list of areas (1 & 2) relatd to templateId 2
so in other words, get a list of Template Areas then get a list of related Areas keyed off of the specific TemplateId.
I'm basically trying to join to TemplateArea from Area on TemplateArea.TemplateId = templateId or something like that if this were T-SQL, e.g. Something like:
select AreaId, Name from Area join TemplateArea on Area.AreaId = TemplateArea.AreaId where TemplateArea.TemplateId = templateId
Using your code approach as a guide, you can join to the templateAreas:
List<Area> areas = Area.Join(templateAreas, a => a.AreaId, t => t.AreaId, (a, t) => a);
Try This :
List<Area> areas = Areas.Where(ta => ta.TemplateId == templateId).Select(ta => ta.Areas).ToList();
you can access any of the area field using this..
How about:
List<Area> areas = TemplateAreas.Where(ta => ta.TemplateId == templateId).Select(ta => ta.Areas).Distinct().ToList();
I am pretty sure this would work in Entity Framework, just not sure in Linq to Sql.
Related
I guess there must be an easy way, but not finding it. I would like to check whether a list of items, appear (completely or partially) in another list.
For example: Let's say I have people in a department as List 1. Then I have a list of sports with a list of participants in that sport.
Now I want to count, in how many sports does all the people of a department appear.
(I know some tables might not make sense when looking at it from a normalisation angle, but it is easier this way than to try and explain my real tables)
So I have something like this:
var peopleInDepartment = from d in Department_Members
group d by r.DepartmentID into g
select new
{
DepartmentID = g.Key,
TeamMembers = g.Select(r => d.PersonID).ToList()
};
var peopleInTeam = from s in Sports
select new
{
SportID = s.SportID,
PeopleInSport = s.Participants.Select(x => x.PersonID),
NoOfMatches = peopleInDepartment.Contains(s.Participants.Select(x => x.PersonID)).Count()
};
The error here is that peopleInDepartment does not contain a definition for 'Contains'. Think I'm just in need of a new angle to look at this.
As the end result I would like print:
Department 1 : The Department participates in 3 sports
Department 2 : The Department participates in 0 sports
etc.
Judging from the expected result, you should base the query on Department table like the first query. Maybe just include the sports count in the first query like so :
var peopleInDepartment =
from d in Department_Members
group d by r.DepartmentID into g
select new
{
DepartmentID = g.Key,
TeamMembers = g.Select(r => d.PersonID).ToList(),
NumberOfSports = Sports.Count(s => s.Participants
.Any(p => g.Select(r => r.PersonID)
.Contains(p.PersonID)
)
)
};
NumberOfSports should contains count of sports, where any of its participant is listed as member of current department (g.Select(r => r.PersonID).Contains(p.PersonID))).
I have two tables, one contains entities other entitylog.
MyEntity:
id, lat, lon
A entity has a position in the world.
MyEntityLog:
id, otherid, otherlat, otherlon
Entity with id has interacted with otherid at otherid's latitude and longitude.
For instance, I have the following entities:
1, 4.456, 2.234
2, 3.344, 6.453
3, 6.234, 9.324
(not very accurate, but it serves the purpose).
Now, If entity 1 interact with 2 the result on the log table would look like:
1, 2, 3.344, 6.453
So my question is, how can I for listing entity 1's available interactions NOT include the ones on the log table?
The result of listing entity 1's available interactions should be only be entity 3 as it already has a interaction with 2.
First make a list of ids that interact with entity 1:
var id1 = 1;
var excluded = from l in db.EntityLogs
where l.id == id1
select l.otherid;
then find the entries not having an id in this list or equal to id1:
var logs= from l in db.EntityLogs
where !excluded.Contains(l.id) && l.id != id1
select l;
Note that linq will defer the execution of excluded and incorporate it in the execution of logs.
Not sure if I understand your question, I guess I need more details, but if you want to list the entities that have no entry in log table, one solution will be something like this, assuming myEntities is the collection of MyEntity and myEntityLogs is the collection of MyEntityLog
var firstList = myEntities.Join(myEntityLogs, a => a.Id, b => b.Id, (a, b) => a).Distinct();
var secondList = myEntities.Join(myEntityLogs, a => a.Id, b => b.OtherId, (a, b) => a).Distinct();
var result = myEntities.Except(firstList.Concat(secondList)).ToList();
var customer= from cust in customerData
select new Customer
{
CustomerID = cust["id"],
Name = cust["Name"],
LastVisit = cust["visit"],
PurchashedAmount = cust["amount"],
Tagged = cust["tagged"]
Code = cust["code"]
}
The rows looks like this
Name LastVisit PurchasedAmount Tagged Code CustomerID
------ --------- -------------- ------ ----- -----
Joshua 07-Jan-09 Yes chiJan01 A001
Joshua 10000
The 2nd row belongs to first row just that the other columns are empty.How can i merge the PurchasedAmount into the first row using LinQ?
This is probably a more general solution than you need - it will work even if the other values are scattered across rows. The main condition is that the Name column should identify rows that belong together.
customer = from c in customer
group c by c.Name
into g
select new Customer
{
Name = g.Key,
LastVisit = g.Select(te => te.LastVisit).
Where(lv => lv.HasValue).FirstOrDefault(),
PurchaseAmount = g.Select(te => te.PurchaseAmount).
Where(pa => pa.HasValue).FirstOrDefault(),
Tagged = g.Select(te => te.Tagged).
Where(ta => ta.HasValue).FirstOrDefault(),
Code = g.Select(te => te.Code).
Where(co => !string.IsNullOrEmpty(co)).FirstOrDefault(),
CustomerID = g.Select(te => te.CustomerID).
Where(cid => !string.IsNullOrEmpty(cid)).FirstOrDefault()
};
This will return a new IEnumerable with the items grouped by Name and the non-null values selected (same effect as moving PurchasedAmount to the first row and deleting the second in your case).
Note that the code is based on the assumption that LastVisit, PurchaseAmount and Tagged are nullable types (DateTime?, int? and bool?). Thus the usage of HasValue. If, however, they are strings in your case, you have to use !string.IsNullOrEmpty() instead (as for Code and CustomerID).
I have a T-SQL 2005 query which returns:
pid propertyid displayname value
----------- ----------- --------------- ---------------
14270790 74 Low Price 1.3614
14270790 75 High Price 0
14270791 74 Low Price 1.3525
14270791 75 High Price 0
14270792 74 Low Price 1.353
14270792 75 High Price 0
14270793 74 Low Price 1.3625
14270793 75 High Price 0
14270794 74 Low Price 1.3524
14270794 75 High Price 0
What I would like to do is essentially pivot on the displayname field, hopefully producing:
pid Low Price High Price
14270790 1.3614 0
14270791 1.3525 0
14270792 1.353 0
14270793 1.3625 0
14270794 1.3524 0
(Not sure how the propertyid field would be output, so I left it out (was hoping it would simply sit alongside the Low Price and High Price fields, to indicate their IDs, but I don't think that will work.)
The problem is that the content of the original displayname field is dynamic - it is produced from a join with a PropertyName' table, so the number of pivoted columns is variable. It could therefore containHigh Price,Low Price,OpenandClose`, depending on what the join with that table returns.
It is, of course, relatively easy (regardless of the trouble I'm having writing the initial query!) to produce this pivot in a fixed query or stored proc. However, is it possible to get LINQ to generate a SQL query which would name each column to be produced rather than having to write a dynamic (probably in a stored proc) query which lists out the column names?
Thanks,
Matt.
I'll give you a sample with a different data (that I needed). You can adapt that to your need. Note only two linq queries are used, most of the other fluff is to convert a list into a datatable.
var data = new[] {
new{Student=1, Subject="English", Marks=40},
new{Student=1, Subject="Maths", Marks=50},
new{Student=1, Subject="Science", Marks=60},
new{Student=1, Subject="Physics", Marks=70},
new{Student=1, Subject="Chemistry", Marks=80},
new{Student=1, Subject="Biology", Marks=90},
new{Student=2, Subject="English", Marks=4},
new{Student=2, Subject="Maths", Marks=5},
new{Student=2, Subject="Science", Marks=6},
new{Student=2, Subject="Physics", Marks=7},
new{Student=2, Subject="Chemistry", Marks=8},
new{Student=2, Subject="Biology", Marks=9}
};
/*Here the pivot column is the subject and the static column is student
group the data against the static column(s)*/
var groups = from d in data
group d by d.Student into grp
select new
{
StudentId = grp.Key,
Marks = grp.Select(d2 => new { d2.Subject, d2.Marks }).ToArray()
};
/*get all possible subjects into a separate group*/
var subjects = (from d in data
select d.Subject).Distinct();
DataTable dt = new DataTable();
/*for static cols*/
dt.Columns.Add("STUDENT_ID");
/*for dynamic cols*/
foreach (var subject in subjects)
{
dt.Columns.Add(subject.ToString());
}
/*pivot the data into a new datatable*/
foreach (var g in groups)
{
DataRow dr = dt.NewRow();
dr["STUDENT_ID"] = g.StudentId;
foreach (var mark in g.Marks)
{
dr[mark.Subject] = mark.Marks;
}
dt.Rows.Add(dr);
}
This is the closest I could get, but it's not LINQ...
create table #t
(
pointid [int],
doublevalue [float],
title [nvarchar](50)
)
insert into #t
select
distinct top 100
v.pointid, v.doublevalue, p.title
from [property] p
inner join pointvalue v on p.propertyid = v.propertyid
inner join point pt on v.pointid = pt.pointid
where v.pointid in (select top 5 p.pointid from point p where p.instanceid = 36132)
declare #fields nvarchar(250)
set #fields = (select STUFF((SELECT N',[' + title + ']' FROM [property] FOR XML PATH('')), 1, 1, N''))
--select #fields
declare #sql nvarchar(500)
set #sql = 'select * from #t
pivot
(
sum(doublevalue)
for [title] in ('+#fields+')
) as alias'
--select #sql
exec (#sql)
drop table #t
The kicker is that I'm simply asking for every entry in the Property table, meaning there's a lot of columns, in the resulting pivot, which have NULL values.
the code I think is like this:
var list = from table in Property
group table by table.pid into g
select new
{
pid = g.key,
LowPrice = g.Where(w => w.pid== g.key && w.priceType == "low").Select(s => s.value).FirstorDefault(),
HighPrice = g.Where(w => w.pid== g.key && w.priceType == "high").Select(s => s.value).FirstorDefault(),
};
Hope it can help you and have a nice day.
I'm quite new to LINQ.
Suppose that I had the following table:
Incident
ID DeviceID Time Info
1 1 5/2/2009 d
2 2 5/3/2009 c
3 2 5/4/2009 b
4 1 5/5/2009 a
In LINQ, how could I write a query that finds the most recent and distinct (on Device ID) set of incidents? The result I'd like is this:
ID DeviceID Time Info
3 2 5/4/2009 b
4 1 5/5/2009 a
Do you have to create an IEqualityComparer to do this?
You can get the most recent incidents for each device (this is how I understood your question) with:
var query =
incidents.GroupBy(incident => incident.DeviceID)
.Select(g => g.OrderByDescending(incident => incident.Time).First())
.OrderBy(i => i.Time); // only add if you need results sorted
int filterDeviceID = 10;
var incidents = (from incident in incidentlist
where incident.DeviceID == filterDeviceID
select incident).Distinct().OrderBy( x => x.Time);