HI,
I have Ling Table with MyObject.
It has got fields:
Id
Number
Name
There is a method that adds ne MyObject to Database. In partial class MyOBject Im implementing OnValidate method. I need to check if there is already a row with such number and name.
The problem is where this values are nulls (for this example both can be)
var result = from m in myContext.MyObjects where m.Number == this.Number &&
m.Name == this.Name
select m;
if(result.Count > 0) {
throw ...
}
if for example this.Name = null and r.Name = null and m.Number == this.Number no rows are selected and I dont know why :/
Any hints on how can I check if row with excactly the same values in fileds except Id (which is PK) are already in database ?
Thanks for help
Linq-To-SQL has a problem when you give it an Equals expression with a nullable parameter that happens to be null - the query it creates is incorrect. You can read all about it here: http://riotingbits.com/2009/int-null-or-why-it-misbehaves-in-linq-to-sql/
You have to treat the cases where this.Number or this.Name are null separately.
IQueryable<MyObject> result = null;
if (this.Name == null && this.Number == null)
result = from m in myContext.MyObjects
where m.Name == null && m.Number == null
select m;
else if (this.Name == null)
result = from m in myContext.MyObjects
where m.Name == null && m.Number == this.Number
select m;
else if (this.Number == null)
result = from m in myContext.MyObjects
where m.Name == this.Name && m.Number == null
select m;
else
result = from m in myContext.MyObjects
where m.Name == this.Name && m.Number == this.Number
select m;
Try this:
var result = from m in myContext.MyObjects
where (((m.Number == this.Number) || (m.Number == null)) &&
((m.Name == this.Name) || (m.Name == null)))
select m;
SQL query that LINQ generates would be:
SELECT Whatewer yourObject contains
FROM yourTable as [t0]
WHERE (([t0].[Number] = #p0) OR ([t0].[Number] IS NULL))
AND (([t0].[Name] = #p1) OR ([t0].[Name] IS NULL))
Related
I have EF Employee table with fields EmpNo, FirstName, LastName, Email. And to create LINQ to search all columns and return existing record. If one or more fields is null or empty the return result based on existing data. I wrote code:
public static int Search(EmployeeDt emp)
{
using (EF.Model1 context = new EF.Model1)
{
List<string> employee = context.Employees.Where(a => (a.EmpNo == null || a.EmpNo == emp.EmpNo)
&& (b => (b.FirstName == null || b.FirstName == emp.FirstName)
&& (c => (c.LastName == null || c.LastName == emp.LastName)).ToList();
return result;
}
}
But code which I tried to write isn't correct. How to write LINQ for my case?
Thanks.
You don't need reuse a=> in second condition and compare emp.FirstName with null not a variable, change your code to
List<string> employee = context.Employees.Where(a => (emp.FirstName == null || a.FirstName == emp.FirstName)
&& (emp.LastName == null || a.LastName == emp.LastName)
&& (emp.EmpNo == null || a.EmpNo == emp.EmpNo)).ToList()
Below is a piece of code that I do in a loop:
At the beginning, in the first query, I get a list of location IDs. The list can be long.
Ultimately, I need to find for which LocationId FamiliId > 0
I have it done in a loop but I would like to do it in one question. Is it possible and if so how?
var locationIds = context.TblUsersDistricts
.Where(d => d.UserId == userId && d.ValidityTo == null)
.Select(x => x.LocationId).ToList();
int familyId = 0;
foreach(var item in locationIds) {
familyId = (from I in context.TblInsuree
join F in imisContext.TblFamilies on I.FamilyId equals F.FamilyId
join V in imisContext.TblVillages on F.LocationId equals V.VillageId
join W in imisContext.TblWards on V.WardId equals W.WardId
join D in imisContext.TblDistricts on W.DistrictId equals D.DistrictId
where(I.Chfid == chfid &&
D.DistrictId == item &&
F.ValidityTo == null &&
I.ValidityTo == null &&
V.ValidityTo == null &&
W.ValidityTo == null &&
D.ValidityTo == null)
select F.FamilyId)
.FirstOrDefault();
if (familyId > 0) break;
};
It sounds like you want:
var familyId = (
from item in locationIds
from I in context.TblInsuree
// ... etc
&& D.ValidityTo == null)
select F.FamilyId)
.FirstOrDefault();
?
i am trying to convert the following SQL into LINQ and need some assistance with the nested select clauses for the paid_amount and paid_vat and also for the select within the where clause. Ignore the index things.
here is the SQL
SELECT
tramps.gl_transaction.debtor_uri,
tramps.debtor.account_no,
tramps.gl_transaction.uri as transaction_uri,
tramps.gl_transaction.base_currency_amount,
tramps.gl_transaction.base_currency_vat_amount,
(select IsNull(sum(gltr.base_currency_amount), 0.00)
from tramps.gl_transaction gltr
where gltr.sibling_uri = tramps.gl_transaction.uri) * (-1) as Paid_Amount ,
(select IsNull(sum(gltr.base_currency_vat_amount), 0.00)
from tramps.gl_transaction gltr
where gltr.sibling_uri = tramps.gl_transaction.uri) * (-1) as Paid_Vat ,
tramps.account.property_ref,
tramps.account.sub_ledger_code,
tramps.gl_transaction.transaction_type_code,
tramps.gl_transaction.transaction_description,
tramps.gl_transaction.effective_date
FROM tramps.account, tramps.chart WITH (INDEX (PK_CHART)), tramps.gl_transaction WITH (INDEX (glt_debtor_gen)) ,tramps.debtor, tramps.receivables_register , tramps.bank_account
WHERE tramps.chart.code = tramps.account.chart_code
AND tramps.gl_transaction.debtor_uri = tramps.debtor.uri
AND tramps.gl_transaction.account_uri = tramps.account.uri
AND tramps.receivables_register.uri = tramps.gl_transaction.receivables_register_uri
AND tramps.receivables_register.bank_account_uri = tramps.bank_account.uri
AND tramps.chart.control_account = 'Debtor'
AND tramps.gl_transaction.status = 'L'
AND tramps.gl_transaction.process_status = 'Released'
AND ( (tramps.gl_transaction.generated = 'C' AND tramps.gl_transaction.sibling_uri IS NULL AND tramps.gl_transaction.written_off <> 'Y')
OR (tramps.gl_transaction.generated = 'N' AND tramps.gl_transaction.sibling_uri IS NULL) )
AND (tramps.gl_transaction.base_currency_amount +
(select IsNull(sum(gltr.base_currency_amount), 0.00)
from tramps.gl_transaction gltr
where gltr.sibling_uri = tramps.gl_transaction.uri) <> 0.00 )
this is the LINQ i have managed to create so far, but i am struggling with the nested selects, the sum and the where clause
from acc in Accounts
join chart in Charts on acc.Chart_code equals chart.Code
join gltrans in Gl_transactions on acc.Uri equals gltrans.Account_uri
join debt in Debtors on gltrans.Debtor_uri equals debt.Uri
join recreg in Receivables_registers on gltrans.Receivables_register_uri equals recreg.Uri
join bankacc in Bank_accounts on recreg.Bank_account_uri equals bankacc.Uri
let paidcurrency = from gltrns in Gl_transactions
where gltrns.Sibling_uri == gltrans.Uri
select gltrns.Base_currency_amount
where
chart.Control_account == "Debtor"
&& gltrans.Status == "L"
&& gltrans.Process_status == "Released"
&& acc.Property_ref == 102979
&& ((gltrans.Generated == "C" && gltrans.Sibling_uri == null && gltrans.Written_off != "Y")
|| (gltrans.Generated == "N" && gltrans.Sibling_uri == null) )
select new
{
gltrans.Debtor_uri,
debt.Account_no,
gltrans.Uri,
gltrans.Base_currency_amount,
gltrans.Base_currency_vat_amount,
er = (decimal?)paidcurrency.Base_currency_vat_amount.Sum() ?? 0,
acc.Property_ref,
acc.Sub_ledger_code,
gltrans.Transaction_type_code,
gltrans.Transaction_description,
gltrans.Effective_date
}
This might help out a little. I blended in some fluent syntax to help translate the Sum functions. Let me know if some of these translations help as I can't check it directly without your schema and some data.
var result =
from acc in Accounts
join chart in Charts on acc.Chart_code equals chart.Code
join gltrans in Gl_transactions on acc.Uri equals gltrans.Account_uri
join debt in Debtors on gltrans.Debtor_uri equals debt.Uri
join recreg in Receivables_registers on gltrans.Receivables_register_uri equals recreg.Uri
join bankacc in Bank_accounts on recreg.Bank_account_uri equals bankacc.Uri
// query expression
//let paidcurrency = from gltrns in Gl_transactions
// where gltrns.Sibling_uri == gltrans.Uri
// select gltrns.Base_currency_amount
// change to fluent..
let paid_Amount = gltrans.Where(g => g.Sibling_uri == g.Uri)
.Select(g => g.Base_currency_amount * -1 ?? 0.00M).Sum()
// same for Vat..
let paid_Vat = gltrans.Where(g => g.Sibling_uri == g.Uri)
.Select(g => g.Base_currency_vat_amount * -1 ?? 0.00M).Sum()
// added another 'let' to use in the where clause..
let base_Currency = gltrans.Where(g => g.Sibling_uri == g.Uri)
.Select(g => g.Base_currenct_amount ?? 0.00M).Sum()
where
chart.Control_account == "Debtor"
&& gltrans.Status == "L"
&& gltrans.Process_status == "Released"
&& acc.Property_ref == 102979
&& (
(
gltrans.Generated == "C" &&
gltrans.Sibling_uri == null &&
gltrans.Written_off != "Y"
)
||
(
gltrans.Generated == "N" &&
gltrans.Sibling_uri == null
)
)
&& gltrans.Base_currency_amount + base_Currency != 0.00M
select new
{
gltrans.Debtor_uri,
debt.Account_no,
gltrans.Uri,
gltrans.Base_currency_amount,
gltrans.Base_currency_vat_amount,
//er = (decimal?)paidcurrency.Base_currency_vat_amount.Sum() ?? 0,
paid_Amount,
paid_Vat,
acc.Property_ref,
acc.Sub_ledger_code,
gltrans.Transaction_type_code,
gltrans.Transaction_description,
gltrans.Effective_date
};
In the below code:
var results = from service
in LogisticsService.GetTransportationModes<CarrierTransportationMode>
(
x => x.CarrierId == carrierRoleId &&
x.ParentTransportationModeId != null &&
!(x is LoadCarrierMode) &&
(x.ParentTransportationMode.TransportationModeStatus != null) &&
x.ParentTransportationMode.TransportationModeStatus.Value != TransportationModeStatus.Inactive
)
//.OrderByDescending(o => o.IsDefault)
//.ThenBy(t => t.ParentTransportationMode.Name)
orderby service.IsDefault descending, service.ParentTransportationMode.Name
select new
{
text = service.ParentTransportationMode.Name,
value = service.ParentTransportationMode.Id
};
If service.IsDefault is null, I need to skip orderby / thenby completely. So the code would execute as if there was no orderby present in the linq like below:
var results = from service
in LogisticsService.GetTransportationModes<CarrierTransportationMode>
(
x => x.CarrierId == carrierRoleId &&
x.ParentTransportationModeId != null &&
!(x is LoadCarrierMode) &&
(x.ParentTransportationMode.TransportationModeStatus != null) &&
x.ParentTransportationMode.TransportationModeStatus.Value != TransportationModeStatus.Inactive
)
select new
{
text = service.ParentTransportationMode.Name,
value = service.ParentTransportationMode.Id
};
I tried to modify the query with conditions like below:
.OrderByDescending(o => o.IsDefault.HasValue ? o.IsDefault : null)
.ThenBy(t => t.IsDefault.HasValue ? t.ParentTransportationMode.Name : null)
orderby !service.IsDefault.HasValue ? null: service.IsDefault descending, service.ParentTransportationMode.Name
But that didn't help.
Do I need to pass any special parameter in the orderby so that the ordering will never happen at all conditionally? any keyword like 'case' or so can be used? If so, how?
Would appreciate any help!.
Thanks!.
As you need to keep the order of the elements with service.IsDefault == null, an easy solution is to split your dataset into two parts (first service.IsDefault == null, second: service.IsDefault != null) sort the second part, then, concat:
var transportationModes = LogisticsService.GetTransportationModes<CarrierTransportationMode>(x =>
x.CarrierId == carrierRoleId &&
x.ParentTransportationModeId != null &&
!(x is LoadCarrierMode) &&
(x.ParentTransportationMode.TransportationModeStatus != null) &&
x.ParentTransportationMode.TransportationModeStatus.Value != TransportationModeStatus.Inactive)
var services = (from service in transportationModes
where service.IsDefault == null
select service).Concat
(from service in transportationModes
where service.IsDefault != null
orderby service.IsDefault descending, service.ParentTransportationMode.Name
select service);
var results = from service in services
select new
{
text = service.ParentTransportationMode.Name,
value = service.ParentTransportationMode.Id
};
I have a filter called serviceEntryFilter with a property System which could have values for instance EP1, EP2 OR EP1 and sometimes this filter would be null. If there are multiple values or a single value then the query (IN) clause runs fine . If the filter value is null then I get the following error:
Unable to create a constant value of type 'System.String[]'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
[HttpPost]
public ActionResult List(string ServiceEntryStatus, string ServiceEntryReconciled, string ServiceEntryReliabilityRecord, string ActiveServiceEntry,
int PageNo, ServiceEntryFilter serviceEntryFilter = null)
{
string[] systems = null;
var list = (from se in db.ServiceEntry
join r in db.RunLogEntry on se.RunLogEntryID equals r.ID into joinRunLogEntry
from r2 in joinRunLogEntry.DefaultIfEmpty()
join u in db.User on se.TechnicianID equals u.ID
join s in db.System1 on se.SystemID equals s.ID
where (
((se.RunLogEntryID == 0 || se.RunLogEntryID != null))
&& ((serviceEntryFilter.ID.HasValue == false) || (se.ID == serviceEntryFilter.ID.Value && serviceEntryFilter.ID.HasValue == true))
&& ((serviceEntryFilter.ServiceDateTime.HasValue == false) || (EntityFunctions.TruncateTime(se.ServiceDateTime) == EntityFunctions.TruncateTime(serviceEntryFilter.ServiceDateTime) && serviceEntryFilter.ServiceDateTime.HasValue == true))
&& ((serviceEntryFilter.RunDate.HasValue == false) || (EntityFunctions.TruncateTime(r2.RunDate) == EntityFunctions.TruncateTime(serviceEntryFilter.RunDate) && serviceEntryFilter.RunDate.HasValue == true))
&& ((serviceEntryFilter.Technician == null) || (u.FullName.Contains(serviceEntryFilter.Technician.Trim()) && serviceEntryFilter.Technician != null))
&& (
((ServiceEntryStatus == "O" && se.ServiceRequestClosed == false) ||
(ServiceEntryStatus == "C" && se.ServiceRequestClosed == true) ||
(ServiceEntryStatus == "A")
)
)
&& (
((ServiceEntryReliabilityRecord == null) ||
(ServiceEntryReliabilityRecord == "N" && se.ReliabilityRecord == false) ||
(ServiceEntryReliabilityRecord == "Y" && se.ReliabilityRecord == true) ||
(ServiceEntryReliabilityRecord == "A")
)
)
&& (
((ServiceEntryReconciled == null) ||
(ServiceEntryReconciled == "N" && se.Reconciled == false) ||
(ServiceEntryReconciled == "Y" && se.Reconciled == true) ||
(ServiceEntryReconciled == "A")
)
)
&& (
((ActiveServiceEntry == null) ||
(ActiveServiceEntry == "N" && se.Active == false) ||
(ActiveServiceEntry == "Y" && se.Active == true) ||
(ActiveServiceEntry == "A")
)
)
&& (
(s.PlatformID == platformID) || (platformID == 0)
)
&& ((serviceEntryFilter.System == null) || ((serviceEntryFilter.System != null) && systems.Contains(s.SystemFullName)))
)
orderby se.ID descending
select new ServiceSearchEntry()
{
ID = se.ID,
ServiceDateTime = se.ServiceDateTime,
Technician = u.FullName,
System = s.SystemFullName,
ReasonForFailure = se.ReasonForFailure,
RunDate = (r2 == null ? (DateTime?)null : r2.RunDate)
});
var listData = list.Skip((page - 1) * PageSize).Take(PageSize);
ServiceEntriesListViewModel viewModel = new ServiceEntriesListViewModel()
{
ServiceSearchEntry = listData,
PagingInfo = new PagingInfo
{
CurrentPage = page,
ItemsPerPage = PageSize,
TotalItems = list.Count()
}
};
}
The Issue:
The following clause is throwing an error when SystemFilter.System is NULL. It is null at times when users do not select values for it. Sample values are as follows:
EP1, EP2
EP1
TP2, TP3, TP4
&& ((serviceEntryFilter.System == null) || ((serviceEntryFilter.System != null) && systems.Contains(s.SystemFullName)))
If it has a value, then I put it in an array and its works like a charm, its just when its null.
The issue is that everything inside a LINQ statement will get translated to SQL. There isn't really a conditional statement that I see here that says "don't try to add this array filter if it's actually null".
I would initialize the systems array to a zero length array, overwrite it if the filter.Systems is not null, and then make my linq statement as follows:
systems.Contains(s.SystemFullName)
Don't include that null checking inside the LINQ statement as it's not doing what you are expecting.
To build conditional LINQ statements, you might want to look at PredicateBuilder: http://www.albahari.com/nutshell/predicatebuilder.aspx
This is a known limitation with Linq to Entities - see section on Referencing Non-Scalar Variables Not Supported.
In otherwords, this line:
systems.Contains(s.SystemFullName)
can't be used as part of your EF query.