LINQ to SQL indirect variable - sql

First, may I apologise if this question is too basic for this forum. I am very new to this and am struggling with a number of basics - but am persevering!
I have a problem in that I want to create a LINQ to SQL query with a WHERE clause with an indirect reference to one of the columns in my database. For example, if I had some code that looked something like this:
var PLMatches = from PLMat in db1.PLAccountHeaders
where PLMat.CompanyAlphaId.Equals(CoId)
&& dbField.Equals(Limit)
select PLMat;
such that dbField would be a variable containing the name of the database field. So, if the value of dbField was"PLMat.ItemCode" it would happily go away and return all instances of records with an ItemCode equal to the value of Limit and if value of dbField was"PLMat.ItemName" it would happily go away and return all instances of records with an ItemName equal to the value of Limit and so on.
I would really appreciate some help on this both to answer a very specific problem and I am sure it will enhance my basic understanding.
Many thanks

i dont think that what you are asking for is possible in LINQ, you can however use the Dynamic Linq Library.
here's the link
You download the zip, unzip it and then just reference it in your solution.
you can then do something like this:
// the "normal" LINQ way:
var query = from x in ctx.People
where x.city == "Boston" && x.age > 18
orderby x.ID
select x;
// the Dynamic Linq way:
var query = database.People
.Where("city = Boston AND age > 18")
.OrderBy("id")
.Select("New(Person as Name, Age)");

