Using FirstOrDefault() in query - entity-framework

Is there a way to use FirstOrDefault() inside a complex query but not throw an exception if it returns null value?
My query:
contex.Table1.Where(t => t.Property == "Value").FirstOrDefault()
.Object.Table2.Where(t => t.Property2 == "Value2").FirstOrDefault();
If the query on the first table (Table1) doesn't return an object the code throws an exception. Is there a way to make it return just null?

Try a SelectMany on Table2, without the intermediate FirstOrDefault():
context.Table1.Where(t1 => t1.Property1 == "Value1")
.SelectMany(t1 => t1.Table2.Where(t2 => t2.Property2 == "Value2"))
.FirstOrDefault();
Also, you might want to use SQL Profiler to check the SQL that is being sent by EF. I believe the query as constructed in your question will result in two queries being sent to the database; one for each FirstOrDefault().

You could build your own helper function, that takes IEnumerable
public static TSource CustomFirstOrDefault<TSource>(this IEnumerable<TSource> source)
{
return source.FirstOrDefault() ?? new List<TSource>();
}
This would effectively return an empty list, which, when called upon, providing your code in your Object property can handle nulls, won't bomb out, cause you'll just be returning a 0 item collection, instead of a null.

Only the first query with Where is a database query. As soon as you apply a "greedy" operator like FirstOrDefault the query gets executed. The second query is performed in memory. If Object.Table2 is a collection (which it apparently is) and you don't have lazy loading enabled your code will crash because the collection is null. If you have lazy loading enabled a second query is silently executed to load the collection - the complete collection and the filter is executed in memory.
You query should instead look like #adrift's code which would really be only one database query.

Related

Does Npgsql support projection queries?

If I do this...
Context.Orders.Select(o => o.User.UserId);
... I get an exception because User is null. I can use Include instead,
Context.Orders.Include(o => o.User).Select(o => o.User.UserId);
... but shouldn't User be loaded automatically?
EDIT:
The first snippet of code doesn't work when the Select is applied to the result of a function. Which type should the function return in order to tack the Select onto the database query?
I've tried IEnumerable<Order> and IQueryable<Order>.

Filtering related entities in entity framework 6

I want to fetch the candidate and the work exp where it is not deleted. I am using repository pattern in my c# app mvc.
Kind of having trouble filtering the record and its related child entities
I have list of candidates which have collection of workexp kind of throws error saying cannot build expression from the body.
I tried putting out anonymous object but error still persist, but if I use a VM or DTO for returning the data the query works.
It's like EF doesn't like newing up of the existing entity within its current context.
var candidate = dbcontext.candidate
.where(c=>c.candiate.ID == id).include(c=>c.WorkExperience)
.select(e=>new candidate
{
WorkExperience = e.WorkExperience.where(k=>k.isdeleted==false).tolist()
});
Is there any workaround for this?
You cannot call ToList in the expression that is traslated to SQL. Alternatively, you can start you query from selecting from WorkExperience table. I'm not aware of the structure of your database, but something like this might work:
var candidate = dbcontext.WorkExperience
.Include(exp => exp.Candidate)
.Where(exp => exp.isdeleted == false && exp.Candidate.ID == id)
.GroupBy(exp => exp.Candidate)
.ToArray() //query actually gets executed and return grouped data from the DB
.Select(groped => new {
Candidate = grouped.Key,
Experience = grouped.ToArray()
});
var candidate =
from(dbcontext.candidate.Include(c=>c.WorkExperience)
where(c=>c.candiate.ID == id)
select c).ToList().Select(cand => new candidate{WorkExperience = cand.WorkExperience.where(k=>k.isdeleted==false).tolist()});

JPQL Aggregation return

Lets say I have the following JPQL query
SELECT e.column1, e.column2, SUM(e.column3), SUM(e.column4) FROM Entity e GROUP BY e.column1, e.column2
Obviously I wont be returning an Entity object but something a bit more complex. How do I return this in the method?
public List<???> query1() {
Query q = entityManager.createQuery("...");
List<Something???> list = q.getResultList();
return list;
}
Such a query returns a List<Object[]>, where each element is thus an array of Objects. The first element of the array will have the type of Entity.column1, the second one will have the type of Entity.column2, and the last 2 ones will be (with Hibernate at least) of type Long (check with EclipseLink).
It's up to you to transform the List<Object[]> in a List<Foo>, by simply looping over the list of objects and transforming each one into a Foo. You may also use the constructor notation directly in the query (provided Foo has such a constructor), but I personally dislike it, because it isn't refactorable:
select new com.baz.bar.Foo(e.column1, e.column2, SUM(e.column3), SUM(e.column4)) from ...

