I am retrieving simple LINQ query, but I am joining with two table and binding data with ListBox.
I am not able to properly show the item into the ListBox.
once I remove new item and select only keyword using it will work properly, but I want to join two table with select new key word it wil not allow to bind data with ListBox.
my code is like.
This will not allow to bind with ListBox.
var newPeople = (from p in clsGeneral.db.Table<SmartFXAttribes>()
join q in clsGeneral.db.Table<CategoryAttribes>() on p.catId equals q.ID
where p.catId == ((SmartFX.CategoryAttribes)((ComboBox)cmbPrintSize).SelectedValue).ID
select new
{
p.ID,
p.ImageHeight,
p.Imageoutline,
p.ImageUnit,
p.ImageWidth,
p.NoofPic,
p.TextboxCaption,
p.CanvasPixelHeight,
p.CanvasPixelWidth,
p.CanvasUnit,
p.catId,
q.FileName
}).ToList();
lstThumbnail.ItemsSource = newPeople;
This code will work fine.
var newPeople =
(from p in clsGeneral.db.Table<SmartFXAttribes>()
join q in clsGeneral.db.Table<CategoryAttribes>() on p.catId equals q.ID
where p.catId == ((SmartFX.CategoryAttribes)((ComboBox)cmbPrintSize).SelectedValue).ID
select p).ToList();
lstThumbnail.ItemsSource = newPeople;
Thanks!
The problem is that the first query creates an anonymous-typed object, but Silverlight cannot do data binding against an anonymous-typed object (anonymous types are internal and Silverlight's reflection capabilities do not allow accessing internal types from other assemblies). Your second query returns objects of a named type so it works just fine.
The best solution to this is to declare a public type containing public properties for everything you want to return from your first query and return an instance of that instead.
You can work around it with this hack, though.
Related
I have three tables, Chart, ChartQuestion, ChartAnswer
A Chart has many ChartQuestions, a ChartQuestion has many ChartAnswers.
I'd like to do a linq query that gives me an object containing all of this data, so it'd be a ChartObject containing List<ChartQuestion> and each ChartQuestion contains a List<ChartAnswer>
I started with this:
(from chart in db.Chart
join chartQuestion in db.chartQuestion on chart.ChartId equals chartQuestion.ChartId into chartQuestions)
This seems to be the first step. However I want to include the ChartAnswers now, so I have to do another join to pull back the ChartAnswers but I don't know how to do this.
I can't do a join, and while I can do a from, I am not sure of the exact syntax.
(from chart in db.Chart
join chartQuestion in db.chartQuestion on chart.ChartId equals chartQuestion.ChartId into chartQuestions
from chartQuestionsSelection in chartQuestions
join chartAnswer in context.ChartAnswers on chartQuestions.ChartAnswerId equals chartAnswer.ChartAnswerId into chartAnswers // This is wrong
)
With that code above you end up as chartAnswers being separate to the chartQuestions rather than belonging to them, so I don't think it is correct.
Any idea?
joining a table destructors it i.e. you now have the row as a variable if you need it in a nested fashion then select in like this
(from chart in db.Chart
select new { //can also be your own class/record, perhaps a DTO
chart.Id,
chart.Name,
questions = (from chartQuestion in db.chartQuestion
where chart.ChartId == chartQuestion.ChartId
select new { //perhaps a dto
chartQuestion.Id,
chartQuestion.Question,
Answers =
(from chartAnswer in context.ChartAnswers
where chartAnswer.ChartAnswerId == chartQuestion.ChartAnswerId
select chartAnswer).ToList() //this is translated and not evaluated
}).ToList() //this is translated not evaluated
}).ToListAsync(cancellationToken) //this will evaluate the expression
If you need it by joins then you can group join it like this:
from m in _context.Chart
join d in _context.ChartQuestions
on m.ID equals d.ID into mdJoin
select new
{
chartId = m.ID,
chartName = "m.name",
quess = from d in mdJoin
join dd in _context.ChartAnswer
on d.Iddomain equals dd.DomainId into anJoin
select new
{
quesId = d.ID,
quesName = d.Question,
anss = anJoin
}
}
A better way: If you edit your DbConfigurations to include navigation properties of each then the code will become way simpler.
example:
db.Chart
.Include(x => x.chartQuestions)
.ThenInclude(x => x.chartAnswers)
You can search more about how to do navigation properties in EFCore, but ofcourse if the code base is large then this might not be feasible for you.
Try following :
(from chart in db.Chart
join chartQuestion in db.chartQuestion on chart.ChartId equals chartQuestion.ChartId
join chartAnswer in context.ChartAnswers on chartAnswer.ChartAnswerId equals chartQuestion.ChartAnswerId
)
Trying to get a linq query (or lambda syntax) for the following SQL which Selects all "Data" which in the joining table have an Attribute equal to "blob".
EXCEPT: without explictly using the Join, but the
select data.*
from data
join settings on data.DataID = settings.DataID
where settings.Attribute = 'blob'
Explicitly defining the join
from d in dbcontext.Data
join s in dbcontext.Settings on d.DataID equals s.DataID
where s.Attribute == "blob"
select d
but is there a way to use the context dbcontext.Data.Settings
like the following?
from d in dbcontext.Data
where d.Settings.Attribute == "blob"
select d
Settings is a collection Type, so things like .Contains, and .Where come to mind.
using .Contains, my understanding is i would need to pass in an object type
where d.Settings.Contains(new Settings(d.DataID, "blob", null))
but i dont care about the null (Value) matching, just column Settings
some table structures
Data
DataID
Name
Settings
DataID
Attribute
Value
As I understand, you have Settings collection navigation property, so instead of explicit join you could simply use it ("navigate"):
from d in dbcontext.Data
from s in d.Settings
where s.Attribute == "blob"
select d
Alternatively you could use Any extension method which in this case is more appropriate than Contains (although Contains can also be used, but needs to be combined with Select):
dbcontext.Data.Where(d => d.Settings.Any(s => s.Attribute == "blob"))
For completeness, here is the Contains version:
dbcontext.Data.Where(d => d.Settings.Select(s => s.Attribute).Contains("blob"))
If I understand your question correctly, you want to create a LINQ that will grab any DataID that has an attribute of of "Blah" that is stored in another table.
If so this may work.
var dataIDs = Setting.Where(entry => entry.Attribute == "Blah")
.Select(entry => entry.DataID); // gets all DataIDs that match the attribute
var data = Data.Where(entry => entry.DataID in dataIDs); // gets data info based on DataIDs.
It should work, but what you should do instead is do an left join somewhat like
select a.*
from data a
left join settings b
on a.DataID = b.DataID
where b.Attribute = 'blob'
but in LINQ. This query would allow you to fetch all the data for DataIDs that match attribute 'blob. I haven't done it in LINQ so if someone more familiar with left joins with linq could respond that might work better
I have this query:
var allValues = from p in _pContext.Persons
where p.Id == currentPerson.Id
from i in p.Items //This is a list that contains "Items"
select i;
I want to have all the Items and all the nested values that they contain. How do I load these when executing this query, too? I know theres the include statement that I can use on the context, but that doesnt lead anywhere. If I f.e. do this:
var allValues = from p in _pContext.Persons.Include("Items.Properties")
where p.Id == currentPerson.Id
from i in p.Items //This is a list that contains "Items"
select i;
to get all the items loaded with their associated "Properties", these properties arent loaded, their list is instanciated but it doesnt contains any.
Include has lots of delusive quirks. One of them is that an Include is ignored if the query shape changes after it is applied. This happens in your case. The Inlude works if the query looks like this:
from p in _pContext.Persons.Include("Items.Properties")
select p
This is because the path "Items.Properties" is traversable off of the entity in the end result: Person.
But now you change the shape of the query by changing the returned entity...
from p in _pContext.Persons.Include("Items.Properties")
from i in p.Items
select i
... and the include path is no longer valid. (Not traversable off of Item).
For Include there's a simple rule of the thumb: apply it at the end of the query. Doing that, you'll automatically enter the correct path, esp. when you use lambda syntax:
(from p in _pContext.Persons
from i in p.Items
select i).Include("Properties")
or
(from p in _pContext.Persons
from i in p.Items
select i).Include(i => i.Properties)
I am projecting LINQ to SQL results to strongly typed classes: Parent and Child. The performance difference between these two queries is large:
Slow Query - logging from the DataContext shows that a separate call to the db is being made for each parent
var q = from p in parenttable
select new Parent()
{
id = p.id,
Children = (from c in childtable
where c.parentid = p.id
select c).ToList()
}
return q.ToList() //SLOW
Fast Query - logging from the DataContext shows a single db hit query that returns all required data
var q = from p in parenttable
select new Parent()
{
id = p.id,
Children = from c in childtable
where c.parentid = p.id
select c
}
return q.ToList() //FAST
I want to force LINQ to use the single-query style of the second example, but populate the Parent classes with their Children objects directly. otherwise, the Children property is an IQuerierable<Child> that has to be queried to expose the Child object.
The referenced questions do not appear to address my situation. using db.LoadOptions does not work. perhaps it requires the type to be a TEntity registered with the DataContext.
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Parent>(p => p.Children);
db.LoadOptions = options;
Please Note: Parent and Child are simple types, not Table<TEntity> types. and there is no contextual relationship between Parent and Child. the subqueries are ad-hoc.
The Crux of the Issue: in the 2nd LINQ example I implement IQueriable statements and do not call ToList() function and for some reason LINQ knows how to generate one single query that can retrieve all the required data. How do i populate my ad-hoc projection with the actual data as is accomplished in the first query? Also, if anyone could help me better-phrase my question, I would appreciate it.
It's important to remember that LINQ queries rely in deferred execution. In your second query you aren't actually fetching any information about the children. You've created the queries, but you haven't actually executed them to get the results of those queries. If you were to iterate the list, and then iterate the Children collection of each item you'd see it taking as much time as the first query.
Your query is also inherently very inefficient. You're using a nested query in order to represent a Join relationship. If you use a Join instead the query will be able to be optimized appropriately by both the query provider as well as the database to execute much more quickly. You may also need to adjust the indexes on your database to improve performance. Here is how the join might look:
var q = from p in parenttable
join child in childtable
on p.id equals child.parentid into children
select new Parent()
{
id = p.id,
Children = children.ToList(),
}
return q.ToList() //SLOW
The fastest way I found to accomplish this is to do a query that returns all the results then group all the results. Make sure you do a .ToList() on the first query, so that the second query doesn't do many calls.
Here r should have what you want to accomplish with only a single db query.
var q = from p in parenttable
join c in childtable on p.id equals c.parentid
select c).ToList();
var r = q.GroupBy(x => x.parentid).Select(x => new { id = x.Key, Children=x });
You must set correct options for your data load.
options.LoadWith<Document>(d => d.Metadata);
Look at this
P.S. Include for the LINQToEntity only.
The second query is fast precisely because Children is not being populated.
And the first one is slow just because Children is being populated.
Choose the one that fits your needs best, you simply can't have their features together!
EDIT:
As #Servy says:
In your second query you aren't actually fetching any information about the children. You've created the queries, but you haven't actually executed them to get the results of those queries. If you were to iterate the list, and then iterate the Children collection of each item you'd see it taking as much time as the first query.
I wrote my own object Tag and I would like to to contains if the .Value is found (I want to simulate WHERE IN like in SQL)
public static List<Question> GetQuestionsIdsWithTags(List<Tag> tags)
{
IEnumerable<Question> res = from t in dataClasses.tags
join
qt in dataClasses.question_to_tags on t.id equals qt.tag_id
join q in dataClasses.questions on qt.question_id equals q.id
where tags.Contains<Tag>(new Tag(t.name))
select new Question(q.text) { };
problem is, if the Contains is in the query, I get
The member 'Core.Literal.Value' has no supported translation to SQL.
Where Literal is the base of Tag.
What can I do?
You're trying to do new Tag(t.name), but this cannot be translated into SQL (the database server can't create new instances of your Tag class). Perhaps this would work:
IEnumerable<Question> res = from t in dataClasses.tags
join
qt in dataClasses.question_to_tags on t.id equals qt.tag_id
join q in dataClasses.questions on qt.question_id equals q.id
where tags.Select(x => x.name).Contains(t.name)
select new Question(q.text) { };
if tags is a List<string>, you should find that:
where tags.Contains(t.Name)
works fine; but there are limits to what it can understand (and more importantly, write as TSQL).
The LinQ Contains() statement can only be translated to SQL if it is performed by a List containing basic datatypes like int or string. If you need to cast your tags list to a List of strings or ints, then it should work.