Another way (besides dynamic linq) is composing your query conditionally. Like so:
var PLMatches = from PLMat in db1.PLAccountHeaders
where PLMat.CompanyAlphaId.Equals(CoId)
select PLMat;
if (dbField == "ItemCode")
PLMatches = PLMatches.Where(m => m.ItemCode == Limit);
else if (dbField == "ItemName")
PLMatches = PLMatches.Where(m => m.ItemName == Limit);
else if (dbField == ...
The code looks a bit repetitive, but I always prefer to do it this way if the number of possible conditions is not too large. The advantages are, first, that the code integrity check is at compile time and not at runtime (as with dynamic linq) and, second, it is very clear what the code is about. (The second advantage also goes for dynamic linq, but less so for a third alternative: building expressions in code).
You can compose linq queries this way because of deferred execution. PLMatches = PLMatches.Where... only changes the query, but nothing is executed yet.

Related

What is the Dump extension used for, and why is it so popular?

To me, adding "Dump" to the end of an expression doesn't seem to do anything different, at least for seeing rows in a table. Can you point me to an example of where it is handy?
If you are just working with an expression, there is no reason to call Dump—it's called automatically. But, in the language selection box, LINQPad allows allows the selection of Statements and Program. Once you select one of those, you don't get any Dump output unless you call it.
With Statements or Programs, you might want to call Dump on multiple times. In those cases, it is handy to pass the Description parameters so you can distinguish the output.
There are also other parameters you can use to shape the output, such as depth, which limits the substructure details.
Simple example (Language=C# Statements):
var integers = Enumerable.Range(1,10);
integers.Select(i => new { i, v = i * i}).Dump("Squares");
integers.Select(i => new { i, v = i * i * i}).Dump("Cubes");
var output = "λ is awesome";
Encoding.UTF8.GetBytes(output)
.Dump("UTF-8");
Encoding.GetEncoding("Windows-1252").GetBytes(output)
.Dump("Windows-1252 (lossy)");

How should I write an MDX Filter statement with multiple OR conditions efficiently?

In SQL you can compare a field against a set in the form
[Foo] In {"Bar1", "Bar2", ... , "BarN"}
However I'm having trouble working out how to move a filter expression into something like this. That is, for now, I end up with:
Filter(
[MyHierarchy].[Foo].Members,
[MyHierarchy].CurentMember.Name = "1"
OR [MyHierarchy].CurentMember.Name = "2"
...
OR [MyHierarchy].CurentMember.Name = "N"
)
Since I have 20-30 comparisons, and a moderate chance of the heirarchy name changing, I'd much rather maintain a set and a hierarchy name than a long expression. Is there any way to accomplish this?
Worth bearing in mind that the context is an Excel CubeSet function, so I'm a little limited in terms of defining my own members in the WITH clause.
Assuming you have a set named SelectedMembers, you could use
Intersect([MyHierarchy].[Foo].Members, [SelectedMembers])
You could of course also code this directly, i. e.
Intersect([MyHierarchy].[Foo].Members,
{
[MyHierarchy].[Foo].[1],
[MyHierarchy].[Foo].[2],
...
[MyHierarchy].[Foo].[N]
}
)
But it might be more convenient to have the set already defined in the cube calculation script - if that is possible.

Adding items to a listview in a specific order

If Not m_Batchs Is Nothing Then
For Each Batch In m_Batchs
newListItem = lstWsJobs.Items.Add(Batch.Id.ToString)
With newListItem
.Name = Batch.Id.ToString()
.SubItems.Add(Batch.JobId.ToString)
.SubItems.Add(Batch.Complete.ToString)
.SubItems.Add(Batch.User)
.SubItems.Add(Batch.Time.ToString)
End With
Next
End If
I have this list view (which is working fine) and i want to find an efficient way of populating it in a specific order, ie by date, by identity etc.
I know i can use linq but as i understand this is inefficient. If m_batchs is a large list of objects then i will looping through this list many, many time (as linq behind the scenes loops through the object collection).
Any ideas?
LINQ is not inefficient in general but almost always it's easier to read and faster to implement, change and extend. Also, does it really matter if one approach is 1 millisecond faster on 1000 iterations?
So i assume that Batch is a custom type and m_Batchs is a List<Batch>:
// order by date
var query = m_Batchs.OrderBy(b => b.Time);
// order by identity
query = m_Batchs.OrderBy(b => b.ID);
// ...
Measure the difference between this simple LINQ query and your custom implementation.
Edit: Sorry, that was C#
Dim batchByTime = m_Batchs.OrderBy(Function(b) b.Time);
Dim batchByID = m_Batchs.OrderBy(Function(b) b.ID);

Constructing a recursive compare with SQL

This is an ugly one. I wish I wasn't having to ask this question, but the project is already built such that we are handling heavy loads of validations in the database. Essentially, I'm trying to build a function that will take two stacks of data, weave them together with an unknown batch of operations or comparators, and produce a long string.
Yes, that was phrased very poorly, so I'm going to give an example. I have a form that can have multiple iterations of itself. For some reason, the system wants to know if the entered start date on any of these forms is equal to the entered end date on any of these forms. Unfortunately, due to the way the system is designed, everything is stored as a string, so I have to format it as a date first, before I can compare. Below is pseudo code, so please don't correct me on my syntax
Input data:
'logFormValidation("to_date(#) == to_date(^)"
, formname.control1name, formname.control2name)'
Now, as I mentioned, there are multiple iterations of this form, and I need to loop build a fully recursive comparison (note: it may not always be typical boolean comparisons, it could be internally called functions as well, so .In or anything like that won't work.) In the end, I need to get it into a format like below so the validation parser can read it.
OR(to_date(formname.control1name.1) == to_date(formname.control2name.1)
,to_date(formname.control1name.2) == to_date(formname.control2name.1)
,to_date(formname.control1name.3) == to_date(formname.control2name.1)
,to_date(formname.control1name.1) == to_date(formname.control2name.2)
:
:
,to_date(formname.control1name.n) == to_date(formname.control2name.n))
Yeah, it's ugly...but given the way our validation parser works, I don't have much of a choice. Any input on how this might be accomplished? I'm hoping for something more efficient than a double recursive loop, but don't have any ideas beyond that
Okay, seeing as my question is apparently terribly unclear, I'm going to add some more info. I don't know what comparison I will be performing on the items, I'm just trying to reformat the data into something useable for ANY given function. If I were to do this outside the database, it'd look something like this. Note: Pseudocode. '#' is the place marker in a function for vals1, '^' is a place marker for vals2.
function dynamicRecursiveValidation(string functionStr, strArray vals1, strArray vals2){
string finalFunction = "OR("
foreach(i in vals1){
foreach(j in vals2){
finalFunction += functionStr.replace('#', i).replace('^', j) + ",";
}
}
finalFunction.substring(0, finalFunction.length - 1); //to remove last comma
finalFunction += ")";
return finalFunction;
}
That is all I'm trying to accomplish. Take any given comparator and two arrays, and create a string that contains every possible combination. Given the substitution characters I listed above, below is a list of possible added operations
# > ^
to_date(#) == to_date(^)
someFunction(#, ^)
# * 2 - 3 <= ^ / 4
All I'm trying to do is produce the string that I will later execute, and I'm trying to do it without having to kill the server in a recursive loop
I don't have a solution code for this but you can algorithmically do the following
Create a temp table (start_date, end_date, formid) and populate it with every date from any existing form
Get the start_date from the form and simply:
SELECT end_date, form_id FROM temp_table WHERE end_date = <start date to check>
For the reverse
SELECT start_date, form_id FROM temp_table WHERE start_date = <end date to check>
If the database is available why not let it do all the heavy lifting.
I ended up performing a cross product of the data, and looping through the results. It wasn't the sort of solution I really wanted, but it worked.

dynamically varied number of conditions in the 'where' statement using LINQ

I'm working on my first project using LINQ (in mvc), so there is probably something very simple that I missed. However, a day of searching and experimenting has not turned up anything that works, hence the post.
I'm trying to write a LINQ query (Linq to SQL) that will contain a multiple number of conditions in the where statement separated by an OR or an AND. We don't know how many conditions are going to be in the query until runtime. This is for a search filter control, where the user can select multiple criteria to filter by.
select * from table
where table.col = 1
OR table.col = 2
OR table.col = 7
.... 'number of other conditions
Before I would just construct the SQL query as a string while looping over all conditions. However, it seems like there should be a nice way of doing this in LINQ.
I have tried looking using expression trees, but they seem a bit over my head for the moment. Another idea was to execute a lambda function inside the where statement, like so:
For Each value In values
matchingRows = matchingRows.Where(Function(row) row.col = value)
However, this only works for AND conditions. How do I do ORs?
I would use PredicateBuilder for this. It makes dynamic WHERE clauses very easy.
AND is easy - you can just call Where in a loop. OR is much trickier. You mention SQL, so I'm assuming this is something like LINQ-to-SQL, in which case one way I've found to do this involves building custom Expression trees at runtime - like so (the example is C#, but let me know if you need help translating it to VB; my VB isn't fantastic any more, so I'll let you try first... you can probably read C# better than I can write VB).
Unfortunately, this won't work with EF in 3.5SP1 (due to the Expression.Invoke), but I believe this is fixed in 4.0.
Something like this should work (forgive my VB):
Expression(Of Func(Of Something, Boolean)) filter = Nothing
ParameterExpression rowParam = Expression.Parameter("row", CType(Something))
For Each value In values
filterPart = Expression.Equal( _
Expression.Property(rowParam, "col"), _
Expression.Constant(value)))
If filter Is Nothing Then
filter = filterPart
Else
filter = Expression.OrElse(filter, filterPart)
End If
Next
If newPredicate IsNot Nothing Then
matchingRows = matchingRows.Where( _
Expression.Lambda(Of Func(Of SomeType, Boolean))(filter, rowParam))
End If
No guarantees, however, my VB is a little rusty :-)
But PredicateBuilder might be a better solution if you want to do more complicated stuff than just Ands and Ors.