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 :]
Related
I want to have Linq Query as below, but the not able to, its giving me compile time error any help please? The error is "inference failed to call the Join" - any help please? I want to use join within where clause of other query, is that possible?
Case _case = (from x in this.Context().CaseRepository.GetAll()
where (from g in x.Violations
join a in this.Context().OneToManyRepository.GetAll().Where(a => a.ParentEntity == "Notice" && a.ChildEntity == "Violation")
on new { g.ViolationId, this.NOVId } equals new { a.ChildEntityId, a.ParentId }
where g.CaseId == x.CaseId
select g).Count() > 0
select x).FirstOrDefault();
this.TriggerMetaDataUpdate<Case>(_case);
this.TriggerMetaDataUpdate<InspectionResult>(this.InspectionResult);
I did it in the following way:
var Violations = (from v in UnitOfWork.ViolationRepository.GetAll()
join a in UnitOfWork.OneToManyRepository.GetAll().Where(a => a.ParentEntity == "Notice" && a.ChildEntity == "Violation")
on v.ViolationId equals a.ChildEntityId
join b in UnitOfWork.OneToManyRepository.GetAll().Where(a => a.ParentEntity == "Notice" && a.ChildEntity == "Case")
on a.ParentId equals b.ParentId
where b.ChildEntityId == caseId
orderby v.ViolationId
select v).ToList();
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 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
};
This may look complicated, but I am really just trying to select all records and their children from A where certain conditions exist in their children. Looking for the syntax I can add to the A variable that allows me to filter a bunch of conditions (like a specification pattern?)
If you have a nested view like this:
var a = from Arow in Atable
where ???
select new AViewModel { // (image Products)
id = Arow.id,
name = Arow.Name,
Brows = (from Brow in Arow.Brows
select new BViewModel { // (sold in different regions)
id = Brow.id,
name = Brow.Name,
Crows = (from Crow in Brow.Crows
select new CViewModel { // (and in many stores)
id = Crow.id,
name = Crow.Name
}
}
};
And text representing queries from a web page like this (Specification Pattern?)
We used JQuery selectors for the operators (like ^= means "starts with")
filter[] = { "Brow.Name = Joe", "Crow.Name = Kim" }
How could you filter the expression A with those criteria? In other words, can you have a where expression like a.Where() that can filter nested properties?
My poor attempt:
var b = from row in a
where a.Brow.Where(b => b.name == "Joe") &&
a.Brow.Crow.Where(c => c.name == "Kim")
select row;
What I really need is something like this:
Select *
from A join B on A.key = B.key join C on B.key = C.key -- propagated keys
where exists (select null from B where A.key = B.key and B.Name = "Joe") and
exists (select null from C where A.key = C.key and C.Name = "Kim")
Especially if I can do this:
var result = a.Where(first).Where(second);
Your "poor attempt" isn't so far off. Just substitute Any() for Where():
var b = from row in a
where a.Brow.Any(b => b.name == "Joe") &&
a.Brow.Crow.Any(c => c.name == "Kim")
select row;
Edited to add:
You might want to do a case-insensitive comparison, though, e.g., .Any(b => b.name.Equals("Joe", StringComparison.CurrentCultureIgnoreCase)).
Or for fun, you can do the lambda equivilant:
var b = a.where(x => x.Brow.Any(b => b.name == "Joe")
&& x.Brow.Crow.Any( c => c.name == "Kim")
.Select(y => y.row);