Entity Framework DeleteObject query a lot of items

I have a problem trying to delete an object with Entity Framework, I previously query the context to get a list of objects I need to delete, then one by one I call deleteobject
IQueryable result = context.CustomObjects.Where(t=>t.Property = something)
foreach (CustomObject customObj in result)
{
context.DeleteObject(customObj);
}
When I call DeleteObject EF executes a weird query, something like that:
exec sp_executesql N'SELECT
[Extent1].[Value1] AS [Value1],
[Extent1].[Value2] AS [Value2],
[Extent1].[Value3] AS [Value3],
FROM [CustomObject] AS [Extent1]
WHERE [Extent1].[ID] = #EntityKeyValue1',N'#EntityKeyValue1 int',#EntityKeyValue1=59
This query seems to search all the object with ID = something, but ID it is just part of the entity key that is indeed composed by 3 fields, so it attaches like n thousands items and make the process very slow, that is a behavior I can't understand, I always deleted object in this way and I have never had such a problem
can someone have an idea?
Thanks
You could be fetching mutiple objects as defined by your where query. Also for each object you fetch, you will be fetching all fields on the object CustomObject.
The query thats being executed is a select query so this confirms the above behaviour.
If you want better performance then I recommend that you do something like this:
var entityToDelete = new SomeEntity();
SomeEntity.PK = 12;
var context = new YourContextntities();
context.YourEntitites.Attach(entityToDelete);
context.YourEntitites.Remove(entityToDelete);
context.SaveChanges();

EF Where(x => x.ColumnVal == 1) vs FirstOrDefault(x => x.Column == 1)

I had a LINQ query that loads a hierarchy of objects like the following.
Query #1
var result = db.Orders
.Include("Customer")
// many other .Include() here
.FirstOrDefault(x => x.Customer.CustomerId == 1 &&
x.OrderId == orderId);
I was having MAJOR performance problem with it.
The CPU usage was near 100% and memory usage was very high.
And I tweaked it to the following and the performance problem was fixed.
Query #2
var result = db.Orders
.Include("Customer")
// many other .Include() here
.Where(x => x.Customer.CustomerId == 1 &&
x.OrderId == orderId)
.FirstOrDefault();
I just want to confirm my suspicion.
Query #1 is probably looping through all my records in memory looking for a matching record
vs
Query #2 filters the records on the Database and then getting the first record only.
Is that why the Query #1 has performance problems?
Just to be safe, do I need to use the .Select(x => x) before the .FirstOrDefault()?
Query #3
var result = db.Orders
.Include("Customer")
// many other .Include() here
.Where(x => x.Customer.CustomerId == 1 &&
x.OrderId == orderId)
.Select(x => x)
.FirstOrDefault();
No, they both should result in a same SQL query when being executed. You can prove it by looking into SQL Profiler and see what is the exact SQL being submitted from EF in both cases. Your performance optimization should have been caused by some other factors. Here is why:
Include method returns an ObjectQuery<T>:
public class ObjectQuery<T> : ObjectQuery, IOrderedQueryable<T>,
IQueryable<T>, IEnumerable<T>,
IOrderedQueryable, IQueryable,
IEnumerable, IListSource
Which means its FirstOrDefault method comes with 2 overloads:
// Defined by Enumerable:
FirstOrDefault(Func<T, Boolean>)
// Defined by Queryable:
FirstOrDefault(Expression<Func<T, Boolean>>)
When you code .FirstOrDefault(x => x.Customer.CustomerId == 1 compiler will go into a process called Overload Resolution to infer the type of the lambda expression x => x.Customer.CustomerId == 1 since it is convertible to the type of both overload's parameter types.
Compiler will use an algorithm (that I am still trying to find in C# Language Specification!), figure out that converting the lambda to the Expression<Func<T, Boolean> is a better conversion than to Func<T, Boolean> so pick the IQueryable overload.
Therefore, you'll see the predicate in the generated SQL when observing it in the SQL Profiler.
I found the culprit. It's the SQL query generated by Entity Framework.
I have a complicated Schema with a lot of many-to-many relationships.
Entity Framework was generating a 32,000 line long SQL string :'(
Now, I am changing my code to load the hierarchy manually for some part.
Please let me know if anyone knows some good articles to read about Eager Loading and Many-to-Many relationships.
I think best would be to use ...Where(condition).Take(1).FirstOrDefault() because Take(1) can be easily translated to SQL as a TOP clause. Anybody with me?