How can i use "COALESCE(SUM..." in linq? - c#

i try to use sum and Coalesce . How can i translate to linq?
SELECT #SumQtyOut=COALESCE(SUM(Qty),0) FROM dbo.StockMovement WHERE FromLocationType=#FromLocationType AND
* FromNo=#FromNo AND FromSeq=#FromSeq AND ItemTypeNo=#ItemTypeNo AND ItemID=#ItemID
i do sometihng :
using (StockProcedureDataContext stock = new StockProcedureDataContext())
{
SumQtyOut = from s in stock.StockMovements
where s.FromLocationType == FromLocationType &&
s.FromNo== FromNo &&
s.FromSeq == FromSeq &&
s.ItemTypeNo == ItemTypeNo &&
s.ItemID == ItemID select
}

This snippet should yield the result you are looking for.
using (StockProcedureDataContext stock = new StockProcedureDataContext())
{
var items = from s in stock.StockMovements
where s.FromLocationType == FromLocationType &&
s.FromNo== FromNo &&
s.FromSeq == FromSeq &&
s.ItemTypeNo == ItemTypeNo &&
s.ItemID == ItemID
select s.Qty ?? 0;
SumQtyOut = items.Sum(x => x);
}
select s.Qty ?? 0 returns 0 if s.Qty is null. items.Sum(x => x) summs up the quantities you have selected.

Related

Refactor and reduce cyclomatic complexity with LINQ

