Linq to Sql - Use sum in the where clause - linq-to-sql

I'm trying to select orders that have either over or under 2000 products ordered in them, depending on other values. I need to select the information from the Orders table, but check this value in the OrdersProducts table, specifically the sum of OrdersProducts.ProductQty. I also need to do this using predicate builder, because of other requirements. So far, I have this, but it isn't returning the results correctly. Its using nested Lambda expressions, which I didn't know I could do but I tried it and it works, but its not returning correct results.
Dim getOrders = From d In db.Orders _
Where d.Status = OrderStatus.Approved _
Select d
' Then a for loop adding parameters via Predicatebuilder...
If over2000 = True Then
' over 2000
predicate1 = predicate1.And(Function(d) (d.OrderProducts.Sum(Function(c) c.ProductQty > 2000)))
Else
' under 2000
predicate1 = predicate1.And(Function(d) (d.OrderProducts.Sum(Function(c) c.ProductQty < 2000)))
End If
basePredicate = basePredicate.Or(predicate1)
' End For loop
getOrders = getOrders.Where(basePredicate)
I removed some code for brevity but I think that gets the point across. How can I do this?? Thanks!

Try changing this:
(d.OrderProducts.Sum(Function(c) c.ProductQty > 2000))
to this:
(d.OrderProducts.Sum(Function(c) c.ProductQty) > 2000)
I haven't built this to test it, but it appears that it was currently trying to sum the results of a boolean comparison instead of summing the quantities and then comparing.

Related

Why did this query change work?

I ended up scrapping the part of the WHERE clause that was giving me issues, but initially I got this query working by doing something that didn't make sense to me at all, and was hoping someone could shine some light on what is going on here. The entire query and function are below, but I'm not sure all of that is necessary
So this query was previously working and this WHERE clause is still being used successfully in another query. Now multiple functions are used in this line of the where clause, however if I just use the portion starting with ModifiedStartDate the query works fine. So it seems like the issue is with ModifiedDate. The portion of the WHERE clause that was giving us issues was:
and ModifiedDate(r.EXPIRATION_DATE, ModifiedStartDate(r.COMMENCEMENT_DATE,
PaySched_MaxFreq(r.RE_CONTRACT_KEY))) > #1/1/2019#
The query was failing with the error "Data type mismatch in criteria expression". So just doing some testing I ended up adding the following portion to the WHERE clause:
and r.RE_CONTRACT_KEY NOT IN (1)
And then the query worked?!?! I really don't get how adding this line magically resolved a data type mismatch error. There is no RE_CONTRACT_KEY = 1 so it's not bad data or something.
I did some testing and took the ModifiedDate function and put that into the select clause and it worked fine. I also added another field to the SELECT clause using the DATEADD function to make sure the function result was still being treated as a date, and it was. Query is below and the function is below that.
SELECT DISTINCT ....
FROM ((((((PAYMENT_LINE_ITEM AS pli
INNER JOIN PAYMENT_SCHEDULE AS tps ON pli.PAYMENT_SCHEDULE_KEY =
ps.PAYMENT_SCHEDULE_KEY)
INNER JOIN RECONTRACT AS r ON pli.RE_CONTRACT_KEY = r.RE_CONTRACT_KEY)
INNER JOIN Conversion_ProductCategory AS cpc ON cpc.Value = pli.PAYMENT_TYPE)
INNER JOIN ManualEntry AS me ON me.LeaseID = r.RE_CONTRACT_ID)
LEFT JOIN Mapping_CostCenter AS mcc ON mcc.CostCenter = me.CostCenter)
INNER JOIN PIW_Exclusions AS pe ON pe.RE_CONTRACT_ID = r.RE_CONTRACT_ID)
LEFT JOIN FacilityCode_Address_xRef AS fca ON fca.[Facility Code] =
mcc.placecode & "-" & mcc.placecodedescription
WHERE pli.PAYMENT_TYPE in ("rent","storage","parking")
and ModifiedDate(r.EXPIRATION_DATE,
ModifiedStartDate(r.COMMENCEMENT_DATE,
PaySched_MaxFreq(r.RE_CONTRACT_KEY))) > #1/1/19#
and PE.Reason = "rent extension"
and r.RE_CONTRACT_KEY NOT IN (1) 'New line added that made query work
And the function:
Public Function ModifiedDate(DateToModify As Date, DateToCompare As Date) As
Date
Select Case DateToModify
Case #2/28/2000#, #2/28/2004#, #2/28/2008#, #2/28/2012#, #2/28/2016#,
#2/28/2020#, #2/28/2024#, #2/28/2028#, #2/28/2032#, #2/28/2036#, #2/28/2040#,
#2/28/2044#, #2/28/2048#
DateToModify = DateAdd("d", 1, DateToModify)
End Select
If DatePart("d", DateAdd("d", 1, DateToModify)) = DatePart("d",
DateToCompare) Then
ModifiedDate = DateAdd("d", 1, DateToModify)
Else
ModifiedDate = DateToModify
End If
End Function
If you're curious the final working WHERE clause is:
WHERE pli.PAYMENT_TYPE in ("rent","storage","parking")
and r.EXPIRATION_DATE > #1/1/19#
and PE.Reason = "rent extension"

