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.
Related
I have three tables and one input value. As a first step, based on the #Input, I need to fetch DSType from DSTypes table. Now again I need to compare DSType of DSTypes with RTInput table's IType column value. If RTInput table has matching records then need to fetch the ID column value alone otherwise NULL should be assigned.
I achieved this logic in SQL but unable to achieve the same in Lambda expression.
I tried some code from google but that is not returning correct value.
DECLARE #ID
#ID = SELECT ID FROM DSMaster Where DSTId = #Input
SELECT RTI.ID FROM DSTypes(NOLOCK) DST
LEFT JOIN RTInput(NOLOCK) RTI
ON RTRIM(LTRIM(DST.DSType)) = RTRIM(LTRIM(RTI.IType))
WHERE DST.ID = #ID
Lambda expression which I tried:
using (BEContext beContext = new BEContext())
{
var mData = beContext.DSMaster.Where(r => r.DSTId = inputvalue);
var Id = beContext.RTInput.Join(beContext.DSTypes.Where(dst => dst.ID == mData.Id )).Select(z => z.ID).FirstOrDefault();
}
I think this may help.
using {BEContext beContext = new BEContext()){
var mData = (from p in beContext.DSMaster.Where(r=>r.DSTId == inputvalue)
join pr in beContext.RTInput on p.Id equals dst.ID
select new {
//select what you want
}).FirstOrDefault();
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(); }
I'm trying to figure out how I can convert this same SQL query into a Linq query, but I'm not seeing a way to do NOT IN with Linq like you can with SQL.
SELECT COUNT(DISTINCT ID)
FROM References
WHERE ID NOT IN (
SELECT DISTINCT ID
FROM References
WHERE STATUS = 'COMPLETED')
AND STATUS = 'FAILED'
I need to know how many distinct [ID] values exist that contain a [Status] value of "FAILED" that do not also have a [Status] of "COMPLETED". Basically, if there is a failed without a completed, i need the distinct amount for that.
var query_5 = from r in Records where r.ID NOT IN(from r in Records where
r.Record_Status == "COMPLETED" ) && (r.Record_Status == "FAILED")
select r.ID;
var rec_5 = query_5;
Console.WriteLine(rec_5.Distinct());
This was my attempt to do it, but I'm receiving numerous errors as it is not the right way to code it. Any examples on how to accomplish this would be much appreciated!
This is how the rest of my setup is looking.
public class References
{
public string ID;
public string Record_Status;
}
public static List<References> Records = new List<References>
{
};
The rough equivalent of a (not) in is using Contains(). Since the inner subquery doesn't reference the outer, you could write it like this:
var completedIds =
(from r in ctx.References
where r.Status == "COMPLETED"
select r.Id).Distinct();
var count =
(from r in ctx.References
where !completedIds.Contains(r.ID)
where r.Status == "FAILED"
select r.Id).Distinct().Count();
You could use the Except method:
var completed =
(from r in References
where r.Record_Status == "COMPLETED"
select r.Id).Distinct();
var failed =
(from r in References
where r.Record_Status == "FAILED"
select r.Id).Distinct();
var countFailedNotCompleted = failed.Except(completed).Count();
Note that this does not require using Contains during iteration. The sequences will be compared all at once within the Except method. You could also tack ToArray() on to each of the distinct sequences to ensure minimal iteration in the case where you want to use those sequences more than once.
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()
...