BLToolkit equivalent of LoadWith from L2S - linq

When working with Linq to SQL you can use DataLoadOptions to specify which "child" objects to load. Is there a similar technique with BLToolkit?
It's nice that with BLT I can create the BO directly, like:
from p in db.Parent
select new Parent
{
ParentId = p.ParentId,
Child = p.Child
};
however going this route, while the entire Child object is created, I would need to specify every field in Parent (i.e. ParentId, ParentName, ParentDob, etc.)
Thanks.

Not exactly like LoadWith, but in my opinion the approach below is even better / cleaner (less magic). In your BO make a static function that would look like this:
public static Parent Build(Parent parent, Child child)
{
parent.Child = child;
return parent;
}
Now you'd need to write your LINQ query like this:
var query = from p in db.Parent
select Parent.Build(p, p.Child);
So rather than "select p" or "select new Parent()" we let the static function return "p" but also assign the Child object to "parent.Child" before returning. As long as your associations are setup properly (BLToolkit.Mapping.Association) p.Child would tell BLT to join to the Child table as well. You could go even further, i.e. p.Child.Friends.etc.

Related

Composable LINQ Select Clause

Is there a way to build on to the select clause of a previously defined LINQ query?
For example:
var stuffQuery =
from stuff in MyStuff
select new {
stuff.Name
};
var query2 =
from stuff in stuffQuery
join otherStuff in YourStuff on stuff.Name equals otherStuff.Name
select new {
stuff.*, // how can I accomplish this?
YourStuff = new {
otherStuff.PropertyX
}
};
The result I want is an object like:
string Name
anonymous YourStuff
string PropertyX
I thought about using a "Combine" method which would reflectively combine my two anonymous objects into a dynamic. But Linq-to-Sql won't know what to do with the method.
Instead, I think I need a method which returns the select expression. Its parameters would be the first Queryable, and the select expression for the second Queryable. Something like:
var query2 =
from stuff in stuffQuery
join otherStuff in YourStuff on stuff.Name equals otherStuff.Name
GetCombinedSelectClause(stuffQuery, new {
YourStuff = new {
otherStuff.PropertyX
}
});
How can I accomplish this? I'm not married to any particular syntax-style. However, I'd prefer not to use a string-based solution (such as System.Linq.Dynamic).
How about ExpandoObject? I believe it can do exactly what you need.
My question probably isn't worded the best it could be. However, I do not think LINQ queries were designed to accomplish the goal I was after.
I'm closing the question because I simply do not think the answer is achievable.

LINQ Select with multiple tables fields being writeable

I'm new to LINQ and I'm doing pretty well until now, but now stuck with this.
I've a LINQ object bounded to a DataGridView to let the user edit is contains.
for simple one table query, it go fine, but how to build a LINQ query with multiple table, so the result will still be read/write?
Here a example of what I mean:
GMR.Data.GMR_Entities GMR = new GMR.Data.GMR_Entities();
var dt = from Msg in GMR.tblMessages
join lang in GMR.tblDomVals on 1 equals 1//on Msg.pLangueID equals lang.ID
select Msg;
// select new {lang.DescrFr, Msg.Message,Msg.pLangueID } ;
this.dataGridView1.DataSource = dt;
In this simple query, if I return only "Msg" with the select statement, the grid can be edited. But if I replace the select statement with select new {lang.DescrFr, Msg.Message,Msg.pLangueID } ; the grid will be readable only.
I can easily understand that this is due because the query result is a anonymous type.
But is there a way to let the table tblMessage being writable?
try creating your own class, for example
public class MsgLangInfo
{
public string langDescFr{get;set;}
public int pLangueID{get;set;}
}
And at the select statement create an object of this class with new like below
select new MsgLangInfo {
langDescFr = lang.DescrFr,
langDescFr = Msg.Message,Msg.pLangueID
} ;
This way you can avoid the anonymous type problem.
You need to select the originals rows and explicitly set the grid columns.

LINQ - using a selected collection between methods/classes

