If Else Statement inside entity query - c#

im trying to produce an if else statement inside entity query, i have the following code:
var asset = dbContext.Set<Asset>()
.Include(x => x.Item)
.Include(x => x.Item.ItemDetailSubCategory)
.Include(x => x.AssetCurrentStatus)
.Include(x => x.AssetCurrentStatus.AssetCondition)
.Include(x => x.Currency)
.Include(x => x.AssetCurrentStatus.AssetAccessories)
.Where(x => x.AssetCurrentStatus.Room.Floor.IsActive == true)
.Where(x => x.AssetCurrentStatus.Room.Floor.Building.IsActive == true)
.Where(x => x.AssetCurrentStatus.Room.IsActive == true)
.ToList();
now i expect something like :
var asset = dbContext.Set<Asset>()
.Include(x => x.Item)
.Include(x => x.Item.ItemDetailSubCategory)
.Include(x => x.AssetCurrentStatus)
.Include(x => x.AssetCurrentStatus.AssetCondition)
.Include(x => x.Currency)
.Include(x => x.AssetCurrentStatus.AssetAccessories)
if(x.AssetCurrentStatus.AssetLocation != null)
{
.Where(x => x.AssetCurrentStatus.Room.Floor.IsActive == true)
.Where(x => x.AssetCurrentStatus.Room.Floor.Building.IsActive == true)
.Where(x => x.AssetCurrentStatus.Room.IsActive == true)
}
else
{
.ToList()
}
is there any way to achieve this?
thanks in advance

Well, an if doesn't make sense because you want to apply that logic on every asset not only once. So you need to apply it to the query itself:
var asset = dbContext.Set<Asset>()
.Include(....)
.Where(x => x.AssetCurrentStatus.AssetLocation == null
|| (x.AssetCurrentStatus.Room.Floor.IsActive
&& x.AssetCurrentStatus.Room.Floor.Building.IsActive
&& x.AssetCurrentStatus.Room.IsActive))
.ToList();
Consecutive && are the same as consecutive Where.

You can try this
var asset = dbContext.Set<Asset>()
.Include(x => x.Item)
.Include(x => x.Item.ItemDetailSubCategory)
.Include(x => x.AssetCurrentStatus)
.Include(x => x.AssetCurrentStatus.AssetCondition)
.Include(x => x.Currency)
.Include(x => x.AssetCurrentStatus.AssetAccessories)
.Where(x => x.AssetCurrentStatus.AssetLocation != null ?
x.AssetCurrentStatus.Room.Floor.IsActive == true && x.AssetCurrentStatus.Room.Floor.Building.IsActive == true && x.AssetCurrentStatus.Room.IsActive == true :
true).ToList();

Related

Linq variable inside select

I have a following query
return _context.Table1
.Where(x => x.ContactId == contactKey.Id)
.Include(x => x.Table2)
.Include(x => x.Table3.Table4)
.Select(a =>
new MyReadModel
{
PriorityAssignment = true,
LastContactedDate = (a.Table3.Table4 != null && a.Table3.Table4.FirstOrDefault(h =>
h.Id == a.Table2.FkId
) != null ?
a.Table3.Table4.FirstOrDefault(h => && h.Id == a.Table2.FkId
).LastContactedDatetime : default
)
}
)
.ToListAsync();
What i wants is to simplify LastContactedDate assignment with in select. I think we can assign
a.Table3.Table4.FirstOrDefault(h =>
h.Id == a.Table2.FkId
)
to some variable but can't able to do it
can someone identify what is needed
With EF Core you don't have to check for null, LINQ Translator do not execute your code, but uses it for translation to the SQL. Also Includes is not needed if you do not retrieve whole objects.
return await _context.Table1
.Where(x => x.ContactId == contactKey.Id)
.Select(a => new MyReadModel
{
PriorityAssignment = true,
LastContactedDate = (DateTime?)a.Table3.Table4.Where(h => h.Id == a.Table2.FkId)
.OrderByDescending(h => LastContactedDatetime)
.Select(h => LastContactedDatetime)
.FirstOrDefault()
}).ToListAsync();
you can use it like this example
List<string> someList= new List<string>();
someList= someList.Select(x =>
{
var newVariable= "newVariable";
return newVariable;
}).ToList();
in your case
return _context.Table1
.Where(x => x.ContactId == contactKey.Id)
.Include(x => x.Table2)
.Include(x => x.Table3.Table4)
.Select(a => {
Table4 newVariable = null;
if(a.Table3.Table4 != null)
newVariable = a.Table3.Table4.FirstOrDefault(h => h.Id == a.Table2.FkId;
var result = new MyReadModel
{
PriorityAssignment = true,
LastContactedDate = (newVariable != null ? newVariable.LastContactedDatetime : default
)
};
}
) .ToListAsync();

Query with large WHERE clause causes timeout exception in EF6

clients = (IQueryable<client>)opts.ApplyTo(_dbContext.sp_client.FromSqlRaw(
SqlQuerys.GetVisibleClients(),
new NpgsqlParameter("providerId", providerId),
new NpgsqlParameter("userId", userId))
.Where(predicate)
.Include(q => q.NameDataQualityValue)
.Include(q => q.SsnDataQualityValue)
.Include(q => q.VeteranStatus)
.Include(q => q.Answers).ThenInclude(q => q.AnswerValue)
.Include(q => q.Answers).ThenInclude(q => q.Question)
.Include(q => q.HouseHoldsRelationship).AsQueryable());
}
List<client> visibleClientsList = client.ToList();
In client.ToList(), the code throws a timeout error - the issue in predicate it have the condition a switch statement
"gt" => predicate.And(q => q.Answers.Any(q =>
(_dbContext.da_answer.FromSqlRaw(
SqlQuerys.GetTopVisibleAnswers(),
new NpgsqlParameter("providerId", providerId),
new NpgsqlParameter("userId", userId),
new NpgsqlParameter("effectiveTimeSpan", dateEffective.Value)).Any(o => o.answer_id == q.answer_id) &&
q.Question.virt_field_name == answerCondition.virtualFieldName && q.val_date != null &&
q.val_date.Value.Date > dateValue.Date))),

