sql "not in" in Linq using datatable - sql

How to convert sql query to linq using datatable.
select DISTINCT targeturl from internal where TargetURL NOT in (select DISTINCT url from Internal)
using this query, but still not getting the correct result.
var List1 = dt.AsEnumerable().Select(c => c.Field<string>("URL")).Distinct().ToList();
var List2 = dt.AsEnumerable().Select(c => c.Field<string>("TargetURL")).Distinct().ToList();
var Targetname = List2.Except(List1.ToList()).ToList();

You can also try populating an object then using the object to populate the datatable.
var data = Select(c => c.Field<string>("TargetURL")).Distinct().ToList();
Datatable dtMyTable = new Datatable();
dtMytable.Columns.Add("col1",typeof(string));
dtMytable.Columns.Add("col2",typeof(string));
dtMytable.Columns.Add("col3",typeof(string));
then populate the table
foreach (var item in data)
{
dtMytable.Rows.Add(data.col1,data.col2,data.col3);
}

I prefer to separate
first
dim query = (from u in Internal select u.url).distinct
Second
dim tmp = (from t in Interal where not query.contains(TargetURL) select TargetURL ).ToList
It's in VB.net but You can translate easily
And you can too distinct with group by request.

To write SELECT DISTINCT targeturl from internal where TargetURL NOT in (select DISTINCT url from Internal) in a linq lambda expression, you could use the following:
var result = Internal
.Select(a => a.TargetURL)
.Where(a => !Internal.Select(i => i.url).Distinct().Contains(a.TargetURL));
Or break it out a little as:
var distinctUrls = Internal.Select(i => i.url).Distinct();
var result = Internal.Select(a => a.TargetUrl)
.Where(a => !disctinctUrls.Contains(a.TargetUrl));
The above creates an IEnumerable of urls, which we use as an exclusion in the where predicate.

Related

Selecting an object from the GroupBy key

I'm accustomed to GroupBy() being more of an art than a science, but maybe someone can help me with a very specific problem:
Given the following code
var results = session.Query<MyClass>()
.GroupBy(c => c.OtherPersistentObject)
.Select(group => new
{
key = group.Key,
count = group.Count()
})
.ToList();
The generated query comes out like this:
/* [expression] */select
otherclass_.ID as col_0_0_,
cast(count(*) as INT) as col_1_0_,
otherclass_.ID as id1_1_,
otherclass_.START_DATE as start2_1_,
otherclass_.END_DATE as end3_1_,
otherclass_.Zone as zone9_1_
from
mytable mytable0_
left outer join
otherclass otherclass_
on mytable0_.otherID=otherclass_.ID
group by
mytable0_.otherID
which gives me the SQL error "Column 'otherclass .ID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause"
Is there a way to get the Select to do what I want?
TIA
It's a known NHibernate issue NH-3027.
As a workaround you can use last approach described in this answer (rewrite GroupBy part as sub-query). So your query can be rewritten to something like:
var results = session.Query<MyClass>()
.Where(c => c == session.Query<MyClass>().First(cs => cs.OtherPersistentObject == c.OtherPersistentObject))
.Select(x => new
{
key = x.OtherPersistentObject,
count = session.Query<MyClass>().Count(cs => cs.OtherPersistentObject == x.OtherPersistentObject)
}).ToList();
Try this:
var results = session
.Query<MyClass>()
.GroupBy(c => c.OtherPersistentObject)
.Select(group => new
{
key = group.Key.Id,
count = group.Count()
})
.ToList();
Here you can find the reason for the error.

How to pass subquery as table name to another query in yii2

I have a query which I am trying to convert into yii2 syntax. Below is the query
SELECT project_id, user_ref_id FROM
(
SELECT `project_id`, `user_ref_id`
FROM `projectsList`
WHERE user_type_ref_id = 1) AS a WHERE user_ref_id = '.yii::$app->user->id;
I am trying to convert it into yii2 format like
$subQuery = (new Query())->select(['p.project_id', 'p.user_ref_id'])->from('projectsList')->where(['user_type_ref_id' => 1]);
$uQuery = (new Query())->select(['p.project_id', 'p.user_ref_id'])->from($subQuery)->where(['user_ref_id ' => yii::$app->user->id])->all();
It is giving an error like
trim() expects parameter 1 to be string, object given
How to I pass subquery as table name to another query
Not tested, but generally this is how it goes. You need to pass the subQuery as a table. So change ->from($subQuery) in the second query to ->from(['subQuery' => $subQuery])
$subQuery = (new Query())->select(['p.project_id', 'p.user_ref_id'])->from('projectsList')->where(['user_type_ref_id' => 1]);
Then
$query = (new Query())->select(['p.project_id', 'p.user_ref_id'])->from(['subQuery' => $subQuery])->where(['subQuery.user_ref_id ' => yii::$app->user->id])->all();

Linq-to-NHibernate - How to do a Join with a SelectMany

