I have a Private-Message Table and a User-Table.
I connect them here:
var messageUsers = (from pm in dc.PrivateMessages
join user in dc.Users
on pm.SenderID equals user.UserID
where !pm.IsDeletedRecipient && pm.RecipientID == id
select new PMInbox
{
SenderUsername = user.Username,
PrivateMessageID = pm.PrivateMessageID,
SenderID = pm.SenderID,
Subject = pm.Subject,
Text = pm.Text,
SenderType = pm.SenderType,
IsDeletedRecipient = pm.IsDeletedRecipient,
IsDeletedSender = pm.IsDeletedSender,
IsRead = pm.IsRead,
Timestamp = pm.TimestampSend
}).ToList();
How to make this in a left-join, so if the userID is not the SenderID (e.g. The Sender is deleted allready), the Username should be empty?
var messageUsers = (
from pm in dc.PrivateMessages
where !pm.IsDeletedRecipient && pm.RecipientID == id
select new PMInbox {
SenderUsername = (
from user in dc.Users
where user.UserID == pm.SenderID
select user.Username
).SingleOrDefault(),
PrivateMessageID = pm.PrivateMessageID,
//...
}
).ToList();
In general, to achieve a Left outer join in LINQ, you should be using SingleOrDefault or possibly FirstOrDefault when you wish to include 1 or 0 rows of the joined "table", and DefaultIfEmpty when you may need to include several lines (in my experience, that's a less common occasion, however). In your specific case, it sounds like UserID is a unique identifier for Users - as such, I translated your left join into a SingleOrDefault call rather than a DefaultIfEmpty call.
Unlike SQL, .NET cannot resolve properties on null values. So if you do something like user.Username and user is null, you'll get a NullReferenceException. You can then either check for null every single time you access user, or you can project (i.e. select) before calling SingleOrDefault or DefaultIfEmpty. After all, an empty sequence of users selects an empty sequence of usernames - which, after SingleOrDefault creates a name or null without the need for any manual null-checking.
Do a group join, then unpack the group by querying it. The DefaultIfEmpty generates a null element when the collection is empty.
var messageUsers = (
from pm in dc.PrivateMessages
join u in dc.Users
on pm.SenderID equals u.UserID
into users
from user in users.DefaultIfEmpty()
where !pm.IsDeletedRecipient && pm.RecipientID == id
...
Also, if you have Associations set up between the tables in the dbml, there should be a relational property from PrivateMessage to User that can be used to express the query more simply. (I'm naming that property Senders, but it might be auto-named Users or Users1. You can rename the property in the dbml.)
var messageUsers = (
from pm in dc.PrivateMessages
where !pm.IsDeletedRecipient && pm.RecipientID == id
from user in pm.Senders.DefaultIfEmpty()
...
Related
I want to fetch record from self reference table parent record contain multiple child record from these multiple record i have to show maximum offer value ,I also want to show child record from another child table too my query like this
var query = (from pd in _context.Product_User_Transactions_Main
join od in _context.Product_User_Transactions_Yarn on pd.TransactionID equals od.TransactionID
into t
where (pd.UserPortalID == UserID && pd.TransactionTypeID == TransactionTypeID)
select new
{
pd.TransactionID,
pd.ProductName,
pd.Quantity,
pd.Price,
pd.TransactionTypeID,
pd.UOMID,
pd.UOM.UOM1,
pd.RefTransactionID,
pd.PaymentTermID,
pd.UserPortalID,
pd.UserSessionID,
pd.TransactionTime,
Offer = (from m in _context.Product_User_Transactions_Main join el in _context.Product_User_Transactions_Main on m.TransactionID equals el.RefTransactionID where el.RefTransactionID != null select el.Price).Max(),
pd.GEN_PaymentTerm.PaymentTermName,
Product_User_Transactions_Yarn = t.Select(p => new { p.YarnBlendID, p.YarnColorID, p.YarnCount, p.YarnDesc, p.YarnPly, p.YarnSourceID, p.YarnTypeID, p.TransactionID }),
}).ToList();
This query returns a wrong result as this query show Max of one record to all I want to show specific offer in front of it price. Where is my mistake? I don't know
I have linq query which has multiple records & I am filtering these records using a where clause.
Now, if the filtered records return nothing then I need to make it default to take default any single record from list.
var resultStaffGua = (from s in _db.Students
join sg in _db.StudentStaffGuardians on s.StudentID equals sg.StudentId
join g in _db.Staffs on sg.StaffId equals g.StaffID
join lr in _db.luRelationTypes on sg.RelationTypeId equals lr.RelationTypeID
join ga in _db.StaffAddresses on g.StaffID equals ga.StaffID
join ad in _db.Addresses on ga.AddressID equals ad.AddressID
where
lse.StatusID == (int?)Extension.StatusType.Active
&& lse.TenantID == tenantid
select new
{
g.FirstName,
g.LastName,
IsPrimary = sg.IsPrimaryGuardian,
se.Email,
Phone = sphon.PhoneNumber,
lr.RelationCD,
gdnr.GenderCD,
ad.Zipcode
}).Where(i=>i.IsPrimary==true);
if resultStaffGua count 0, I need one record from resultStaffGua. Thank you
if result count 0, I need one record from parentList.
Sometimes the obvious solution is the best. Why not add this after your code?
if (resultStaffGua.Count() == 0)
{
resultStaffGua = parentList.First();
}
If you want to be "clever" and do it all in one line (and I guess it would save a DB transaction too possibly) you could exchange your Where for an OrderBy and a Take.
So instead of:
).Where(i=>i.IsPrimary==true);
You could do:
).OrderBy( i => i.IsPrimary ? 0 : 1 ).Take(1);
This will prioritize any record that has an IsPrimary set to true, but it'll get one record regardless of whether any match.
Assuming that your intent is to retrieve one single record (there's at most one record with IsPrimary==true):
var query = (from s in...); //The whole query except the "where"
var resultStaffGua = query.SingleOrDefault(i=>i.IsPrimary==true) ?? query.First();
Otherwise, if the query could actually return more than one result:
var query = (from s in...);
var resultStaffGua = query.Where(i=>i.IsPrimary==true);
if(resultStaffGua.Count() == 0) resultStaffGua = new[] { query.First(); }
Account:
Id|Contact1|Contact2
Contact:
Id|status
I need a LINQ query that returns all of the accounts where contact1 and contact2 do not have a certain status.
var query = from a in accounts
join c1 in contact on a.contact1 equals c1.id
join c2 in contact on a.contact2 equals c2.id
where c1.status != 1 && c2.status != 1
select new {a.id}
I'm struggling with the logic. Clearly this isn't going to work, and doesn't. Just not sure how to join two tables on one in linq.
EDIT:
I discovered my issue is in most cases contact2 is null. I need some sort of conditional join that only occurs if a.contact2 is not null.
To clarify, the logic I'm attempting to achieve is: Retrieve all accounts where contact1 status does not equal 1. If contact1 == 1, check if contact2 == 1. If contact2 != 1 retrieve the account.
Running into issues because contact2 on the account is not always populated. When it's null, nothing is retrieved by my original query.
I think I've understood your logic correctly...
As long as either contact1 or contact2 on an account have a status other than 1 then retrieve the account. Only accounts where both contacts have a status of 1 are not returned. In the event that either contact is null it is ignored as you can't check the status.
var query = from a in accounts
from c in contacts
where c.Id == a.Contact1 || c.Id == a.Contact2
where c.Status != 1
select new { a.Id };
I have FinancialCompliances and Compliance tables. Below my query work flow is get one latest row .The problem is i have empty values in table because i deleted all rows in my table .But my below query is return one old rows .
var Compliance = (from c in datamodel.Compliances
join f in datamodel.FinancialCompliances on c.ComplianceId equals f.ComplianceId
where (c.VerifierId == userId || c.OwnerId == userId || c.UserId == userId) && (f.ComplianceId == c.ComplianceId)
orderby (f.AddedDate)
select f);
financialCompliance = Compliance.ToList().LastOrDefault();
What is the problem?
It sounds like you may be deleting your objects in the datamodel instance but not saving the changes and resetting the datamodel, thereby keeping the old records still in the context even if they aren't in the database. To be safe, try using a new context for this query.
Also, you may want to consider modifying the query to order the results decending and then selecting the top one rather than ordering them ascending and taking only the last one:
var Compliance = (from c in datamodel.Compliances
join f in datamodel.FinancialCompliances on c.ComplianceId equals f.ComplianceId
where (c.VerifierId == userId || c.OwnerId == userId || c.UserId == userId) && (f.ComplianceId == c.ComplianceId)
orderby (f.AddedDate) descending
select f);
financialCompliance = Compliance.FirstOrDefault();
Perhaps lastordefalt are sending the default value. Could you please confirm that you actually have real data in your object that is returned? I doubt that would be the case.
One obvious problem with your code is that you are calling ToList() before LastOrDefault(). This will cause your code to load all data from your storage into your application and context, and then from the result retrieving the last object. I suspect that this may cause some problems.
Try to skip your .ToList() and call LastOrDefault() directly.
I'm writing a query that looks like this:
var TheOutput = (from x in MyDC.MyTable
where.....
select new MyModel()
{
MyPropID = (from a in MyDC.MyOtherTable
where....
select a.ElementID).SingleOrDefault(),
MyPropData = (from a in MyDC.MyOtherTable
where a.ElementID == MyPropID
select a.ElementData).SingleOrDefault(),
}
I'm filling up MyModel with several properties from the database. Two of these properties are filled by reading another table. At the moment, I first read MyPropID to see if there's an element in the other table and then I read the other table again to get the data, regardless of whether or not an ID was retrieved.
How can I eliminate this second read if I know, from reading MyPropID and returning a null, that there's no data that matches the where a.ElementID == MyPropID clause.
Thanks.
var TheOutput = (from x in MyDC.MyTable
where.....
let id = (from a in MyDC.MyOtherTable
where....
select a.ElementID).SingleOrDefault()
select new MyModel()
{
MyPropID = id,
MyPropData = (from a in MyDC.MyOtherTable
where id != null && a.ElementID == id
select a.ElementData).SingleOrDefault()
}
If your code would create a single SQL statement from this query I do not think checking for null would matter. If this query would result in multiple SQL statements it might.