How to implement a more efficient search feature?

In my database there are 3 column which is Name, Age, Gender.
In the program, I only want to use 1 search button. When the button is clicked, the program determine which 3 of the textbox has input and search for the right data.
How do you work with the query? For example if Name and Gender has text, the query :
"Select * from table Where (Name = #name) AND (Gender = #gender)"
And when only name is entered, I only query for the name. Must I check textbox by textbox whether there is user input and then write multiple query for each of them? Or is there a better way to do this?
Edit (29/5/16) : I tried doing this another way like this
myCommand = New MySqlCommand("Select * from project_record Where
(FloatNo = #floatNo OR FloatNo = 'None') AND
(DevCompanyName = #devCompanyName OR DevCompanyName = 'None') AND
(DevType = #devType OR DevType = 'None') AND
(LotPt = #lotPt OR LotPt = 'None') AND
(Mukim = #mukim OR Mukim = 'None') AND
(Daerah = #daerah OR Daerah = 'None') AND
(Negeri = #negeri OR Negeri = 'None') AND
(TempReference = #tempRef OR TempReference = 'None')", sqlConn)
But as you can guess already it will not work efficiently as well because if I only enter input for DevType and leave other textboxes blank, the query will not pull up all the records for DevType only. It will just display as no records.
Select * from table
Where (Name = #name OR #name is Null)
AND (Gender = #gender OR #gender is Null)
...
it should be one query
Other answers have explained how to simplify the query. It is especially important to get rid of the ORs, since they inhibit any use of indexes.
Once you have the query build cleanly, you need to think about the dataset and decide which columns are usually used for filtering. Then make a few INDEXes for them. You won't be able to provide 'all' possible indexes, hence my admonition that you think about the dataset.
When building indexes, you can have single-column or multiple-column indexes. For your type of data, I would suggest starting with several 2-column indexes. Make sure each index starts with a different column.
For Where (Name = #name) AND (Gender = #gender), here are some notes:
INDEX(gender) is useless because of low 'cardinality';
INDEX(gender, name) might be useful, but the following would be better:
INDEX(name)
Things like name and DevCompanyName are virtually unique, so a 1-column index is probably good.
If you had gender and age, then INDEX(age, gender) might be useful.
MySQL will almost never use two indexes for a single SELECT.
By the way, the construction of the WHERE could be done in a Stored Procedure. You would need CONCAT, PREPARE, etc.
Original answer
(scroll down to see update)
Can you try the following:
build a list only including values of the textboxes that have an input
set a string of the join the items of that list together with the " AND " string
append that string to your standard SELECT statement
The code looks like this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim Predicate1 As String = Me.TextBox1.Text
Dim Predicate2 As String = Me.TextBox2.Text
Dim Predicate3 As String = Me.TextBox3.Text
Dim PredicateList As New List(Of String)
Dim WhereClause As String
Dim Query As String
If Predicate1 <> String.Empty Then
PredicateList.Add("Name=""" & Predicate1 & """")
End If
If Predicate2 <> String.Empty Then
PredicateList.Add("Age=""" & Predicate2 & """")
End If
If Predicate3 <> String.Empty Then
PredicateList.Add("Gender=""" & Predicate3 & """")
End If
WhereClause = String.Join(" AND ", PredicateList.ToArray)
Query = "SELECT * FROM TABLE WHERE " & WhereClause
MessageBox.Show(Query)
End Sub
Update
Further to the comments re SQL injection, here is an updated sample.
Dim Command As SqlClient.SqlCommand
Dim Predicate1 As String = Me.TextBox1.Text
Dim Predicate2 As String = Me.TextBox2.Text
Dim Predicate3 As String = Me.TextBox2.Text
Dim ParameterList As New List(Of SqlClient.SqlParameter)
Dim PredicateList As New List(Of String)
Dim BaseQuery As String = "SELECT * FROM TABLE WHERE "
If Predicate1 <> String.Empty Then
PredicateList.Add("name = #name")
ParameterList.Add(New SqlClient.SqlParameter("#name", Predicate1))
End If
If Predicate2 <> String.Empty Then
PredicateList.Add("age = #age")
ParameterList.Add(New SqlClient.SqlParameter("#age", Predicate2))
End If
If Predicate3 <> String.Empty Then
PredicateList.Add("gender = #gender")
ParameterList.Add(New SqlClient.SqlParameter("#gender", Predicate3))
End If
Command = New SqlClient.SqlCommand(BaseQuery & String.Join(" AND ", PredicateList.ToArray))
Command.Parameters.AddRange(ParameterList.ToArray)
COALESCE is your friend here. You can use it to make the where clause ignore comparisons where the parameter is NULL.
Select * from table Where (Name = COALESCE(#name,table.Name))
AND (Gender = COALESCE(#gender,table.Gender))
So, if the #name parameter is NULL, COALESCE(#name,table.Name) will return the value of the 'Name' column of the current row and (Name = COALESCE(#name,table.Name)) will always be true.
This assumes that if no value is entered in a textbox the corresponding parameter will be NULL. If instead it is a value such as 'None', you can use the NULLIF function to map 'None' to NULL
Select * from table Where
(Name = COALESCE( NULLIF( #name, 'None'), table.Name))
AND (Gender = COALESCE( NULLIF( #gender, 'None'), table.Gender))
How to implement a more efficient search?
The answer partly depends on what your definition of efficient is. I suspect you mean less code and fewer if blocks etc. But fundamentally, running a new SELECT * query to apply a filter is inefficient because your base data set can be all the rows and you just fiddle with the users View of it.
I have a DB with random data in columns for Fish, Color (string), Bird, Group (int) and Active which should be similar enough for Name, Age and Gender in the question - or that other long thing at the bottom.
DataTable
Fill a datatable and bind it to a DGV:
' form level object
Private dtSample As DataTable
...
' elsewhere
Dim sql = "SELECT Id, Name, Descr, `Group`, Fish, Bird, Color, Active FROM Sample"
Using dbcon As MySqlConnection = New MySqlConnection(MySQLConnStr)
' create SELECT command with the Query and conn
Dim cmd As New MySqlCommand(sql, dbcon)
...
daSample.Fill(dtSample)
daSample.FillSchema(dtSimple, SchemaType.Source)
End Using
dgv2.DataSource = dtSample
Going forward, we can filter the user's view of that table without issuing a new query.
Filter Controls
If some of the fields are limited to certain selections, for instance Gender, you can use a ComboBox instead of a TextBox. This is to help the user succeed and avoid typos (Make or Mael instead of Male; or here, correctly spelling Baracuda I mean Baraccuda, er Barracuda correctly.
For illustration purposes, Fish is something where the user can type in anything at all, but Bird is constrained to a set of choices. If there is a Bird table, cboBird can be bound or populated from it. But you may also be able to populate it from the master/base table:
Dim birds = dtSample.AsEnumerable.Where(Function(d) d.IsNull(5) = False).
Select(Function(d) d.Field(Of String)("Bird")).
Distinct.
ToArray()
cboBird.Items.AddRange(birds)
If "Finch" is a legal choice but there are none in the database, it wont show in the list. Depending on the app, this can be a Good Thing:
If the user filters on Finch and there a no resulting records, you won't need a MessageBox or StatusBar message explaining the empty result set.
If something is not in the list, you are signalling up front that there are none of those. It then becomes a matter of training why a known element isnt in the list.
On the other hand, you'd have to repopulate those filter controls each time before they are used in case new records were added recently. If the controls are on a Dialog or different TabPage, this is easy to do as needed.
It isnt always applicable, but it can help the user avoid typos.
It depends on the app whether either method is of value.
DBNull / 'none'
I am not sure why you are adding 'none' to each clause. If someone want to see all the 'John` or all the 'Cod' records, it doesn't seem like they would also be interested in 'none'. Personally, Null/DBNull seems a better way to handle this, but it is easy to add or not add either form.
It would seem more valuable to filter to just those with DBNull/None. The code above for the Bird List filters out DBNull and I would do so for none as well. Then, before the result is added to the ComboBox, add a `None' item first so it is at the top.
Again it depends on what the app does; Or = 'None', may make perfect sense in this case.
Filter
Using a TextBox for Fish and Group, a ComboBox for Bird and Color and a CheckBox for Active, the code can form the filter thusly:
Dim filterTerms As New List(Of String)
Dim filterFmt = "{0} = '{1}' "
' OR:
' Dim filterFmt = "{0} = '{1}' OR {0} Is Null"
' OR:
' Dim filterFmt = "{0} = '{1}' OR {0} = 'none'"
If String.IsNullOrEmpty(tbSearchFish.Text) = False Then
Dim txt = tbSearchFish.Text.Replace("'", "''")
filterTerms.Add(String.Format(filterFmt, "Fish", txt))
End If
If cboBird.SelectedIndex > -1 Then
filterTerms.Add(String.Format(filterFmt, "Bird", cboBird.SelectedItem.ToString))
End If
If String.IsNullOrEmpty(tbGroup.Text) = False Then
Dim n As Int32
If Int32.TryParse(tbGroup.Text, n) Then
filterTerms.Add(String.Format(filterFmt, "[Group]", n))
End If
End If
If cboColor.SelectedIndex > -1 Then
filterTerms.Add(String.Format(filterFmt, "Color", cboColor.SelectedItem.ToString))
End If
If chkActive.Checked Then
' NOTE: I do not have TreatTinyAsBoolean turned on
' for some reason
filterTerms.Add(String.Format(filterFmt, "Active", "1"))
End If
If filterTerms.Count > 0 Then
Dim filter = String.Join(" AND ", filterTerms)
dtSample.DefaultView.RowFilter = filter
Dim rows = dtSample.DefaultView.Count
End If
Use whichever filterFmt is appropriate for what the app needs to do
A filter term is only added to the list if the related control has a value (as per above, this could include a 'None').
For the TextBox, it escapes any embedded ticks such as might be found in names like O'Malley or D'Artgnan. It replaces one tick with two.
Since Group is a numeric, a valid Int32 input is tested
If there are elements in the filterTerms list, a filter string is created
The filter is applied to the DefaultView.Filter (you can use also use a DataView or a BindingSource) so that the code need not query the database to provide filter capabilities.
Rows will tell you how many rows are in the current View.
The only halfway tricky one is a Boolean like Gender or Active because those actually resolve to three choices: {Any/Either, A, B}. For that, I would use a ComboBox and ignore it for SelectedIndex 0 as well. I didn't bother with this because the Combo concept is amply covered. Result:
Is it More "Efficient"?
It still depends.
It doesn't re-query the database to get rows the app can already have.
No new DBConnection, DBCommand or other DBProvider objects are created, just a list.
No need to dynamically create a SQL statement with N parameters in a loop to avoid SQL injection/special words and chars.
It doesn't even query the database for the items for the filter terms. If there is a static list of them in the DB, they could be loaded once, the first time they use the filters.
It is easy to remove the filter, no need to query yet again without WHERE clauses.
A ComboBox where applicable helps the user find what they want and avoid typos.
Is the SQL "cleaner". more "efficient? The code doesn't really mess with new SQL, just some WHERE clauses.
Is there less code? I have no idea since we just see the result. It doesnt string me as a lot of code to do what it does.
In my database there are 3 column which is Name, Age, Gender. In the program, I only want to use 1 search button. When the button is clicked, the program determine which 3 of the textbox has input and search for the right data.
And when only name is entered, I only query for the name. Must I check textbox by textbox whether there is user input and then write multiple query for each of them? Or is there a better way to do this?
SELECT * FROM `table`
WHERE (`name` = #name AND `name` IS NOT NULL)
OR (`age` = #age AND (`age`>0 OR `age` IS NOT NULL))
OR (`gender` = #gender AND `gender` IS NOT NULL);
With the above query if all text boxes have value, the result will not be one record (as if you where using logical AND between fields). If you want only that record you will filter it server-side with php from the rest of the results.
You can check the results on your own in this Fiddle
EDIT
In order to solve the above inconvenience (not bringing easily single results when needed) i got a little help from this answer and re-wrote the above query as:
SELECT *, IF(`name`=#name, 10, 0) + IF(`age`=#age, 10, 0) + IF(`gender`=#gender, 10, 0) AS `weight`
FROM `table`
WHERE (`name` = #name AND `name` IS NOT NULL)
OR (`age` = #age AND (`age`>0 OR `age` IS NOT NULL))
OR (`gender` = #gender AND `gender` IS NOT NULL)
HAVING `weight`=30;
OR to still get all records with a weight on result
SELECT *, IF(`name`=#name, 10, 0) + IF(`age`=#age, 10, 0) + IF(`gender`=#gender, 10, 0) AS `weight`
FROM `table` WHERE (`name` = #name AND `name` IS NOT NULL)
OR (`age` = #age AND (`age`>0 OR `age` IS NOT NULL))
OR (`gender` = #gender AND `gender` IS NOT NULL)
ORDER BY `weight` DESC;
You were pretty close. Let's look at
(FloatNo = #floatNo OR FloatNo = 'None')
So you want the field either to be the given input or 'None'? But there are (supposedly) no records in your table with FloatNo 'None'. What you really want to do is find out whether the input is none (i.e. empty):
(FloatNo = #floatNo OR #floatNo = '')
And for the case the user types in a blank by mistake, you can ignore this, too:
(FloatNo = #floatNo OR TRIM(#floatNo) = '')
The whole thing:
myCommand = New MySqlCommand(
"Select * from project_record Where
(FloatNo = #floatNo OR TRIM(#floatNo) = '') AND
(DevCompanyName = #devCompanyName OR TRIM(#devCompanyName) = '') AND
(DevType = #devType OR TRIM(#devType) = '') AND
(LotPt = #lotPt OR TRIM(#lotPt) = '') AND
(Mukim = #mukim OR TRIM(#mukim) = '') AND
(Daerah = #daerah OR TRIM(#daerah) = '') AND
(Negeri = #negeri OR TRIM(#negeri) = '') AND
(TempReference = #tempRef OR TRIM(#tempRef) = '')", sqlConn)
What is wrong with your approach?
Just change
(FloatNo = #floatNo OR FloatNo = 'None')
to
(FloatNo = #floatNo OR FloatNo = '' or FloatNo IS NULL)
And do that for every criteria.
Your query will respect empty values and NULL values after that.

Conversion of Foxpro code to Set-Based MySQL Query

Trying to convert a Visual Foxpro code to set-based MySQL query. Following is the code segment from Foxpro
lnFound=0
IF LnFound = 0 .and. rcResult = "ALL" AND PcOpOrIp = "OP"
SELECT PFile
LcTag = ORDER()
SET ORDER TO TAG PtcntlNm
=SEEK(LcPatientNo)
SCAN WHILE PtcntlNm = LcPatientNo
IF GcMResult <= "0"
GcMResult = "1-7MAT-PTC"
ENDIF
IF MONTH(cSRa.Fromdate) = MONTH(pFile.Fromdate) ;
.AND. pFile.ThruDate >= cSRa.ThruDate
** Check From/Thru Date against pFile
IF (ABS(cSRa.totalchrg) = (pFile.BDeduct+pFile.Deduct+pFile.Coinsur)) .OR. cSRa.Tchrgs = (pFile.BDeduct+pFile.Deduct+pFile.Coinsur) .or. (ABS(cSRa.totalchrg) = pFile.Total .OR. cSRa.Tchrgs = pFile.Total)
IF lnFound = 0
gcRecid = recid
gcmResult=rcResult
ENDIF
lnFound = lnFound + 1
gcUNrECID = gcunRecid + IIF(EMPTY(gCUNreCID),Recid,[,]+recid)
ENDIF
ENDIF
ENDSCAN
SELECT PFile
SET ORDER TO &LcTag
ENDIF
I have a table named pfile which I'am trying to join with another table named csra. The main aim of this is to set the record_id (gcrecid) based on the condition of three nested if statements. After setting the gcrecid variable the lnfound variable is set to one hence the third if statement condition is false from the second iteration onwards.
Here is the MySQL stored procedure which I came up with and as you can see I'm not able to completely convert the code in an efficient manner.
UPDATE csra AS cs
JOIN p051331s AS p ON cs.patientno = p.ptcntlnm
SET cs.recid = p.recid
, cs.mcsult = "ALL"
, cs.lnfound = '"1"'
WHERE cs.provider = '051331'
AND cs.lnfound = "0"
AND cs.RECID IS NULL
AND month(cs.fromdate) = month(p.fromdate)
AND p.thrudate >= cs.ThruDate
AND ABS(cs.totalchrg) = (p.bdeduct+p.deduct+p.coinsur)
OR cs.tchrgs = (p.bdeduct+p.deduct+p.coinsur)
OR ABS(cs.totalchrg) = p.total OR cs.tchrgs = p.total;
Any lead in this regard will be much appreciated as I've been working on this procedure for a couple of day with no noticeable results.
According to this partial VFP code (which is not clear on variables it uses) there is no code to be converted to set based at all. Corresponding mySQL or MS SQL or any other SQL series backend code would simply be "nothing". ie: this would be equivalant:
-- Hello to mySQL or MS SQL
PS: On your trial to convert to an update code, inner joining with csra is wrong. It is not joined in VFP code, csra values are constant --unless there is a relation on fields set-- (pointing to the "current row" values in csra only). You would want to make them into parameters as with the rest of memory variables (which is not clear from the code which ones are memory variables).

passing an Array as a Parameter to be used in a SQL Query using the "IN" Command

Good Afternoon to All,
I have a question concerning on SQL Queries. is it possible to use an array as a parameter to a query using the "IN" command?
for example,
int x = {2,3,4,5}
UPDATE 'table_name' set 'field' = data WHERE field_ID IN (x)
the reason I am asking this is to avoid an iterative SQL Statement when I have to update data in a database.
I also thought of using a for each statement in for the UPDATE Query but I don't know if it will affect the performance of the query if it will slow down the system if ever 100+ records are updated.
I am using VB.Net btw.
My Database is MySQL Workbench.
I have gotten the answer. I just simply need to convert each elements to a String then concatenate it with a "," for each element. so the parameter that i will pass will be a string.
ANSWER:
int x = {2,3,4,5}
will become
string x = "2,3,4,5"
My Query string will become "UPDATE tablename SET field=value WHERE ID IN("&x&")"
Thank you to all who helped.
If you have the query in a variable (not a stored procedure) and you don't have a huge amount of ids, you could built your own IN. I haven't tested the speed of this approach.
This code won't compile, it's just to give you an idea.
query = "SELECT * FROM table WHERE col IN ("
For t = 0 TO x.Length-1
If t > 0 Then query &= ","
query &= "#var" & t
Next
query &= ")"
...
For t = 0 TO x.Length-1
cmd.Parameters.Add("#var" & t, SqlDbType.Int).Value = x(t)
Next
i am not familiar with mySQL, but when dealing with MSSQL, I normally have a split function in DB so that I can use it to split concatenated integer values as a table, at VB side, something like:
Dim myIds = {1, 2, 3, 4}
Dim sql = <sql>
SELECT m.* FROM dbo.tblMyData m
INNER JOIN dbo.fncSplitIntegerValues(#Ids, ',') t ON t.id = m.Id
</sql>.Value
Using con As New SqlConnection("My connection string..."),
cmd As New SqlCommand(sql, con)
cmd.Parameters.Add("#Ids", SqlDbType.VarChar).Value =
myIds.Select(Function(m) m.ToString).Aggregate(Function(m, n) m & "," & n)
con.Open()
Dim rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection)
While rdr.Read()
Console.WriteLine(rdr.GetValue(0))
' do something else...
End While
End Using
dbo.fncSplitIntegerValues is a db function to split concatenated integer varchar into integer Id with given separator.
it's important not to use plain sql, instead, use sql parameters.
Note: above sample is not tested...

What's the Linq to SQL equivalent to TOP or LIMIT/OFFSET?

How do I do this
Select top 10 Foo from MyTable
in Linq to SQL?
Use the Take method:
var foo = (from t in MyTable
select t.Foo).Take(10);
In VB LINQ has a take expression:
Dim foo = From t in MyTable _
Take 10 _
Select t.Foo
From the documentation:
Take<TSource> enumerates source and yields elements until count elements have been yielded or source contains no more elements. If count exceeds the number of elements in source, all elements of source are returned.
In VB:
from m in MyTable
take 10
select m.Foo
This assumes that MyTable implements IQueryable. You may have to access that through a DataContext or some other provider.
It also assumes that Foo is a column in MyTable that gets mapped to a property name.
See http://blogs.msdn.com/vbteam/archive/2008/01/08/converting-sql-to-linq-part-7-union-top-subqueries-bill-horst.aspx for more detail.
Use the Take(int n) method:
var q = query.Take(10);
The OP actually mentioned offset as well, so for ex. if you'd like to get the items from 30 to 60, you would do:
var foo = (From t In MyTable
Select t.Foo).Skip(30).Take(30);
Use the "Skip" method for offset.
Use the "Take" method for limit.
#Janei: my first comment here is about your sample ;)
I think if you do like this, you want to take 4, then applying the sort on these 4.
var dados = from d in dc.tbl_News.Take(4)
orderby d.idNews descending
select new
{
d.idNews,
d.titleNews,
d.textNews,
d.dateNews,
d.imgNewsThumb
};
Different than sorting whole tbl_News by idNews descending and then taking 4
var dados = (from d in dc.tbl_News
orderby d.idNews descending
select new
{
d.idNews,
d.titleNews,
d.textNews,
d.dateNews,
d.imgNewsThumb
}).Take(4);
no ? results may be different.
This works well in C#
var q = from m in MyTable.Take(10)
select m.Foo
Whether the take happens on the client or in the db depends on where you apply the take operator. If you apply it before you enumerate the query (i.e. before you use it in a foreach or convert it to a collection) the take will result in the "top n" SQL operator being sent to the db. You can see this if you run SQL profiler. If you apply the take after enumerating the query it will happen on the client, as LINQ will have had to retrieve the data from the database for you to enumerate through it
I do like this:
var dados = from d in dc.tbl_News.Take(4)
orderby d.idNews descending
select new
{
d.idNews,
d.titleNews,
d.textNews,
d.dateNews,
d.imgNewsThumb
};
You would use the Take(N) method.
Taking data of DataBase without sorting is the same as random take
Array oList = ((from m in dc.Reviews
join n in dc.Users on m.authorID equals n.userID
orderby m.createdDate descending
where m.foodID == _id
select new
{
authorID = m.authorID,
createdDate = m.createdDate,
review = m.review1,
author = n.username,
profileImgUrl = n.profileImgUrl
}).Take(2)).ToArray();
I had to use Take(n) method, then transform to list, Worked like a charm:
var listTest = (from x in table1
join y in table2
on x.field1 equals y.field1
orderby x.id descending
select new tempList()
{
field1 = y.field1,
active = x.active
}).Take(10).ToList();
This way it worked for me:
var noticias = from n in db.Noticias.Take(6)
where n.Atv == 1
orderby n.DatHorLan descending
select n;