EFCore Query and selection

Hey I am trying to query and find a object that looks something like this:
I have already result
I have id that is quiz id.
So i have both Ids.
var singlequiz = await _context.Quizzes
.Include(q => q.Questions)
.ThenInclude(question => question.Options)
.Include(qz => qz.Results)
.Where(b => b.Id == id)
.Select(c => c.Results.Select(z => z.Id == result.Id))
.FirstOrDefaultAsync();
What I am trying to do here is : find an object with id X, then that object with id X has a list of results, I want to get the list, BUT with only the one element that has id of result.Id.
What am i doing wrong?
EDIT:
Used this ATM
var singlequiz = await _context.Quizzes
.Include(x => x.Questions)
.ThenInclude(x => x.Options)
.Include(x => x.Results)
.FirstOrDefaultAsync(x => x.Id == id);
var singleQuizElement = singlequiz.Results.Where(x => x.Id == result.Id).ToList();
singlequiz.Results = singleQuizElement;
Try this :
var singlequiz = await _context.Quizzes
.Include(x => x.Questions)
.ThenInclude(x => x.Options)
.Include(x => x.Results)
.FirstOrDefaultAsync(x=> x.Id == id && x.Results.Any(y => y.Id == result.Id));

Linq query fine tuning

Query logic is Grouping the items by Id and Ordering it by Id. Then inside grouped items Ordering by Item1 then by Item2.
Linq query below,
var group1Items = MyList.GroupBy(g => g.Id)
.Where(w => w.Any(a => a.Code = 1)
.Select(s => new
{ key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
}
)
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items).ToList();
var group2Items = MyList.GroupBy(g => g.Id)
.Where(w => w.Any(a => a.Code = 2)
.Select(s => new
{ key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
}
)
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items).ToList();
MyList.Clear();
MyList.InsertRange(Mylist.Count, group1Items);
MyList.InsertRange(Mylist.Count, group2Items);
In the above two queries, only difference is Where condition. Is it possible to rewrite into single query?
Single query:
var groupItems = MyList.GroupBy(g => g.Id)
.Where(w => w.Any(a => a.Code == 1 || a.Code == 2)
.Select(s => new
{ key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
}
)
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items).ToList();
If Code 1 must come before Code 2:
var groupItems = MyList.GroupBy(g => g.Id)
.Where(w => w.Any(a => a.Code == 1)
.Select(s => new
{ key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
}
)
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items)
.Union(MyList.GroupBy(g => g.Id)
.Where(w => w.Any(a => a.Code == 2)
.Select(s => new
{ key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
}
)
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items)).ToList();
If you only want to avoid code duplication it may be easiest to capture a variable holding the code by which to filter.
int code = 0; // initialize with any value
var groupItems = MyList.GroupBy(g => g.Id)
.Where(w => w.Any(a => a.Code == code)
.Select(s => new
{
key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
})
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items); // No ToList() here!
MyList.Clear();
code = 1;
MyList.InsertRange(Mylist.Count, groupItems.ToList());
code = 2;
MyList.InsertRange(Mylist.Count, groupItems.ToList());
Removed where clause in the LINQ expression and implemented at InsertRange() method. This avoids redundant queries
var groupItems = MyList
.GroupBy(g => g.Id)
.Select(s => new
{ key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
}
)
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items).ToList();
MyList.Clear();
MyList.InsertRange(Mylist.Count, groupItems.Where(w => w.Code == 1));
MyList.InsertRange(Mylist.Count, groupItems.Where(w => w.Code == 2));

Get one child element per group

I am getting, with EF6, one advert by position as follows:
var adverts = context.Adverts
.Include(x => x.Files)
.Where(x => x.Position <= 32)
.OrderBy(x => Guid.NewGuid())
.GroupBy(x => x.Position)
.ToDictionary(x => x.Key, x => x.First());
I get one advert per group and each advert has one file.
But what I really want is a file for each advert so I tried:
var adverts = context.Adverts
.Include(x => x.Files)
.Where(x => x.Position <= 32)
.OrderBy(x => Guid.NewGuid())
.GroupBy(x => x.Position)
.ToDictionary(x => x.Key, x => x.First().Files);
In this case the value of the dictionary is empty.
Any idea how to solve this?

Categories

Resources