I am trying to filter my dataset before I do join in Linq to Entities but I could not find the way to do it. My current linq query is that makes left joins is :
from m in Products
join f in FileFolders on m.ProductCode equals f.Name into list1
from l1 in list1.DefaultIfEmpty()
join p in Files on l1.FileFolderID equals p.FileFolderID into list2
// I want something like p.Name == "Test" here
from l2 in list2.DefaultIfEmpty()
join b in BaseReferenceFile on l2.BaseReferenceFileID equals b.BaseReferenceFileID into list3
from l3 in list3.DefaultIfEmpty()
select new
{
//select some stuff here
};
I want to filter Files collection such that only the files with name "Test" are joined with l1.
I have tried filtering on l2 with l2.Name == "Test" but it is not working. It generates a weird query with an inner join and a left join.
How can I do that?
join p in Files.Where(m => m.Name == "Test") on l1.FileFolderID equals p.FileFolderID into list2
I think this will work but this will query each time (for each record):
join p in (from f in Files where f.Name == "Test") on l1.FileFolderID equals p.FileFolderID into list2
its best to use where before select.
...from l3 in list3.DefaultIfEmpty()
where (l1 !=null ? l1.Name == "Test" : true)
select new
{
//select some stuff here
};
Related
I need to get NewsImage field and list of categories Ids that associated with the news in Many to Many relationship ... but it gives me error:
The type of one of the expressions in the join clause is incorrect.Type inference failed in the call to 'Join'.
My code looks like this
var Result1 = (from c in db.News
join d in db.Categories
on c.NewsId equals d.News.Select(l => l.NewsId)
where c.NewsId == 1
select new { c.NewsImagePath, d.CategoryId }).ToList();
Assuming you have a navigation property defining the n-n relation I would write:
var result = db.News
.Where(x => x.NewsId == 1)
.SelectMany(x => x.Categories,
(news, category) => new { news.NewsImagePath, category.CategoryId })
.ToList();
The problem is inside the on statement.
on c.NewsId equals d.News.Select( l => l.NewsId )
The Select on the right-hand side will return a IEnumerable of news, which is not what you want.
Something like this would technically work:
on c.NewsId equals d.News.Select( l => l.NewsId ).FirstOrDefault()
But it does not make sense logically.
I suspect the whole query should be built differently. I think you want to join when the category list of news contains the news item. In that case, you can't use the join statement, it would look somewhat like this:
from n in db.News
from c in db.Categories
where c.News.Select( ne => ne.NewsId ).Contains( n.NewsId )
select new { n.NewsImagePath, c.CategoryId }
I am creating a LINQ statement like following
from c2 in context.AspNetRoles
join c1 in context.RoleActions
on c2.Id equals c1.RoleId
where c2.UserId == System.Web.HttpContext.Current.User.Identity.GetUserId()
select new { c2.Name };
Notice that c2 appears first. The problem is the
c2.UserId
is not showing in intelligence. Is this a common behavior in LINQ. how can I fix the above LINQ statement, order is important?In where clause with join should have table identifier in the last in joining?
Thanks
If i understand you well...
You can mix standard notation of query with lambda. So, if you want to filter context.AspNetRoles then join context.RoleAction, you can try something like that:
var result = from c2 in context.AspNetRoles.Where(x=>x.Field=="SomeValue"
&& x.UserId == System.Web.HttpContext.Current.User.Identity.GetUserId())
join c1 in context.RoleActions on c2.Id equals c1.RoleId
select new { c2.Name };
Why join if you need only one value? Maybe try something like this:
var result = context.AspNetRoles
.Where(o => context.RoleActions.Any(oo => oo.RoleId == o.Id) &&
o.UserId == System.Web.HttpContext.Current.User.Identity.GetUserId())
.Select(o => o.Name)
.ToList();
I have the following LINQ query that works fine:
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
Now I want the query to only return those records where FieldValue equals to the value submitted from TextBox1
I have tried:
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
return View(comps);
and
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
comps=comps.Where(x => x.FieldValue== TextBox1);
return View(comps);
But neither returns any data. What am I doing wrong?
Update:
public ActionResult Index(string TextBox1)
{
if (TextBox1 != null)
{
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
return View(comps);
}
}
SOLVED! Answer is below! Not what I thought - reversing the table order in the query worked. Interesting pafr is that the query without a filter worked regardless of table order
The problem might be with what you think you are doing and what you actually do
You see as with most programing languages, in C# String is not value type but object, and the thing you are doing is actually comparing two adresses so to put it simply you check if the object in textBox1 is the same object you have as r.FildValue and what you really what to do is checking its contents, in C# each objeact has method Equals for comparing to other.
Try
where TextBox1.Equals(r.FieldValue)
The other think that you should check is if TextBox1 is value is correct
You can use System.Diagnostic.Debug.WriteLine("MyText" + TextBox1); to do that
Cheers :)
Hmmm, very strange. I was able to resolve the issue by switching the table order. Strangely the LINQ query worked fine when there was no filter but once filter was added - nothing. So I reversed the order of the tables and instead of
var comps = (from c in tc.companies
join r in tc.registry
on c.Key equals r.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
return View(comps);
used:
var comps = (from r in tc.registry
join c in tc.companies
on r.Key equals c.Key
where r.FieldValue==TextBox1
select new { FieldValue=r.FieldValue, Name=c.Name, Company=c.Company,Industry=c.Industry,Rank=c.Rank});
return View(comps);
and it worked like a charm!
I have two classes, Profile and Download. Download has the foreign key ProfileID which maps to the ID in Profile. Each row in Download represents one download for the connected profile.
I'm having trouble making a linq query that fetches a list of Profiles that is ordered in how many times it has been downloaded.
EDIT:
Here's what I have so far in the function.
IndexViewModel model = new IndexViewModel();
model.NewSubtitles = (from Profile in _ProfileRepo.GetAll()
orderby Profile.ID descending
select Profile).Take(5).ToList();
// This doesn't work:
// model.TopSubtitles = (from n in _ProfileRepo.GetAll()
// join d in _DownloadRepo.GetAll() on n.ID equals d.ProfileID into c
// group c by c.ProfileID into g
// orderby g.Count() descending
// select n).Take(5).ToList();
return View(model);
Try this :
model.NewSubtitles = (from Profile in _ProfileRepo.GetAll()
join downloads in _DownloadRepo.GetAll() on Profile.UserId equals downloads.UserId
group downloads by Profile into p
orderby p.Count() descending
select new {p.Key.UserId , p.Key.UserName , p.Count()).Take(5).ToList();
Have you tried something like :
from d in Downloads
orderby d.Profiles.Count()
...
?
Should do what you want:
model.TopSubtitles = (from p in _ProfileRepo.GetAll()
join d in _DownloadRepo.GetAll() on p.ID equals d.ProfileId
group d by p into g
orderby g.Count() descending
select g.Key).Take(5).ToList();
and for the LINQ syntax challenged:
model.TopSubtitles = _ProfileRepo.GetAll()
.Join(_DownloadRepo.GetAll(), p => p.ID, d => d.ProfileId, (p, d) => new { Profile = p, Download = d })
.GroupBy(x => x.Profile)
.OrderByDescending(g => g.Count())
.Select (g => g.Key)
.Take(5)
.ToList();
I have the following query:
from p in dataContext.Repository<IPerson>()
join spp1 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp1.PersonId
join s1 in dataContext.Repository<ISports>() on spp1.SportsId equals s1.Id
join spp2 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp2.PersonId
join s2 in dataContext.Repository<ISports>() on spp2.SportsId equals s2.Id
where s1.Name == "Soccer" && s2.Name == "Tennis"
select new { p.Id };
It selects all the person who play Soccer and Tennis.
On runtime the user can select other tags to add to the query, for instance: "Hockey". now my question is, how could I dynamically add "Hockey" to the query? If "Hockey" is added to the query, it would look like this:
from p in dataContext.Repository<IPerson>()
join spp1 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp1.PersonId
join s1 in dataContext.Repository<ISports>() on spp1.SportsId equals s1.Id
join spp2 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp2.PersonId
join s2 in dataContext.Repository<ISports>() on spp2.SportsId equals s2.Id
join spp3 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp3.PersonId
join s3 in dataContext.Repository<ISports>() on spp3.SportsId equals s3.Id
where s1.Name == "Soccer" && s2.Name == "Tennis" && s3.Name == "Hockey"
select new { p.Id };
It would be preferable if the query is build up dynamically like:
private void queryTagBuilder(List<string> tags)
{
IDataContext dataContext = new LinqToSqlContext(new L2S.DataContext());
foreach(string tag in tags)
{
//Build the query?
}
}
Anyone has an idea on how to set this up correctly?
Thanks in advance!
A LINQ query is not parsed until it is actually executed. So you can do stuff like this:
var q = from r in ctx.records
/* Do other stuff */
select r;
if (!string.IsNullOrEmpty(search)) {
q = from r in q
where r.title == search
select r;
}
if (orderByName) {
q = q.OrderBy(r => r.name);
}
/* etc */
this will create one SQL statement being executed.
For your specific question: The joins make it somewhat complicated, but I think you can join with other "dynamic" queries.
So you would end up with something like this:
var baseQ = from p in dataContext.Repository<IPerson>()
select p;
foreach(var tag in tags) {
baseQ = from p in baseQ
join spp1 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp1.PersonId
join s1 in dataContext.Repository<ISports>() on spp1.SportsId equals s1.Id
where s1.name == tag
select p;
}
/* If you have defined your relations correct, simplify to something like this.
Does not actually work because of SportsPerPerson probably has multiple sports: */
foreach(var tag in tags) {
baseQ = baseQ.Any(p => p.SportsPerPerson.Sports.Name == tag);
}
var resultQ = from p in baseQ
select new { p.Id };
Me and my colleague have found the solution, and we refactored the query so it would work properly. We now use the following query to retrieve the correct resultset:
var query = dataContext.Repository<ILead>();
foreach (var tag in tags)
{
String tagName = tag;
query = query.Where(l => dataContext.Repository<ISportsPerPerson>()
.Any(tpl => tpl.PersonId.Equals(l.Id) && tpl.Sports.Name.Equals(tagName)));
}
// Do something with query resultset :]