C# LINQ to objects query to change the field value based on List - c#-4.0

I have the follwing objects
objItem (id,name,qty) - list<items>
objSel(selId) - list<int>
objSel.selId is the selected item id of objItem.
How to write the LINQ query to change item qty to 0 if the items are not selected and return objItem.

Your pseudo-code is quite confusing, but I suspect you want something like:
List<Item> items = ...;
List<int> selectedIds = ...;
foreach (var item in items.Where(x => !selectedIds.Contains(x.Id)))
{
item.Quantity = 0; // Property name adjusted for readability and convention
}
For more efficiently, use HashSet<int> for the selected IDs instead.
Note that it's not the LINQ query which performs the change - the query just gives the items which require changing. While you can abuse LINQ to change data, it's a bad idea to do so. The clue is in the word "query" - it's about asking a question. What you do with the answer to that question is a different matter.

Related

How to get count of a generic list in C# and no need to consider items with null or empty values in the count?

I need to get the count of a generic list in C#.No need to consider empty and null items in the count of list.
Below is my code
Public class Student
{
public string Name {get;set;}
public string Age {get;set;}
}
List<student> listStudent = new List<student>();
Student studentOne=new Student();
studentOne.Name="abc";
studentOne.Age="20";
listStudent.Add(studentOne);
Student studentTwo=new Student();
studentOne.Name="def";
studentOne.Age="22";
listStudent.Add(studentTwo);
Student studentThree=new Student();
studentOne.Name=" ";
studentOne.Age=null;
listStudent.Add(studentThree);
I have written below code to get the count
listStudent.count
It returns 3.it is correct as it contains 3 rows in the list.But I need to get the count of elements or items only having values. here in my code values in last item is null or empty.so I need to get count as 2.
Is there any built in method in c# to do the same. is there any way to check without using loops ?
LINQ can help here:
listStudent.Where(
s => !string.IsNullOrWhiteSpace(s.Name) && s.Age != null
).Count();
There is no method in framework that you are looking for. You need to create your own extended method to make this.

How to get all possible values for SPFieldLookup

I have a lookup field in sharepoint which just references another list. I wonder how do I programatically enumerate all possible values for this field?
For example, my lookup field "Actual City" refers list "Cities" and column "Title", I have 3 cities there. In code I would like to get list of all possible values for field "Actual City", smth like (metacode, sorry):
SPFieldLookup f = myList["Actual City"];
Collection availableValues = f.GetAllPossibleValues();
//this should return collection with all cities a user might select for the field
I wrote some code to handle this for my project just the other day. Perhaps it will help.
public static List<SPFieldLookupValue> GetLookupFieldValues(SPList list, string fieldName)
{
var results = new List<SPFieldLookupValue>();
var field = list.Fields.GetField(fieldName);
if (field.Type != SPFieldType.Lookup) throw new SPException(String.Format("The field {0} is not a lookup field.", fieldName));
var lookupField = field as SPFieldLookup;
var lookupList = list.ParentWeb.Lists[Guid.Parse(lookupField.LookupList)];
var query = new SPQuery();
query.Query = String.Format("<OrderBy><FieldRef Name='{0}'/></OrderBy>", lookupField.LookupField);
foreach (SPListItem item in lookupList.GetItems(query))
{
results.Add(new SPFieldLookupValue(item.ID, item[lookupField.LookupField].ToString()));
}
return results;
}
Then to use it, your code would look something like this:
var list = SPContext.Current.Web.Lists["My List"];
var results = GetLookupFieldValues(list, "Actual City");
foreach (SPFieldLookupValue result in results)
{
var value = result.LookupValue;
var id = result.LookupId;
}
I think there is no explicit method returning what you want. But the SPFieldLookup class stores all the info you need to request this information manually: LookupField and LookupList
So you could retrieve the information by getting it form the list you lookup field uses. To make it reusable you could implement it as a Extension Method. So the next time you could really call f.GetAllPossibleValues();.
As I understand you want to query all values that are in use?
If so, you would have to query items where Actual City is not null, query would look something like:
<Where><IsNotNull><FieldRef Name='Actual City'/></IsNotNull></Where>
Then, for each queried item you would
List<SPFieldLookupValue> result = new List<SPFieldLookupValue>(returnedItemCount * 5);
foreach (SPListItem item in queriedItems) {
object lookup = item["Actual City"];
SPFieldLookupValueCollection lookupValues = new SPFIeldLookupValueCollection(
(lookup != null) ? lookup.ToString() : ""
);
foreach (SPFieldLookupValue lookupValue in lookupValues) {
if (!result.Contains(lookupValue)) {
result.Add(lookupValue);
}
}
}
Or you could use HashTable where LookupId would be string and LookupValue would be int id and then check if HashTable.ContainsKey(lookupId)... must be faster to find an integer in hashtable rather than string in list, but the resource intensive part is to probably query all items where that field contains some value and then loop...
If you want to enumerate all possible values, that means you basically want to get all the Title field values from all the items in the Cities list. I don't think there is a method like GetAllPossibleValues() in SharePoint, but you can either just list all the items in Cities and get their titles, if there's just a few, or use a CAML query if there's plenty.