Is it possible in Linq-to-NHibernate to do a Join with a SelectMany within the same query?
It might look weird, but the idea would be to generate the following query:
select * from State
join (
select CityId, StateId
from State
inner join City on State.StateId=City.StateId
) as City on City.StateId = State.StateId
The reason is that we are using a repository pattern and I do not want to use 2 different repository to do my join.
In code, I have tried the following block, but I get a not supported exception
var states = Session.Query<State>();
var query = states.Join(states.SelectMany(x => x.Cities), state => state.StateId,
city => city.State.StateId, (state, city) => new {state, city});
var result = query.ToArray(); // <- Throws a not supported exception
I have tried the same thing with two repositories and it works:
var states = Session.Query<State>();
var cities = Session.Query<City>();
var query = states.Join(cities , state => state.StateId,
city => city.State.StateId, (state, city) => new {state, city});
var result = query.ToArray(); // <- This works perfectly fine
Thanks in advance!
Ah! I found out that I wasn't thinking the right way. I can do the equivalent by starting with a SelectMany, then do a select of both.
This is supported and will do the same thing as a join but even more optimized:
var states = Session.Query<State>();
var query = states.SelectMany(x => x.Cities).Select(city => new {city.State, city});
var result = query.ToArray(); // It works!
And with that, I don't even need to get a repo of City.

LINQ to EF Using a Collection in a Where Clause

I have a main VendorProfile table and a 1-many VendorHistory table that contains status codes and date stamps. The query below works at retrieving only the latest status (status code and date) for each vendor. However, the view allows the user to select checkboxes of any of the status codes to filter the view. So I need to add a where clause that matches ANY of the checkbox StatusSelections.
Model Diagram
public IEnumerable<BrowseStatusModel> BrowseByStatus(int[] StatusSelections)
{
IQueryable<BrowseStatusModel> query = _db.VendorProfiles
.Include("VendorStatusHistory")
.Include("StatusCodes")
.Select(s => new BrowseStatusModel
{
ProfileID = s.ProfileID,
Name = s.Name,
CompanyName = s.CompanyName,
CompanyDBA = s.CompanyDBA,
DateCreated = s.DateCreated,
Status = s.VendorStatusHistories.OrderByDescending(o => o.DateCreated).FirstOrDefault().Id,
StatusDate = s.VendorStatusHistories.OrderByDescending(o => o.DateCreated).FirstOrDefault().DateCreated
})
.OrderBy(x => x.ProfileID);
foreach (int status in StatusSelections)
{
query = query.Where(x => x.Status == status);
}
return query;
}
The above foreach loop works but, unfortunately creates AND condition where ALL selections must be true instead of ANY. I figured I would have to use a where clause with the following in some way but have been unsuccessful at the correct syntax.
.AsQueryable().Any();
Use contains in the place of that foreach loop
query = query.Where(x => StatusSelections.Contains(x.Status))

SQL to Entity Framework Count Group-By

I need to translate this SQL statement to a Linq-Entity query...
SELECT name, count(name) FROM people
GROUP by name
Query syntax
var query = from p in context.People
group p by p.name into g
select new
{
name = g.Key,
count = g.Count()
};
Method syntax
var query = context.People
.GroupBy(p => p.name)
.Select(g => new { name = g.Key, count = g.Count() });
Edit: EF Core 2.1 finally supports GroupBy
But always look out in the console / log for messages. If you see a notification that your query could not be converted to SQL and will be evaluated locally then you may need to rewrite it.
Entity Framework 7 (now renamed to Entity Framework Core 1.0 / 2.0) does not yet support GroupBy() for translation to GROUP BY in generated SQL (even in the final 1.0 release it won't). Any grouping logic will run on the client side, which could cause a lot of data to be loaded.
Eventually code written like this will automagically start using GROUP BY, but for now you need to be very cautious if loading your whole un-grouped dataset into memory will cause performance issues.
For scenarios where this is a deal-breaker you will have to write the SQL by hand and execute it through EF.
If in doubt fire up Sql Profiler and see what is generated - which you should probably be doing anyway.
https://blogs.msdn.microsoft.com/dotnet/2016/05/16/announcing-entity-framework-core-rc2
A useful extension is to collect the results in a Dictionary for fast lookup (e.g. in a loop):
var resultDict = _dbContext.Projects
.Where(p => p.Status == ProjectStatus.Active)
.GroupBy(f => f.Country)
.Select(g => new { country = g.Key, count = g.Count() })
.ToDictionary(k => k.country, i => i.count);
Originally found here:
http://www.snippetsource.net/Snippet/140/groupby-and-count-with-ef-in-c
Here are simple examples of group-by in .NET Core 2.1:
var query = this.DbContext.Notifications
.Where(n => n.Sent == false)
.GroupBy(n => new { n.AppUserId })
.Select(g => new { AppUserId = g.Key, Count = g.Count() });
var query2 = from n in this.DbContext.Notifications
where n.Sent == false
group n by n.AppUserId into g
select new { id = g.Key, Count = g.Count()};
Both of these translate to:
SELECT [n].[AppUserId], COUNT(*) AS [Count]
FROM [Notifications] AS [n]
WHERE [n].[Sent] = 0
GROUP BY [n].[AppUserId]
with EF 6.2 it worked for me
var query = context.People
.GroupBy(p => new {p.name})
.Select(g => new { name = g.Key.name, count = g.Count() });