linq subquery returning null - linq

I have an odd linq subquery issue.
Given the following data structure:
Parents Children
------- --------
Id Id
ParentId
Location
HasFoo
(obviously this is not the real structure, but it's close enough for this example)
I'm able to run this query and get a desired result:
bool b = (from p in Parents
from c in Children
where p.Id == 1 && c.ParentId == p.Id && c.Location == "Home"
select c.HasFoo).SingleOrDefault();
So if there is a child that has the Location "Home" for a Parent of Id 1, I will get that Child's "HasFoo" value, otherwise, I'll get false, which is the "default" value for a bool.
However, if I try and write the query so I have a list of Parent objects, like so:
var parentList = from p in Parents
select new ParentObject
{
ParentId = p.ParentId,
HasHomeChildren = p.Children.Count(c => c.Location == "Home") > 0,
HasHomeChildrenWithFoo = (from c in p.Children where c.Location == "Home" select c.HasFoo).SingleOrDefault()
}
I get the following error when iterating over the list:
The null value cannot be assigned to a member with type System.Boolean which is a non-nullable value type.
I don't see where this "null" value is coming from, however.

I wonder if the compiler is inferring HasHomeChildrenWithFoo to be bool, but then actually casting to a nullable bool (thus messing up your SingleOrDefault call). At any rate, I'd be willing to bet you could fix it with a cast to a nullable type in that final select which you can then manually default to false when null. It'd probably make the error go away, but it's kind of a brute-force kludge.
var parentList = from p in Parents
select new ParentObject
{
ParentId = p.ParentId,
HasHomeChildren = p.Children.Any(c => c.Location == "Home"),
HasHomeChildrenWithFoo = (from c in p.Children where c.Location == "Home" select (bool?)c.HasFoo) ?? false)
}

Related

how do i union int? and int variables in linqpad

In LinqPad
Getting the following error trying to union int? and int variables
Researched but can't find a solution that seems to work.
CS1929 'IQueryable<>' does not contain a definition for 'Union' and the best extension method overload 'ParallelEnumerable.Union<>(ParallelQuery<>, IEnumerable<>)' requires a receiver of type 'ParallelQuery<>'
//Parent not null
var parent =
from s in Students
where s.Id==5027
select new {
ID_PK = s.CaseOwnerIdAspnet_Users.User_ID_FKDYN_User_Profile.Organization_ID_FKDYN_Organization.Parent_ID_FK == null ?
s.CaseOwnerIdAspnet_Users.User_ID_FKDYN_User_Profile.Organization_ID_FKDYN_Organization.ID_PK
:
s.CaseOwnerIdAspnet_Users.User_ID_FKDYN_User_Profile.Organization_ID_FKDYN_Organization.Parent_ID_FK
};
var orgs =
from o in DYN_Organizations
join p in parent on o.Parent_ID_FK equals p.ID_PK
select new {ID_PK = o.ID_PK};
parent.Union(orgs);
Suppose parent is returning int? and orgs is returning int, then you can change orgs to return int? by casting the value, eg
change it to
var orgs =
from o in DYN_Organizations
join p in parent on o.Parent_ID_FK equals p.ID_PK
select new {ID_PK = (int?) o.ID_PK};
Your error message also mentions ParallelQuery and IEnumerable and I'm not sure if you can create a union between this types. If not, then the easiest way is to add .ToList() to the end of each query and then you are creating a union between two Lists which will work.

Dynamic CRM :Contains<> is not working in CRM

My code is as below:
var conntionRecord1Id = (from connectionBase in orgServiceContext.CreateQuery("connection")
where connectionBase["record1roleid"] == null
select new { OpportunityId = connectionBase["record1id"] }).Distinct().ToList();
var query =
from opportunity in orgServiceContext.CreateQuery("opportunity")
orderby opportunity["createdon"] ascending
select new
{
Topic = opportunity.Attributes.Contains("name") == true ? opportunity["name"] : null,
OpportunityId = opportunity.Attributes.Contains("opportunityid") == true ? opportunity["opportunityid"] : null,
PostalCode = opportunity.Attributes.Contains("new_address_postalcode") == true ? opportunity["new_address_postalcode"] : null,
};
var result = (from f in query.ToList() where conntionRecord1Id.Contains(f.OpportunityId) select f).ToList();
But in above query where i am using Contains it giving count 0. even though I have common records in the list
The Contains Linq extension method does not know how to compare complex objects.
Comparing f.OpportunityId to a list of Guids instead of a list of an anonymous type will work:
var conntionRecord1Id = (from connectionBase in orgServiceContext
.CreateQuery("connection")
where connectionBase["record1roleid"] == null
select connectionBase.GetAttributeValue<Guid?>("record1id"))
.Distinct()
.ToList();
Implement IEqualityComparer in a custom comparer class to compare complex objects: https://stackoverflow.com/a/6694563/1817350
Keep in mind that calling .ToList() brings down all the records into memory and will cause performance problems with large amounts of records.

Difficult sort order with Linq to SQL

