if clause in linq c# [duplicate] - c#

Is it possible to use If Else conditional in a LINQ query?
Something like
from p in db.products
if p.price>0
select new
{
Owner=from q in db.Users
select q.Name
}
else
select new
{
Owner = from r in db.ExternalUsers
select r.Name
}

This might work...
from p in db.products
select new
{
Owner = (p.price > 0 ?
from q in db.Users select q.Name :
from r in db.ExternalUsers select r.Name)
}

I assume from db that this is LINQ-to-SQL / Entity Framework / similar (not LINQ-to-Objects);
Generally, you do better with the conditional syntax ( a ? b : c) - however, I don't know if it will work with your different queries like that (after all, how would your write the TSQL?).
For a trivial example of the type of thing you can do:
select new {p.PriceID, Type = p.Price > 0 ? "debit" : "credit" };
You can do much richer things, but I really doubt you can pick the table in the conditional. You're welcome to try, of course...

Answer above is not suitable for complicate Linq expression.
All you need is:
// set up the "main query"
var test = from p in _db.test select _db.test;
// if str1 is not null, add a where-condition
if(str1 != null)
{
test = test.Where(p => p.test == str);
}

var result = _context.Employees
.Where(x => !x.IsDeleted)
.Where(x => x.ClientId > (clientId > 0 ? clientId - 1 : -1))
.Where(x => x.ClientId < (clientId > 0 ? clientId + 1 : 1000))
.Where(x => x.ContractorFlag == employeeFlag);
return result;
If clientId = 0 we want ALL employees,. but for any clientId between 1 and 999 we want only clients with that ID. I was having issues with seperate LINQ statements not being the same (Deleted/Clients filters need to be on all queries), so by add these two lines it works (all be it until we have 999+ clients - which would be a happy re-factor day!!

you should change like this:
private string getValue(float price)
{
if(price >0)
return "debit";
return "credit";
}
//Get value like this
select new {p.PriceID, Type = getValue(p.Price)};

my example:
companyNamesFirst = this.model.CustomerDisplayList.Where(a => a.CompanyFirst != null ? a.CompanyFirst.StartsWith(typedChars.ToLower())) : false).Select(b => b.CompanyFirst).Distinct().ToList();

If you are using LinQ with EF Core, an easy example can be this-
var orderedData = await _dbContext.ModelName
.OrderBy(c => c.Name.Length.Length > 4 ? c.Name:c.SuperTerm.Name.IndexOf(searchValue))
.ThenBy(t => t.Producer)
.TolistAsync();

Related

how to use linq to return a value from 4 tables