I have a method that I feel like could be refactored more efficiently with LINQ.
The purpose of the function is to use some logic to determine which phone number to return. The logic is: Any returned number must be sms_capable. If a number was last used for an rx, use it, otherwise return the first valid number by type in this order: Other, Home, Office
string GetDefaultSMSPhoneNumber(IEnumerable<PhoneNumbers> patientNumbers)
{
const int PHONE_TYPE_HOME = 1;
const int PHONE_TYPE_OFFICE = 3;
const int PHONE_TYPE_OTHER = 9;
var phoneNumberByType = patientNumbers.Where(p => p.sms_capable == 1).GroupBy(p => p.phone_type_id);
// Select the phone number last used in creating a prescription
if (patientNumbers.Where(p => p.sms_capable == 1 && p.last_used_for_rx == 1).Count() > 0)
{
return patientNumbers.Where(p => p.sms_capable == 1 && p.last_used_for_rx == 1).FirstOrDefault().phone_number;
}
// If no number has been used, select a configured SMS number in the following order (Other, Home, Office)
if (patientNumbers.Where(p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_OTHER).Count() > 0)
{
return patientNumbers.Where(p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_OTHER).FirstOrDefault().phone_number;
}
// If no number has been used, select a configured SMS number in the following order (Other, Home, Office)
if (patientNumbers.Where(p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_HOME).Count() > 0)
{
return patientNumbers.Where(p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_HOME).FirstOrDefault().phone_number;
}
// If no number has been used, select a configured SMS number in the following order (Other, Home, Office)
if (patientNumbers.Where(p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_OFFICE).Count() > 0)
{
return patientNumbers.Where(p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_OFFICE).FirstOrDefault().phone_number;
}
return string.Empty;
}
I know the first thing I can do is filter the list to only sms_capable numbers. I feel like I should be able to use .GroupBy to group the numbers by there type, but after they're grouped I'm not sure how to return the first non empty value? I feel like I'm looking for a way to coalesce in linq?
string GetDefaultSMSPhoneNumber(IEnumerable<PhoneNumbers> patientNumbers)
{
const int PHONE_TYPE_HOME = 1;
const int PHONE_TYPE_OFFICE = 3;
const int PHONE_TYPE_OTHER = 9;
var phoneNumberByType = patientNumbers.Where(p => p.sms_capable == 1).GroupBy(p => p.phone_type_id);
var phoneNumber = patientNumbers.FirstOrDefault(p => p.sms_capable == 1 && p.last_used_for_rx == 1)?.phone_number;
// Doesn't work
if (string.IsNullOrEmpty(phoneNumber))
{
var number = phoneNumberByType.FirstOrDefault(p => p.Key == PHONE_TYPE_OTHER && p.Where(x => !string.IsNullOrEmpty(x.phone_number)) ||
(p.Key == PHONE_TYPE_HOME && p.Where(x => !string.IsNullOrEmpty(x.phone_number)) ||
(p.Key == PHONE_TYPE_OFFICE && p.Where(x => !string.IsNullOrEmpty(x.phone_number))));
}
If you need matching against predicates in specific order you can create a collection of Func<PhoneNumbers, bool> and iterate it (also if PhoneNumbers is a class or record then you don't need Count, if it is not, better use Any instead of count):
string GetDefaultSMSPhoneNumber(IEnumerable<PhoneNumbers> patientNumbers)
{
const int PHONE_TYPE_HOME = 1;
const int PHONE_TYPE_OFFICE = 3;
const int PHONE_TYPE_OTHER = 9;
var predicates = new List<Func<PhoneNumbers, bool>>()
{
p => p.sms_capable == 1 && p.last_used_for_rx == 1,
p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_OTHER,
p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_HOME,
p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_OFFICE
}; // Can be moved to static field
// prevent potential multiple materialization of the source
var enumerated = patientNumbers as ICollection<PhoneNumbers> ?? patientNumbers.ToArray();
foreach (var predicate in predicates)
{
var firstOrDefault = enumerated.FirstOrDefault(predicate);
if (firstOrDefault is not null)
{
return firstOrDefault.phone_number;
}
}
return string.Empty;
}
Also in this particular case you can "prefilter" the enumerated with .Where(p => p.sms_capable == 1) to improve performance a bit:
// ...
var enumerated = patientNumbers
.Where(p => p.sms_capable == 1)
.ToArray();
var predicates = new List<Func<PhoneNumbers, bool>>()
{
p => p.last_used_for_rx == 1,
p => p.phone_type_id == PHONE_TYPE_OTHER,
p => p.phone_type_id == PHONE_TYPE_HOME,
p => p.phone_type_id == PHONE_TYPE_OFFICE
};
// ...
This isnt using linq, but you can refactor this by putting some of the complexity into their own methods
private IEnumerable<IGrouping<int, PhoneNumbers>> GetSmsCapablePhoneNumbersByType(IEnumerable<PhoneNumbers> patientNumbers)
{
return patientNumbers.Where(p => p.sms_capable == 1).GroupBy(p => p.phone_type_id);
}
private PhoneNumbers GetLastUsedSmsNumber(IEnumerable<PhoneNumbers> patientNumbers)
{
return patientNumbers.FirstOrDefault(p => p.sms_capable == 1 && p.last_used_for_rx == 1);
}
private PhoneNumbers GetFirstSmsNumberByType(IEnumerable<PhoneNumbers> patientNumbers, int phoneTypeId)
{
return patientNumbers.FirstOrDefault(p => p.sms_capable == 1 && p.phone_type_id == phoneTypeId);
}
public string GetDefaultSMSPhoneNumber(IEnumerable<PhoneNumbers> patientNumbers)
{
var phoneNumberByType = GetSmsCapablePhoneNumbersByType(patientNumbers);
var lastUsedSmsNumber = GetLastUsedSmsNumber(patientNumbers);
if (lastUsedSmsNumber != null)
{
return lastUsedSmsNumber.phone_number;
}
var defaultSmsNumber = GetFirstSmsNumberByType(patientNumbers, PHONE_TYPE_OTHER)
?? GetFirstSmsNumberByType(patientNumbers, PHONE_TYPE_HOME)
?? GetFirstSmsNumberByType(patientNumbers, PHONE_TYPE_OFFICE);
if (defaultSmsNumber != null)
{
return defaultSmsNumber.phone_number;
}
return string.Empty;
}
If you do it correctly, your method names should describe exactly whats happening, so when somone else reads your code they should be able to follow whats happening by reading the method names (This also means there is less need for comments)

How to write a linq query to exclude some of the records?

This is my LINQ
IList<string> ExceptList = new List<string>() { "045C388E96", "C9B735E166", "02860EB192", "2401016471" };
var listusers = context.USER_INFO.Where(x => x.ACTIVATED
&& x.COMP.EQUIPMENT.Count(y => y.STATUS == (int)STATUSEQ.ACTIVE) > 0
&& (x.LAST_LOGIN < time)
&& !ExceptList.Contains(x.COMP.CODE)
&& !x.IS_LOCK
|| !x.COMP.IS_LOCK)
.Select(x => new EmailOutOfDateLoginModel
{
COMPCode = x.COMP.CODE,
First_Name = x.FIRST_NAME,
Last_Name = x.LAST_NAME,
Total_EQ = x.COMP.EQUIPMENT.Count(y => y.STATUS == (int)STATUSEQ.ACTIVE),
User_Email = x.USER_EMAIL
}).ToList();
I am not sure why my ExceptList is not working. I want to exclude any record that contaisn any of the CODE in the ExceptList
Put parentheses around the expressions containing the && logic. The || at the end is only matched with the !x.IS_LOCK || !x.COMP.IS_LOCK otherwise.
According your linq all records where (!x.COMP.IS_LOCK==true) will be included in the query. Try this "where" part:
.Where(x => x.ACTIVATED
&& x.COMP.EQUIPMENT.Count(y => y.STATUS == (int)STATUSEQ.ACTIVE) > 0
&& (x.LAST_LOGIN < time)
&& !ExceptList.Contains(x.COMP.CODE)
&& !(x.IS_LOCK && x.COMP.IS_LOCK))

Adding additional linq where clauses based on variables

I'm trying to add additional where clauses to a linq query depending on what variable results are passed to a function.
var allFeedback =
from f in _unitOfWork.Feedback.All()
join b in _unitOfWork.Bookings.All() on f.CourseBookingID equals b.CourseBookingID
join cb in _unitOfWork.CourseBookings.All() on f.CourseBookingID equals cb.CourseBookingID
where b.SiteID == siteID && b.Date >= fromDate && b.Date <= to && b.CancelledID == null
select f;
if (courseID > 0)
{
allFeedback.Where(f => f.CourseBooking.CourseID == courseID);
}
if (facilitatorID == 0)
{
allFeedback.Where(f => f.CourseBooking.FacilitatorID == null);
}
else if (facilitatorID > 0)
{
allFeedback.Where(f => f.CourseBooking.FacilitatorID == facilitatorID);
}
allFeedback.ToList();
I want to add the where clauses to the original query "allFeedback" but when the query is executed the additional clauses are ignored.
Is this possible?
yes its possible just do :
if (courseID > 0)
{
allFeedback = allFeedback.Where(f => f.CourseBooking.CourseID == courseID);
}
if (facilitatorID == 0)
{
allFeedback = allFeedback.Where(f => f.CourseBooking.FacilitatorID == null);
}
else if (facilitatorID > 0)
{
allFeedback = allFeedback.Where(f => f.CourseBooking.FacilitatorID == facilitatorID);
}
You just forgot to assign the result to the variable.

How to write below sql query in linq c# where some of paramteres will be null sometimes

I have following query in sql,
select * from dbo.WaitingLists
where WaitingListTypeId in (1)
or StakeBuyInId in (Select StakeBuyInId from dbo.WaitingLists where StakeBuyInId in (5) and
WaitingListTypeId = 2)
in this, sometimes StakeBuyInId will be null or WaitingListTypeId will ne null. I want to perform this query via linq c# in following code.
public GameListItem[] GetMyWaitingList(Guid UserId, int LocalWaitingListTypeId, int GlobalWaitingListTypeId, int[] StakeBuyInIds)
{
ProviderDB db = new ProviderDB();
List<GameListItem> objtempGameListItem = new List<GameListItem>();
List<GameTables> objGameTablesList = new List<GameTables>();
var objWaitingListUser = db.WaitingLists.Where(x => x.UserId.Equals(UserId));
if (LocalWaitingListTypeId > 0 || (GlobalWaitingListTypeId > 0 && StakeBuyInIds != null))
{
objWaitingListUser = objWaitingListUser.Where(x => x.WaitingListTypeId == LocalWaitingListTypeId || (x.WaitingListTypeId == GlobalWaitingListTypeId
&& StakeBuyInIds != null ? StakeBuyInIds.Contains((Int32)x.StakeBuyInId) : true)
);
}
return objtempGameListItem.ToArray();
}
Here StakeBuyInIds int[] will be sometimes null, then how will i perform linq operation for above sql query. Thanks for any help.
You could probably just check for null outside of your expression, like this:
if (LocalWaitingListTypeId > 0 || (GlobalWaitingListTypeId > 0 && StakeBuyInIds != null))
{
if (StakeBuyInIds != null)
{
objWaitingListUser = objWaitingListUser.Where(
x => x.WaitingListTypeId == LocalWaitingListTypeId ||
(x.WaitingListTypeId == GlobalWaitingListTypeId &&
StakeBuyInIds.Contains((Int32)x.StakeBuyInId));
} else {
objWaitingListUser = objWaitingListUser.Where(
x => x.WaitingListTypeId == LocalWaitingListTypeId ||
x.WaitingListTypeId == GlobalWaitingListTypeId);
}
}
You might also be able to do this:
if (LocalWaitingListTypeId > 0 || (GlobalWaitingListTypeId > 0 && StakeBuyInIds != null))
{
var arrayNull = StakeBuyInIds != null;
var array = StakeBuyInIds ?? new int[0];
objWaitingListUser = objWaitingListUser.Where(
x => x.WaitingListTypeId == LocalWaitingListTypeId ||
(x.WaitingListTypeId == GlobalWaitingListTypeId &&
(arrayNotNull || array.Contains((Int32)x.StakeBuyInId)));
}
It effect it tests for null outside of the query, but ensures that it cannot be null when actually executing the query.
The waitingListTypeId and stakeBuyinId should be nullable int in your relational object WaitingList.
List<int?> WaitingListTypeIds=new List(new int?[]{1});
var StakeBuyInIds=from w in WaitingListsCollection where new List<int?>(new int?[]{5}).Contains(w.StakeBuyInId) && w.WaitingListTypeId = 2;
var output= from w in WaitingListsCollection where WaitingListTypeIds.Contains(w.WaitingListTypeId) || StakeBuyInIds.Contains(w.StakebuyInId)

How to improve the LINQ query?

This is what i got:
int? productID = (ClientProduct != null ? (int?)ClientProduct.ProductID : null);
result = (from po in ((Chase_Media_Pro_Entity_Model)this.NavigationItem.ObjectContext).raPurchaseOrder_List
where po.ClientID == Client.CustomerID
&& ((object.Equals(po.ClientProductID, productID)) || (po.ClientProductID == (productID ?? po.ClientProductID)))
&& (po.Is_Active == (isActive ?? po.Is_Active))
&& (po.IsApproved == (isApproved ?? po.IsApproved))
orderby po.Is_Active descending, po.IsApproved ascending
select po);
Is there a way to improve this line:
&& ((object.Equals(po.ClientProductID, productID)) || (po.ClientProductID == (productID ?? po.ClientProductID)))
This was the only way i could get the right results.
&& (!productID.HasValue || (productID == po.ClientProductID))
How about
&& ((productID.HasValue && po.ClientProductID.HasValue) ? po.ClientProductID.Value = productID.Value : true)

Categories

Resources