I have a List of objects that I need sorted a particular way.
The relevant table fields are:
ID (int)
IsMandatory (bit)
ParentID (int nullable)
Code (varchar)
I need them sorted by IsMandatory=true first, then by Code, but anything with a ParentID must be sorted by Code but appear straight after the row with the same ID as ParentID (and these records will always have IsMandatory set to NULL).
Some sample data, and this is also in the order in which they should appear when ordered:
ID=1, IsMandatory=1, ParentID=NULL, Code="A"
ID=2, IsMandatory=NULL, ParentID=1, Code="A"
ID=3, IsMandatory=NULL, ParentID=1, Code="B"
ID=4, IsMandatory=1, ParentID=NULL, Code="B"
ID=5, IsMandatory=0, ParentID=NULL, Code="C"
ID=6, IsMandatory=NULL, ParentID=5, Code="A"
ID=7, IsMandatory=0, ParentID=NULL, Code="D"
How would this best be accomplished in a Linq to SQL orderby?
It was a difficult sort!
The reason for the difficulty stems from the fact you are ordering on the Parents record properties first and then the actual records properties.
I tried to make the variables as self explanatory as possible, but if you have any questions please ask!
var query = from x in context.Table
let parent = list.FirstOrDefault(y => x.ParentID == y.ID)
let parentIsMandatory = parent == null ? x.IsMandatory : parent.IsMandatory
let parentIsMandatoryOrder = parentIsMandatory == true ? 0 : 1
let parentCode = parent == null ? x.Code : parent.Code
let parentId = x.ParentID ?? x.ID
let isParent = x.ParentID == null ? 0 : 1
orderby parentIsMandatoryOrder, parentCode, parentId, isParent, x.Code
select x;

Distinct works on IQueryable but not List<T>?? Why?

First Table is the View and Second is the result I want
This below query works fine
List<BTWStudents> students = (from V in db.vwStudentCoursesSD
where classIds.Contains(V.Class.Value)
select new BTWStudents
{
StudentId = V.StudentId
Amount= V.PaymentMethod == "Cashier Check" ? V.Amount: "0.00"
}).Distinct().ToList();
But I changed it to List to add string formatting(see below)
List<BTWStudents> students = (from V in db.vwStudentCoursesSD
where classIds.Contains(V.Class.Value)
select new {V}).ToList().Select(x => new BTWStudents
{
StudentId = V.StudentId
Amount= V.PaymentMethod == "Cashier Check" ? String.Format("{0:c}",V.Amount): "0.00"
}).Distinct().ToList();
With this Second Query I get this
Why is distinct not working in the second query?
When working with objects (in your case a wrapped anonymous type because you are using Select new {V} rather than just Select V), Distinct calls the object.Equals when doing the comparison. Internally, this checks the object's hash code. You'll find in this case, the hash code of the two objects is different even though the fields contain the same values. To fix this, you will need to override Equals on the object type or pass a custom IEqualityComparer implementation into the Distinct overload. You should be able to find a number of examples online searching for "Distinct IEqualityComparer".
Try this (moved your distinct to the first query and corrected your bugged if/then/else):
List<BTWStudents> students = (from V in db.vwStudentCoursesSD
where classIds.Contains(V.Class.Value)
select new {V}).Distinct().ToList().Select(x => new BTWStudents
{
classId = V.Class.HasValue ? V.Class.Value : 0,
studentName = V.StudentName,
paymentAmount = V.PaymentMethod == "Cashier Check" ? String.Format("{0:c}",x.V.AmountOwed): "0.00"
}).ToList();
You can get around using Distinct all together if you Group by StudentID
var studentsGroupedByPayment =
(from V in db.vwStudentCoursesSD
where classIds.Contains(V.Class.Value)
group V by V.StudentId into groupedV
select new
{
StudentID = groupedV.Key,
Amount = string.Format("{0:C}",
groupedV.First().PaymentMethod == "Cashier Check" ?
groupedV.First().Amount : 0.0)
}
).ToList();

Conditional Multiple Fields Searching and Filtering in LINQ

Assuming that we have the following table:
Person:
PersonID,
Name,
Age,
Gender
And we are providing a search function that allows users to search the table according to the name and/or the age.
The tricky part in writing the SQL ( or LINQ) query is that the users can choose to search for both field, or any one field, or no field. If he wants to search for all then he would just have to leave the textbox blank.
The logic to do this can be written as follows:
var p;
if(Name_TextBox=='')
{
p=from row in person
select row ;
}
else
{
p= from row in person
where row.Name=Name_TextBox
select row ;
}
// repeat the same for age
Now after a while the code gets very long and messy... How can I compress the above into a single query with no if-else?
Try code like this
string personName = txtPersonName.Text;
int personAge = Convert.ToInt32(txtAge.Text);
var opportunites = from p in this.DataContext.Persons
select new
{
p.PersonID,
p.Name,
p.Age,
p.Gender
};
if (personsID != 0)
opportunites = opportunites.Where(p => p.PersonID == personID);
if (personName != string.Empty)
opportunites = opportunites.Where(p => p.Name.StartsWith(personName));
if (personAge != 0)
opportunites = opportunites.Where(p => p.Age == personAge);
This will work fine. If personName is not given it will be not add to where, and if given then it will added.
One alternative which I have used in SQL which could be implemented in Linq too is
var p = from p in Person
where p.Name == Name_TextBox || Name_TextBox == String.Empty
select p;
(Note that your 'linq' is using SQL syntax, which won't compile. Also you can't declare a var as you are doing without directly assigning a value)
why not use the null coalescing operator? eg.
var products = from a in context.products
where a.ID == (productID ?? a.ID)
select a;
This works really well on my system

Resources