I am reasonably new to Linq and it seems quite easy to iuse but I am having an issue when trying to extract a value from a table that is linked/constrained by 3 other tables.
I have this in my SQL DB:
I am using Asp.Net 4 and Entity Framework 6.
I have as a parameter the 'DatabaseName'.
I ultimately want to get the SubscriptionRef that is assigned to this name.
I could do this step-by-step (ie using multiple linqs) but I thought it would look 'clean' using just 1 linq statment.
I have got as far as this:
var names = o.RegisteredNames.Where(d => d.DatabaseName == DBName).Where(d => d.ClientNames.Where(f => f.ClientId == f.Client.ClientId).FirstOrDefault();
But I get the error:
Cannot implicitly convert type 'Services.ClientName' to 'bool'
You have a Problem here:
d => d.ClientNames.Where(f => f.ClientId == f.Client.ClientId)
f => ... returns a single ClientName or null, which causes your error, because there should be a boolean.
If you want this first value or null, you should replace
.Where(d => d.ClientNames ...
//with
.Select(d => d.ClientNames ...
Try this:
o.RegisteredNames.First(d => d.DatabaseName == DBName).ClientNames.Select(x=>x.Client.Subscription.SubscriptionRef)
It should give you list go SubscriptionRef.
You can try with one LINQ query like...
var names = o.RegisteredNames.Where(d => d.DatabaseName == DBName ).FirstOrDefault();
You might wanna try sql style:
var client = from c in db.Clients
join cn in db.ClientNames on c.ClientId equals cn.ClientId
join rn in db.RegisteredNames on cn.RegisteredNamesId equals rn.RegisteredNameId
where rn.DatabaseName == "YourDBName"
select c;
But it also depends on how your objects were built.
Try using join:
var names = (
from names in o.RegisteredNames.Where(d => d.DatabaseName == DBName)
join cnames in o.ClientNames on names.RegisteredNamesId equals cnames.RegisteredNamesId
select cnames.ClientId
).FirstOrDefault();
Add as many joins as you want.
Try this
It works in List,
var option1= o.RegisteredNames
.Where(g => g.DbName == "YourDbName")
.Where(h => h.ClientNames.Any(f => f == 5))
.FirstOrDefault();
var option2= o.RegisteredNames
.FirstOrDefault(h => h.DbName == "Name" && h.ClientNames.Any(j => j == 1));

OUTER APPLY is not supported in this LINQ query

I need to run this query in a oracle 11.2 database, but the generated query contains a "OUTER APPLY". How can I solve it ?
var query = from r in Ctx.Reg
let status_1 = (r.Hist.OrderByDescending(o => o.Id).FirstOrDefault(h => h.RegId == r.Id).Status == 1)
let status_2 = (r.Hist.OrderByDescending(o => o.Id).Skip(1).FirstOrDefault(h => h.RegId == r.Id).Status == 2)
select new
{
r.Id,
...
status_1,
status_2
};
OUTER APPLY is generated by your let statement expressions. You can avoid it by turning them into EXISTS translatable expressions using the equivalent Any based LINQ constructs:
var query = from r in Ctx.Reg
let status_1 = r.Hist.OrderByDescending(h => h.Id).Take(1).Any(h => h.Status == 1)
let status_2 = r.Hist.OrderByDescending(h => h.Id).Skip(1).Take(1).Any(h => h.Status == 2)
select new
{
r.Id,
...
status_1,
status_2
};
Note that h.RegId == r.Id is not needed because that is implied by r.Hist navigation property.

Union on datatable

How I will convert this SQL query in Linq, sorry but I am not that much expert in LINQ
select ConnectionId
from LearnerConnections
where LearnerId = 1
union
select LearnerId
from LearnerConnections
where ConnectionId = 1
also can I write the DataTable methode to get the result (like DataTable.Select() method)?
thanks in advance
something like that
LearnerConnections.Where(x => x.LearnerId == 1)
.Select(m => m.ConnectionId)
.Union(LearnerConnections.Where(l => l.ConnectionId ==1)
.Select(lc => lc.LearnerId)
);
with a datatable, it should look like
dtLearnerConnections.AsEnumerable()
.Where(m => m.Field<int>("LearnerId") == 1)
.Select(m => m.Field<int>("ConnectionId"))
.Union(dtLearnerConnections.AsEnumerable()
.Where(x => x.Field<int>("ConnectionId") == 1)
.Select(x => x.Field<int>("LearnerId"))
);
May this will helpful
var results = (from l in LearnerConnections where l.LearnerId == 1
select l.ConnectionId).Union(from a in LearnerConnections
where a.ConnectionId == 1 select l.LeaenerId);
var result = (from lc in LearnerConnections
where lc.LearnerId == 1
select lc.ConnectionId)
.Union
(from lc in LearnerConnections
where lc.ConnectionId == 1
select lc.LearnerId);
If you are using DataTables, this involves the use of LINQ to DataSet. This SO question might also help you.

LINQ Using Max() to select a single row

I'm using LINQ on an IQueryable returned from NHibernate and I need to select the row with the maximum value(s) in a couple of fields.
I've simplified the bit that I'm sticking on. I need to select the one row from my table with the maximum value in one field.
var table = new Table { new Row(id: 1, status: 10), new Row(id: 2, status: 20) }
from u in table
group u by 1 into g
where u.Status == g.Max(u => u.Status)
select u
This is incorrect but I can't work out the right form.
BTW, what I'm actually trying to achieve is approximately this:
var clientAddress = this.repository.GetAll()
.GroupBy(a => a)
.SelectMany(
g =>
g.Where(
a =>
a.Reference == clientReference &&
a.Status == ClientStatus.Live &&
a.AddressReference == g.Max(x => x.AddressReference) &&
a.StartDate == g.Max(x => x.StartDate)))
.SingleOrDefault();
I started with the above lambda but I've been using LINQPad to try and work out the syntax for selecting the Max().
UPDATE
Removing the GroupBy was key.
var all = this.repository.GetAll();
var address = all
.Where(
a =>
a.Reference == clientReference &&
a.Status == ClientStatus.Live &&
a.StartDate == all.Max(x => x.StartDate) &&
a.AddressReference == all.Max(x => x.AddressReference))
.SingleOrDefault();
I don't see why you are grouping here.
Try this:
var maxValue = table.Max(x => x.Status)
var result = table.First(x => x.Status == maxValue);
An alternate approach that would iterate table only once would be this:
var result = table.OrderByDescending(x => x.Status).First();
This is helpful if table is an IEnumerable<T> that is not present in memory or that is calculated on the fly.
You can also do:
(from u in table
orderby u.Status descending
select u).Take(1);
You can group by status and select a row from the largest group:
table.GroupBy(r => r.Status).OrderByDescending(g => g.Key).First().First();
The first First() gets the first group (the set of rows with the largest status); the second First() gets the first row in that group.
If the status is always unqiue, you can replace the second First() with Single().
Addressing the first question, if you need to take several rows grouped by certain criteria with the other column with max value you can do something like this:
var query =
from u1 in table
join u2 in (
from u in table
group u by u.GroupId into g
select new { GroupId = g.Key, MaxStatus = g.Max(x => x.Status) }
) on new { u1.GroupId, u1.Status } equals new { u2.GroupId, Status = u2.MaxStatus}
select u1;
What about using Aggregate?
It's better than
Select max
Select by max value
since it only scans the array once.
var maxRow = table.Aggregate(
(a, b) => a.Status > b.Status ? a : b // whatever you need to compare
);
More one example:
Follow:
qryAux = (from q in qryAux where
q.OrdSeq == (from pp in Sessao.Query<NameTable>() where pp.FieldPk
== q.FieldPk select pp.OrdSeq).Max() select q);
Equals:
select t.* from nametable t where t.OrdSeq =
(select max(t2.OrdSeq) from nametable t2 where t2.FieldPk= t.FieldPk)
Simply in one line:
var result = table.First(x => x.Status == table.Max(y => y.Status));
Notice that there are two action.
the inner action is for finding the max value,
the outer action is for get the desired object.

Filter Results Before FirstOrDefault() and Then Using FirstOrDefault()

I want to do something like that;
Context.Users.Include("Addresses", a => a.IsRowDeleted == false).FirstOrDefault(u => u.UserId == 5);
I mean; I want to filter included entities but not always, its also have to be optional.
What is the best solution for this? Please help me,
You cannot filter eager loaded data in EF. Include operation doesn't support filtering or sorting.
You must use either projection to custom type (or anonymous type):
var query = from u in context.Users
where u.UserId == 5
select new UserFiltered
{
User = u,
Addresses = u.Addresses.Where(a => !a.IsRowDeleted)
};
UserFiltered u = query.FirstOrDefault();
Or you must devide your query into two separated queries and use explicit loading:
context.ContextOptions.LazyLoadingEnabled = false;
var user = context.Users.FirstOrDefault(u => u.UserId == 5);
((EntityCollection<Address>)user.Addresses)
.CreateSourceQuery()
.Where(a => !a.IsRowDeleted)
.Execute();
Or you can simply use two queries:
var user = context.Users.FirstOrDefault(u => u.UserId == 5);
var addresses = context.Addresses.Where(a => a.User.UserId == 5 && !a.IsRowDeleted).ToList();
Do you mean something like (warning: untested code):
Context.Users.SingleOrDefault(u => u.Addresses.Where(a => a.IsRowDeleted == false).Count > 0) && u.UserId == 5);

Categories