How to skip repeated ids from table and select remains using linq - c#

In a table i have the following,
GroupId
3786
3787
3788
3788
So i need to take 3786, 3787 id's only. If i use distinct() it will take 3788 also. I don't know which method should use in linq.
IQueryable<Sub> subDetails=
from carSub in this.UnitOfWork.Repository<CarSub>().Queryable()
//from pcs in carSub.ConfirmedCarrier.CarrierCandidate.ProductCarrierScores
join p in this.UnitOfWork.Repository<ProductGroup>().Queryable() on carSub.Submission.PlacementID equals p.PlacementID
join pg in this.UnitOfWork.Repository<ProductGroupMember>().Queryable() on p.ProductGroupID equals pg.ProductGroupID
join pcs in this.UnitOfWork.Repository<ProductCarrierScore>().Queryable() on p.ProductGroupID equals pg.ProductGroupID
inside of that JOIN join pcs in this.UnitOfWork.Repository<ProductCarrierScore>().Queryable() on p.ProductGroupID equals pg.ProductGroupID here only i have to use this
pg means ProductGroupMember. in that Member i have to pass the only not repeated values only. Please guide me. I am stuck very much

i would make it like this:
Group them by GroupId;
Get only those which have 1 element in group;
The code will look like this:
var groupIds = subDetails.GroupBy(x=>x.GroupId).Where(x=>x.Count()==1).Select(x=>x.Key)
P.S. There might be some other faster solutions for this, but this is what came to mind first.

You can group by, then narrow down the results to items with count less than 2
For example,
var ids = new List<int> {1, 2, 3, 2, 5, 3, 4};
var itemsNotDuplicate = ids.GroupBy(f => f, t => t,
(k, items) => new {val = k, count = items.Count()}).Where(g => g.count < 2);

you can also you TakeWith
var list = new List<int> { 3786, 3787, 3788, 3788};
var onlyOne=list.TakeWhile(t=> list.Count(l=>l==t)==1);
its a similar approach to using GroupBy, but you only need to use a single lambda expression.

Related

SQL IN Operator to LINQ