SPList Item get value - ArgumentException

I have an SPListItem and I have an array of column names.
When I try to access the SPListItem values using the code below:
for(int i=0;i<arrColName.length;i++)
{
string tempValue = item[arrColName[i]].ToString();
// Works fine in case the the specific column in the list item is not null
// Argument exception - Values does not fall witing expected range
// exception in case the value //is null
}
I think that you used an SPQuery to get the list items and forgot to add the field into the viewfields property of SPQuery.
query.ViewFields = string.Format("<FieldRef Name=\"{0}\" Nullable=\"True\" />", mFieldName);
Usually when you test your program with the farm account the code will work, with normal users you get an ArgumentException.
Another problem/feature which causes ArgumentException is the new ListView Threshold. If th elist you try to access has too many items, this Exception is raised. A way to handle this is to increase the threshold with powershell for the list.
Not only check if item != null but also item["FieldName"] != null. Because if you will try to call .ToString() on null, you will get exception.
And if that field with internal name "FieldName" name does not exist, you will also get an exception. So you would probably try
SPFieldCollection fields = list.Fields;
foreach (SPListItem item in list.Items) {
if (fields.Contains("FieldName") && item["FieldName"] != null) {
string fieldValue = item["FieldName"].ToString();
}
}
I had a similar situation with custom cascade field (or column). I did it following way and it seemed to work for the custom field types.
item.Properties["Country"] = "Mexico"; // custom field
item.Properties["nCity"] = "Cancun"; // custom field
item["Document Descriptions"] = "Test document description.";
Note: I added item.Properties for the custom columns. No need to add properties for built in field type (else they don't work).
Does your array contain the internal names or the display names of the columns? If it's the latter you might try item[item.Fields[arrColName[i]].InternalName].ToStrinng(); instead.
Sharepoint Lists aren't stored as a array with a static size.
You have to use the built in sharepoint iterator to go through each element
For example:
SPList checklist = //Some initiliaztion
foreach (SPListItem item in checklist.Items){
//work
}
This will do work on each item in your SPlist
Edit:
Wrong advice, I didn't see the code until after the edit.
Maybe try a cast?
(String)item[colname]

What is the best way to retrieve distinct / unique values using SPQuery?

I have a list that looks like:
Movie Year
----- ----
Fight Club 1999
The Matrix 1999
Pulp Fiction 1994
Using CAML and the SPQuery object I need to get a distinct list of items from the Year column which will populate a drop down control.
Searching around there doesn't appear to be a way of doing this within the CAML query. I'm wondering how people have gone about achieving this?
Another way to do this is to use DataView.ToTable-Method - its first parameter is the one that makes the list distinct.
SPList movies = SPContext.Current.Web.Lists["Movies"];
SPQuery query = new SPQuery();
query.Query = "<OrderBy><FieldRef Name='Year' /></OrderBy>";
DataTable tempTbl = movies.GetItems(query).GetDataTable();
DataView v = new DataView(tempTbl);
String[] columns = {"Year"};
DataTable tbl = v.ToTable(true, columns);
You can then proceed using the DataTable tbl.
If you want to bind the distinct results to a DataSource of for example a Repeater and retain the actual item via the ItemDataBound events' e.Item.DataItem method, the DataTable way is not going to work. Instead, and besides also when not wanting to bind it to a DataSource, you could also use Linq to define the distinct values.
// Retrieve the list. NEVER use the Web.Lists["Movies"] option as in the other examples as this will enumerate every list in your SPWeb and may cause serious performance issues
var list = SPContext.Current.Web.Lists.TryGetList("Movies");
// Make sure the list was successfully retrieved
if(list == null) return;
// Retrieve all items in the list
var items = list.GetItems();
// Filter the items in the results to only retain distinct items in an 2D array
var distinctItems = (from SPListItem item in items select item["Year"]).Distinct().ToArray()
// Bind results to the repeater
Repeater.DataSource = distinctItems;
Repeater.DataBind();
Remember that since there is no CAML support for distinct queries, each sample provided on this page will retrieve ALL items from the SPList. This may be fine for smaller lists, but for lists with thousands of listitems, this will seriously be a performance killer. Unfortunately there is no more optimized way of achieving the same.
There is no DISTINCT in CAML to populate your dropdown try using something like:
foreach (SPListItem listItem in listItems)
{
if ( null == ddlYear.Items.FindByText(listItem["Year"].ToString()) )
{
ListItem ThisItem = new ListItem();
ThisItem.Text = listItem["Year"].ToString();
ThisItem.Value = listItem["Year"].ToString();
ddlYear.Items.Add(ThisItem);
}
}
Assumes your dropdown is called ddlYear.
Can you switch from SPQuery to SPSiteDataQuery? You should be able to, without any problems.
After that, you can use standard ado.net behaviour:
SPSiteDataQuery query = new SPSiteDataQuery();
/// ... populate your query here. Make sure you add Year to the ViewFields.
DataTable table = SPContext.Current.Web.GetSiteData(query);
//create a new dataview for our table
DataView view = new DataView(table);
//and finally create a new datatable with unique values on the columns specified
DataTable tableUnique = view.ToTable(true, "Year");
After coming across post after post about how this was impossible, I've finally found a way. This has been tested in SharePoint Online. Here's a function that will get you all unique values for a column. It just requires you to pass in the list Id, View Id, internal list name, and a callback function.
function getUniqueColumnValues(listid, viewid, column, _callback){
var uniqueVals = [];
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_layouts/15/filter.aspx?ListId={" + listid + "}&FieldInternalName=" + column + "&ViewId={" + viewid + "}&FilterOnly=1&Filter=1",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" }
}).then(function(response) {
$(response).find('OPTION').each(function(a,b){
if ($(b)[0].value) {
uniqueVals.push($(b)[0].value);
}
});
_callback(true,uniqueVals);
},function(){
_callback(false,"Error retrieving unique column values");
});
}
I was considering this problem earlier today, and the best solution I could think of uses the following algorithm (sorry, no code at the moment):
L is a list of known values (starts populated with the static Choice options when querying fill-in options, for example)
X is approximately the number of possible options
1. Create a query that excludes the items in L
1. Use the query to fetch X items from list (ordered as randomly as possible)
2. Add unique items to L
3. Repeat 1 - 3 until number of fetched items < X
This would reduce the total number of items returned significantly, at the cost of making more queries.
It doesn't much matter if X is entirely accurate, but the randomness is quite important. Essentially the first query is likely to include the most common options, so the second query will exclude these and is likely to include the next most common options and so on through the iterations.
In the best case, the first query includes all the options, then the second query will be empty. (X items retrieved in total, over 2 queries)
In the worst case (e.g. the query is ordered by the options we're looking for, and there are more than X items with each option) we'll make as many queries as there are options. Returning approximately X * X items in total.

Accessing SPLIstItem properties in SharePoint

I'm trying something very simple - accessing my SharePoint list's items and their properties.
However, SPListItem.Properties count is zero for all normal lists. Everything works as expected for document and pages libraries. So, if the list items are based on document type, all is good. If they are based on item, properties are not returned.
I've tried in two environments, with new sites created from OOTB publishing templates, with new lists which are based on OOTB content types etc. Always the same thing.
Right amount of SPListItems is always returned. Title and Name are fine. It's just that the .Properties hashtable is totally empty.
In desperation, I wrote a web part that outputs the following (ugly!) diagnostics.
foreach (SPList list in SPContext.Current.Web.Lists)
{
foreach (SPListItem item in list.Items)
{
Label label = new Label();
label.Text = "Name: " + item.Name + "Property count: " + item.Properties.Count;
this.Controls.Add(label);
}
}
The only observation is that it works exactly as I described earlier. I just share the code to show that this is the most basic operation imaginable.
Here is sample output - I've added the line breaks for readability ;-)
Name: Test Property count: 0
Name: default.aspx Property count: 21
Obviously item "Test" is an item based list item and default.aspx is a page.
Has anyone ever encountered anything like this? Any ideas?
item["FieldName"] is the canonical way to get a value of a metadata column in a SharePoint list. If you need to get the list of available fields for a SharePoint list, check the parent SPList object's Fields property which is a collection of the fields in this list. Each of those field objects will have a property called InternalName and that is what you should use to access its value when you are working with an instance of SPListItem.
Are you trying to get the field Values? Sadly, they are not strongly typed:
string ModifiedBy = (string)item["Author"];
To get the proper names of the fields (they have to be the internal names), go to the List and then List Settings. You will find the List of Columns there. Click on any Column Name to go to the Edit Page, and then look at the URL in the Address Bar of your Browser. At the very end, there should be a parameter "Field=Editor" or similar - that's your internal field name.
If you wonder why a field like "Test Field" looks strange, that is because Sharepoint encodes certain characters. A Space would be encoded to x0020 hence the Internal Name for "Test Field" is "Test_x0020_Field".
In order to get the proper field type to cast to:
string FieldType = item["Author"].GetType().FullName;
(The Intermediate Window in Visual Studio is tremendously helpful for this!)
I have found the following extension to the SPListItem class to be very helpful.
internal static class SharePointExtensions
{
internal static Dictionary<string, object> PropertiesToDictionary(this SPListItem item)
{
// NOTE: This code might be temping - but don't do it! ...itdoes not work as there are often multiple field definitions with the same Title!
// return item.Fields.Cast<SPField>().ToDictionary(fld => fld.Title, fld => item[fld.Title]);
Dictionary<string, object> dict = new Dictionary<string, object>();
var fieldNames = item.Fields.Cast<SPField>().Select(fld => fld.Title).Distinct().OrderBy(sz => sz).ToArray();
foreach (fieldName in fieldNames)
dict.Add(sz, item[fieldName]);
return dict;
}
}
with it you can simply do:
item.PropertiesToDictionary()
...and you will have a nice Linq dictionary object that will work just the way you'd expect. Is it a little heavy-weight / low-performance? Sure. Are most people willing to make that trade-off? I think so...
Do you run SPListItem.Update() or .SystemUpdate() after setting the properties?
If you want to get an object out of a SPField of a SPListItem you've got to do like this:
SPField field = ((SPList)list).Fields.GetField("FieldName");
object fieldValue = field.GetFieldValue(((SPListItem)item)[field.Title].ToString());
The ListItem.Properties hashtable will be empty unless you assign to it.
SPListItem item = properties.ListItem;
item.Properties["Key"] = "value";
int total = item.Properties.Count;
Answer:
"total == 1"
SPList yourList = web.Lists["Your list name"];
string sColumnValue = oSPListItem[yourList.Fields["yourSiteColumn display
name"].InternalName].ToString();

Resources