After a lot of searching I wasn't able to find anything that clearly describes why I'm seeing this behavior (and I presume it's something very simple I'm missing - I'm still very much a beginner :)
I have a method (RefreshFilter) that takes an object (rfp) as a parameter. rfp has a property named 'Items' that is of type List.
I have 2 calls to RefreshFilter that look like this:
rfp = RefreshFilter(rfp, FilteredBy.Category)
rfp = RefreshFilter(rfp, FilteredBy.Industry)
Here is the RefreshFilter method:
public FilterParams RefreshFilterList(FilterParams rfp, FilteredBy filteredBy)
{
using (myEntity context as new myEntity())
{
itemsInCategory = (from i in context.items
join ic in context.ItemsCategories on i.Id equals ic.items.id
where ic.Categories.Id == '52'
select i).ToList<items>();
rfp.Items = rfp.Items.Intersect(itemsInCategory).ToList<items>();
}
return rfp;
}
The first call to RefreshFilter(...) works just fine and returns a FilterParams object with a .items property that contains an intersected list.
The second call to RefreshFilter(...) always returns a FilterParams object with a .items property containing an list of 0 elements (which is not expected since I know there are matching elements in the lists).
Through some testing, I believe I have been able to narrow this down to being related to the context that rfp.Items is set in. However I was always under the impression that the proper way to share collections between contexts was to select them into collection objects and pass these objects around, but it seems that these objects are still tied to their initial context in some way.
Thanks,
Try this:
public FilterParams RefreshFilterList(FilterParams rfp, FilteredBy filteredBy)
{
using (myEntity context as new myEntity())
{
itemIdsInCategory = (from i in context.items
join ic in context.ItemsCategories on i.Id equals ic.items.id
where ic.Categories.Id == '52'
select i.Id).ToList<int>();
rfp.Items = rfp.Items.Where(i => itemIdsInCategory.Contains(i.Id)).ToList<Item>();
}
return rfp;
}
Here we are only comparing the unique Ids of the items (int in this case) which could provide a performance benefit as well.

Linq - How to check if an object exists in database

I have an in memory List of objects. I want to check if each one exists in a database and if not, set a bool property on that object to true.
Object
class Part
{
public bool NewPart { get; set; }
public string PartNumber { get; set; }
public string Revision { get; set; }
public string Description { get; set; }
}
List contains the collection of parts. For each part, if it exists in the database then NewPart should be set to FALSE, else TRUE. I'm looking for the most efficient way to do this as there are likely to be hundred of parts so I'm thinking that running a SQL query for each part may not be the most efficient method.
Ideas on the best way to achieve this appreciated.
It depends on which ORM you are using, but with Linq2Sql you can use a query like:
var query = from p in db.parts
where myList.Contains(p.PartNumber)
select p.PartNumber;
You can then use the IEnumerable returned to set your newPart field
As an alternative, if your ultimate goal is to do an Upsert type action, then check out this question and its answers Insert Update stored proc on SQL Server (needs SQL level implementation, not linq)
The following will only hit the database once.
var myList = (from r in parts select r.PartNumber).ToList();
var existingParts = (from r in dc.Parts
where myList.Contains(r.PartNumber) select r.PartNumber).ToList();
foreach(var r in parts)
r.NewPart = existingParts.Contains(r.PartNumber);
Note, the generated sql could very well be something like
SELECT PartNumber
FROM Parts Where PartNumber in (#p0, #p1, #p2, #p3 .... )
so this should work if the parts list of a hundred or so, but not if it is over 2100.
This is one of those cases where the most efficient approach depends upon the actual data.
The first obtains all partNums from the database:
HashSet<int> partNums = new HashSet<int>(from p in GetTable<DBPart> select p.PartNumber);
foreach(var p in parts)
p.NewPart = partNums.Contains(p.PartNumber);
The second queries the database with the relevant partNumbers:
HashSet<int> partNums = new HashSet<int>(
from p in GetTable<DBPart> where (from mp in parts select mp.PartNumber).Contains(p.PartNumber) select p.PartNumber);
foreach(var p in parts)
p.NewPart = partNums.Contains(p.PartNumber);
The former will be more efficient above a certain number of rows in the database, and less efficient above it, because the latter takes a longer time to build a more complicated query, but the former returns everything.
Another factor is the percentage of hits expected. If this number is relatively low (i.e. only a small number of the parts in the list will be in the database) then it could be more efficient to do:
Dictionary<int, Part> dict = partsSource.ToDictionary(p => p.PartNumber, p);
foreach(int pn in
from p in GetTable<DBPart> where (from kv in dict select kv.Key).Contains(p.PartNumber) select p.PartNumber);
dict[pn].NewPart = true;
Where partsSource is the means by which the List parts was obtained in the first place, here instead of obtaining a list, we obtain a dictionary, which makes for more efficient retrieval of those we want. However, it we're going to obtain parts as a list anyway, then we can't really gain here, as we use slightly more effort building the dictionary in the first place, than iterating through the list.

When IQueryable is created from a linq query why is it not a "new" variable?

I am using the Entity Framework and have got a loop that looks at a set of People and using a foreach loop creates a query for the address of each person. As each address query is created it is added to the node of a treeview where it can be later used (to populate children nodes):
IQueryable<Person> pQuery = (IQueryable<Person>)myContext.People; //get a list of people
//go through and get the set of addresses for each person
foreach (var p in pQuery)
{
var addressQuery = from a in myContext.Addresses
from al in a.Address_Links
where al.P_ID == p.P_ID
orderby a.A_POST_CODE
select a;
//add the query to a TreeView node (use the tag to store it)
TreeNode newNode = new TreeNode();
newNode.Tag = addressQuery;
}
Now, the problem that I am finding upon running the app is that ALL the queries are the last query created i.e. the last iteration of the loop. It is like the addressQuery is created on the first iteration of the loop and then overwritten on each subsequent query. The result of this is that it is like all the address queries in the treenodes are references to the last query made(?)
Further investigation that I could solve the problem by using a static class to generate the address query and pass that into each the TreeNode, as follows:
public static class Queries
{
public static IQueryable<Address> AddressesForPerson(GenesisEntities myContext, int key)
{
var query = from a in myContext.Addresses
from al in a.Address_Links
where al.P_ID == key
orderby a.A_POST_CODE
select a;
return query;
}
}
The question I have is that I am baffled by this behaviour. Why does having a static query class help me? Can anyone explain to me what is going on?
Confused.Com!
The reason is that the p variable (the foreach loop variable) is captured and the query is evaluated lazily. As a result, when the query is actually run, it uses the current value of p variable at that time, which is the last value. Read my answer to "What is the exact definition of a closure?" for more info.
To solve the problem, simply try introducing a temporary variable:
// `loopVariable` is scoped inside loop body AND the loop declaration.
foreach (var loopVariable in pQuery)
{
var p = loopVariable; // This variable is scoped **inside** loop body.
var addressQuery = from a in myContext.Addresses
from al in a.Address_Links
where al.P_ID == p.P_ID
orderby a.A_POST_CODE
select a;
//add the query to a TreeView node (use the tag to store it)
myTreeView.Tag = addressQuery
}

Resources