I need this query to be translated to Linq query
SELECT DISTINCT (pf.Id)
FROM
PF pf
LEFT JOIN FA fa on pf.id = fa.PFId
LEFT JOIN Fan f ON pf.FId = f.Id
WHERE
pf.PId=2 AND fa.AId IN (1,26) AND fa.AId NOT IN(27)
This is the LINQ query I have so far as requested
var allFansSavedAsLeads = _dbContext.PF
.Where(e => e.F.S != null &&
e.A.Any(x => x.AId==27 &&
x.AId.Equals(1) /*&&
x.AId != 27*/) &&
e.PId == pId);
I get zero results with this.
I suggest you Create two lists of Ids representing the Activities that can be included and activities which needs to be excluded. use them like the following:
List<int> IncludedIds = new List<int>(){1,26};
List<int> ExcludedIds = new List<int>(){27};
_dbContext.ProfileFans.Where(e => e.Fan.SNUrl != null &&
e.Activities.Any(x => IncludedIds.Any(x.ActivityId) &&
!ExcludedIds.Any(x.ActivityId) &&
e.ProfileId == profileId);
Please note: I used List<int> because of the example that you are given, you have to create the lists based on the data type of ActivityId
You can create a temporary ActivityList AS
var List<int> ActivityList = new List<int>() {1, 26}
and use something like
ActivityList.Contains(x => x.ActivityId)
But see sujith's answer for a more complete solution.
You don't need a whitelist and a blacklist. It's either one or the other. So I'm making a whitelist. If the allowed ActivityId is 1 or 26, then by definition it is definitely not 27, so there is no need to try and exclude it. I'm using int[] instead of List<int> given that the whitelist is likely to be static, but feel free to change this to a List<int> if you want to dynamically modify it.
int[] whiteList = { 1, 26 };
var allFansSavedAsLeads = _dbContext.ProfileFans.Where(pf =>
pf.Fan.SNUrl.HasValue &&
pf.Activities.Any(fa => whiteList.Contains(fa.ActivityId)));
If you want the JOINs as well, you may want to look into .Include(), but from your original SQL query you seem like you're not going to actually need the contents of the joined tables.

How to Convert Linq to Lambda Expression

var getr = (from d in _context.DR
join r in _context.R on d.RID equals r.RID
where HID == r.HID && cI >= d.DRD && cO < d.DRD
group d by new {d.RID, d.RGID} into g
select g);
How to convert Linq to lambda? This is what I got:
var getr = _context.DR.Join(_context.R, x => x.RID, y => y.RID, (x, y) => new { R= x, DR= y}).Where(z => z.DR.RID== y.RID);
Are there any pros and cons of using either one?
In terms of performance : there is no performance difference whatsoever between two.
Which one should use is mostly personal preference, but its important to bear in mind that there are situation where one will be better suited the other.
int[] ints = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// using Query expression
var evensQuery = from i in ints where isEven(i) select i;
// using Lambda expression
var evensLambda = ints.Where(isEven);
There so many function that available with lambda ie. single(), First(), Take(), Skip()..
Although you can mix and match the two by calling the Lambda-only methods at the end of the query:
// mix and match query and Lambda syntax
//Example ver :1
var query = (from person in people
join pet in pets on person equals pet.Owner
select new { OwnerName = person.Name, Pet = pet.Name }).Skip(1).Take(2);
or, for better readability :
//Example ver :2
var query = from person in people
join pet in pets on person equals pet.Owner
select new { OwnerName = person.Name, Pet = pet.Name };
var result = query.Skip(1).Take(2);
Both example version return the same output without performance differences because of delayed(or Deferred ) execution, that means query is not executing at the point of declaration, but it will execute when try to iterate through the result variable.
BUT, if you don’t want delayed execution, or need to use one of the aggregate functions such as Average() or Sum(), for example, you should be aware of the possibility of the underlying sequence being modified between the assignments to query and result. In this case,I’d argue it’s best to use Lambda expressions to start with or add the Lambda-only methods to the query expression.

Linq to SQL, contains in where clause repeated values

I have a simple table of items, called "ITEMS":
id description
-- -----------
1 Something
2 Another thing
3 Best thing
I have a list of Int32 which are item IDs I'd like to show:
List<Int32> currentItemsCodes = new List<int>();
For this example currentItemsCodes contains 1,2,2,3
Currently I have this Linq-to-SQL:
var itemDescriptions = (from a in db.ITEMS
where currentItemsCodes.Contains(a.id)
select new {a.id, a.description});
What this returns is:
1,Something
2,Another thing
3,Best thing
I need to return two "Another things":
1,Something
2,Another thing
2,Another thing
3,Best thing
Or if currentItemsCodes was 3,3,3,3 I would need 4 x "Best thing" returned
You should do a inner join in linq to get what you are looking for. Use the below linq query to do that.
var itemDescriptions = (from a in db.ITEMS
join c in currentItemsCodes
on a.id equals c
select new {a.id, a.description});
You can use a join clause for that:
var itemDescriptions = (from item in db.ITEMS
join i in currentItemsCodes on item.id equals i
select new
{
id = item.id,
description = item.description
}).ToList();
Something like this?
var x = db.items;
var itemDescriptions = (from a in currentItemsCodes
select new {a, x[a].description});
As in Kris's comments substitute for [a] a method to access the items by id

How to do a WHERE...IN... clause in LinqToSql?

How can I select multiple elements using a WHERE...IN... type of clause as in
select * from orders where orderid in (1, 4, 5)
in LinqToSql? I'd prefer not to have a lambda expression since they scare me.
LINQ has "Contains" which is like "IN" but expressed the other way round - an element isn't "in" a set, a set "contains" an element.
int[] validIds = { 1, 4, 5 };
var query = from order in db.Orders
where validIds.Contains(order.Id)
select order
This is more simply expressed (IMO) with a lambda though:
int[] validIds = { 1, 4, 5 };
var query = db.Orders.Where(order => validIds.Contains(order.Id));
I realise lambdas are "new" and therefore scary to some extent, but it's really well worth grabbing hold of them with both hands. They're lovely.
int[] arry = new int[] {1,4,5};
var q = from r in orders
where Array.IndexOf(array, orderid) != -1
select r;
or
List<int> lst = new List<int>(new int[] {1,4,5});
var q = from r in orders
where lst.Contains(orderid);
select r;

Can take be used in a query expression in c# linq instead of using .Take(x)?

I'm trying to write some LINQ To SQL code that would generate SQL like
SELECT t.Name, g.Name
FROM Theme t
INNER JOIN (
SELECT TOP 5 * FROM [Group] ORDER BY TotalMembers
) as g ON t.K = g.ThemeK
So far I have
var q = from t in dc.Themes
join g in dc.Groups on t.K equals g.ThemeK into groups
select new {
t.Name, Groups = (from z in groups orderby z.TotalMembers select z.Name )
};
but I need to do a top/take on the ordered groups subquery. According to http://blogs.msdn.com/vbteam/archive/2008/01/08/converting-sql-to-linq-part-7-union-top-subqueries-bill-horst.aspx in VB I could just add TAKE 5 on the end, but I can't get this syntax to work in c#. How do you use the take syntax in c#?
edit: PS adding .Take(5) at the end causes it to run loads of individual queries
edit 2: I made a slight mistake with the intent of the SQL above, but the question still stands. The problem is that if you use extension methods in the query like .Take(5), LinqToSql runs lots of SQL queries instead of a single query.
Second answer, now I've reread the original question.
Are you sure the SQL you've shown is actually correct? It won't give the top 5 groups within each theme - it'll match each theme just against the top 5 groups overall.
In short, I suspect you'll get your original SQL if you use:
var q = from t in dc.Themes
join g in dc.Groups.OrderBy(z => z.TotalMembers).Take(5)
on t.K equals g.ThemeK into groups
select new { t.Name, Groups = groups };
But I don't think that's what you actually want...
Just bracket your query expression and call Take on it:
var q = from t in dc.Themes
join g in dc.Groups on t.K equals g.ThemeK into groups
select new { t.Name, Groups =
(from z in groups orderby z.TotalMembers select z.Name).Take(5) };
In fact, the query expression isn't really making things any simpler for you - you might as well call OrderBy directly:
var q = from t in dc.Themes
join g in dc.Groups on t.K equals g.ThemeK into groups
select new { t.Name, Groups = groups.OrderBy(z => z.TotalMembers).Take(5) };
Here's a faithful translation of the original query. This should not generate repeated roundtrips.
var subquery =
dc.Groups
.OrderBy(g => g.TotalMembers)
.Take(5);
var query =
dc.Themes
.Join(subquery, t => t.K, g => g.ThemeK, (t, g) => new
{
ThemeName = t.Name, GroupName = g.Name
}
);
The roundtrips in the question are caused by the groupjoin (join into). Groups in LINQ have a heirarchical shape. Groups in SQL have a row/column shape (grouped keys + aggregates). In order for LinqToSql to fill its hierarchy from row/column results, it must query the child nodes seperately using the group's keys. It only does this if the children are used outside of an aggregate.

Categories

Resources