b.Title.Contains(b.Author)” is invalid. Calculations should occur on the value side of the condition:
“…where b.NumberOfPages < 250 * 2 ” is invalid.
The correct way is: “…where b.NumberOfPages / 2 < 250 ”
The condition itself can be in inverse order, so: “…where b.Author == “Scott Richter” “and “ “Scott Richter” == b.Author ” are both valid conditions in a LINQ-statement.
The following methods on System.String are supported in LINQ to SharePoint: StartsWith( string ), Contains( string ) and Equals( string ).Excessive ToString calls are stripped off automatically when using == or != comparisons:
b.Author.ToString().ToString() == "Jeffrey Richter" becomes b.Author == "Jeffrey Richter"
Entity properties that have been marked as Nullable because it aren't reference types and the field is not defined as required in the SharePoint list definition can be checked for null values in two ways:
u.Age.HasValue
u.Age != null
To reference the value of the nullable property, two approaches exist as well:
u.Age == 24
u.Age.Value == 24
Choice and MultiChoice fields are mapped on enum types by the SPMetal tool. Each CHOICE from SharePoint is mapped on a field in the target enumeration, possibly decorated with a ChoiceAttribute to indicate a different underlying name (for example [Choice("Laurel & Hardy")] will be applied on an enum field LaurelHardy). MultiChoice fields (represented by radio buttons in SharePoint) are mapped on a [Flags] enumeration where all values are powers of two to allow bitwise combination.
[Flags]
enum FavoriteFood
{
Pizza = 1,
Lasagna = 2,
Hamburger = 4
}
enum MembershipType
{
Gold,
Silver,
Bronze
}
Conditions on Choice fields should look like this:
u.MembershipType == MembershipType.Silver
u.MembershipType != MembershipType.Gold
and are translated into <Eq> or <Neq> CAML conditions. Comparison operators like <, <=, > and >= won't trigger compilation or runtime errors but shouldn't be used.
Conditions on MultiChoice fields should look like this:
u.FavoriteFood == FavoriteFood.Pizza
u.FavoriteFood != FavoriteFood.Pizza
u.FavoriteFood == (FavoriteFood.Pizza | FavoriteFood.Lasagna)
Warning: There's a semantic mismatch between LINQ queries for MultiChoice fields and what you normally expect in C#.
The first condition means that Pizza should be one of the choices applied for the list item. To that respect, it's equivalent to the (u.FavoriteFood & FavoriteFood.Pizza) == FavoriteFood.Pizza syntax normally used to check enumeration flags. This syntax isn't supported though. In a similar fashion, the second condition means that Pizza shouldn't be in the list of favorite foods of the list item; it doesn't restrict any other values though. The last condition is equivalent to u.FavoriteFood == FavoriteFood.Pizza || u.FavoriteFood == FavoriteFood.Lasagna but again it doesn't rule out the presence of other choices on the list item. If you want to use an absolute equality check, it should be written manually. For example, to find people who only like Pizza (and nothing but that), you'd have to write u.FavoriteFood == FavoriteFood.Pizza && u.FavoriteFood != FavoriteFood.Lasagna && u.FavoriteFood != FavoriteFood.Hamburger.
Fields with fill-in choices will have an additional mapping field of type string that can be null (no fill-in choice made) or set to some string. This mapping field is cross-linked from the original field using the OtherChoice property of the FieldAttribute mapping, like this:
/// <summary>
/// Favorite food
/// </summary>
[Field("Favorite food", FieldType.MultiChoice, Id = "c48610a1-098e-438c-9f77-6e65c6a392cb", OtherChoice = "FavoriteFoodOther")]
public FavoriteFood? FavoriteFood { get; set; }
/// <summary>
/// Favorite food 'Fill-in' value
/// </summary>
[Field("Favorite food", FieldType.Text, Id = "c48610a1-098e-438c-9f77-6e65c6a392cb")]
public string FavoriteFoodOther { get; set; }
The fill-in choice entity property can used in queries too:
u.FavoriteFoodOther == "Steak"
u.FavoriteFoodOther != "Steak"
Again, the semantic mismatch applies and putting a condition on the fill-in choice doesn't say anything about the possible presence of other choices. Therefore, the first condition will retrieve all the people who like Steak but necessarily only Steak. The last condition retrieves everyone who doesn't like Steak.
In the current implementation, the fill-in choice field can also be used to put restrictions on known choice values. For example, you could rewrite u.FavoriteFood == FavoriteFood.Pizza with u.FavoriteFoodOther == "Pizza". To this respect, the 'Other' suffix on fill-in choice fields is a bit of a misnomer. This flexibility allows the list definition to be extended with new CHOICE values, without having to change the code. For example, u.FavoriteFoodOther == "Steak" will keep working even when Steak is added as a recognized pre-defined CHOICE value on the field.
Boolean negation isn't supported directly in CAML, but LINQ to SharePoint knows how to invert most of the supported comparison operators and implements De Morgan's laws to transform Boolean conditions with negations into a negation-less equivalent. A few examples:
· !(u.Age == 24) becomes u.Age != 24 (<Neq>...</Neq>)
· !(u.Age <= 24) becomes u.Age > 24 (<Lt>...</Lt>)
· !(u.Age > 24 && u.FirstName == "Bart") becomes u.Age <= 24 || u.FirstName != "Bart" (<Or><Leq>...</Leq><Neq>...</Neq></Or>)
· !(u.Age >= 24 || !(u.FirstName == "Bart" && u.AccountBalance < 1234)) becomes u.Age < 24 && (u.FirstName == "Bart" && u.AccountBalance < 1234) (<And><Lt>...</Lt><And><Eq>...</Eq><Lt>...</Lt></And></And>)
Negation of the BeginsWith and Contains operators isn't supported though.