Update statement with Entity Framework - entity-framework

Simple question, is it possible to achieve this query this with Entity Framework when updating one entity?
update test set value = value + 1 where id = 10

Use the Batch Update feature of the Entity Framework Extended Library, like this:
dbContext.Tests.Update(t => t.Id == 10, t => new Test() { Value = t.Value + 1 });

Not really under this form no.
You will have to select all entities that match your criteria, foreach over them and update them.
If you are looking for something that will do it right in the DB because your set could be huge, you will have to use SQL directly. (I don't remember if EF has a way to execute UPDATE queries directly the way Linq To SQL does).

It should be, it will just be a little bit more constrained generally.
var myEntity = context.First(item => item.id == 10);
myEntity.value += 1;
context.SaveChanges();
Should produce similar SQL, you can watch the profiler to see what SQL is actually being generated, but it should be very similar to your statement.

Related

Automapper projectTo generated SQL has no where clause

Using Entity Framework Core I'm trying to map an entity containing a child collection.
Without projectTo the generated SQL includes a where clause and only fetches the entities that belong in the child collection. When I add a projectTo, the result is correct but looking at the SQL I see no where clause. It appears to load all the entities of the child type and then do a where in memory.
I've tried all sorts of mappings on the collection but nothing seems to change this behavior.
Is there a way to improve this query?
The code in question is:
var parent = _context
.Parents
.Where(a => a.FamilyId == familyId && a.Id == id)
.Include(r => r.Children)
//.ProjectTo<ParentDetailViewModel>()
.AsNoTracking() // In case projection contains sub entities
.SingleOrDefault();
Without the project to I see the following SQL in the profiler
exec sp_executesql N'SELECT [r].[Id], [r].[FieldOne], [r].[Cid], [r].[FieldTwo], [r].[ParentId]
FROM [Child] AS [r]
WHERE EXISTS (
SELECT TOP(2) 1
FROM [Parent] AS [a]
WHERE (([a].[FamilyId] = #__familyId_0) AND ([a].[Id] = #__id_1)) AND ([r].[ParentId] = [a].[Id]))
ORDER BY [r].[ParentId]',N'#__familyId_0 int,#__id_1 int',#__familyId_0=1,#__id_1=1
With project I see this. No where clause included.
SELECT [r].[ParentId], [r].[Id]
FROM [Child] AS [r]
As a general rule of thumb, I put the ProjectTo as the last thing before your query materialization. Put ProjectTo after AsNoTracking - HOWEVER, the AsNoTracking is pointless. With ProjectTo, you're skipping entities entirely, going straight from SQL to DTO, no entities involved at all.
Also, the Include is pointless. With ProjectTo/Select, EF knows exactly what entities it needs to join, because they're in the Select projection!
Apparently caused by an Entity Framework Core bug. Fixed in 1.1.0 preview

EF Core Group On Nav Properties

Quick question regarding this issue.
I have an error unable to get the data from database,
Is there something issue with EF Core or my linq query?
var query = _postRepository.Table
.Where(x => x.Approval == true)
.Include(p => p.Industry)
.GroupBy(grp => new { grp.Industry.Id, grp.Industry.Name })
.Select(s => new JobPostStatistics
{
IndustryId = s.Key.Id,
IndustryName = s.Key.Name,
TotalJobPost = s.Count()
});
return query.Take(6).ToList();
InvalidOperationException: Sequence contains more than one element
Seems in EF RC1 GroupBy cause error, here is reported bug:
GroupBy query cause error Sequence contains more than one element
EF Core 2.1 will not only work, but it will also be capable of translating GroupBy to SQL GROUP BY. The expected release date is Q4 2017. Previous versions also support GroupBy but execute it on the client side, which can be a huge problem if you're using it to retrieve aggregates, like SUM, from the database. Imagine retrieving 2 million rows from the server to calculate the sum on the client side, instead of getting it directly from the database server.
In the meantime, you can always write your own SQL query and map it to an entity or anonymous type, using DbSet.FromSql, i.e. invoking FromSql as a member of an entity collection of your context.
Here you have enabled eager loading by using include keyword. You try with disable lazy loading
Server-side GroupBy-support of EF Core has been postponed to after the release: https://github.com/aspnet/EntityFramework/issues/2341
When you log the queries EF creates you can see that it does not create GROUP BY in the SQL.
Here somebody else posted the same error with another GroupBy query.
https://github.com/aspnet/EntityFramework/issues/4775
I had another error with GroupBy and Include(). As EF does not support GroupBy in the SQL and the grouping is done on the client side, I split my query into a server side part and a client side part. The first part queries from the database with the Include() into an anonymous type. Then I do the grouping on the client side.
var event2Country = DbContext.Event2Countries
.Include(j => j.Location)
.Select(j => new { j.Location.Id, j.Location.Name })
.AsNoTracking();
viewModel.MostUsedCountries = event2Country
.GroupBy(j => new { j.Id, j.Name })
.OrderByDescending(j => j.Count())
.ThenBy(j => j.Key.Id)
.Select(j => new SimpleListCountViewModel()
{
Id = j.Key.Id,
Name = j.Key.Name,
Count = j.Count()
})
.Take(15)
.ToList();
Currently you cannot use GroupBy in EF Core if you have a lot of data. A workaround would be to use FromSql. See issue 4959 on Github.

E-SQL in Entity Framework DbContext

I'm using EF 5.0 Code First API, and I need to add the ability for building dynamic OrderBy expressions (the UI has a filter panel where users can choose multiple oredering criteria (e. g. select top 20 Customers, order by LastName ASC, then by Birst Date DESC).
ObjectContext API exposes OrderBy("it.PropertyName") method which looks great, despite it's missing compile time verification. However, I can't find any analogues in the DbContext API.
Googling the problem I found such advice:
((IObjectContextAdapter)myContextInstance).ObjectContext.CreateQuery<MyEntity>("<ESQL Query>")
However, I would not like to give up LINQ query at all.
Are there any ways to have something like this (mix ESQL and LINQ, as it could be by using ObjectContext):
var customers = myDbContext.Customers.OrderBy("it.LastName desc").Where(c => c.Age < 18)
Something like this? I'm not sure about mixing ESQL and LINQ, but your last query can be done entirely from LINQ.
var customers = myDbContext.Customers.OrderByDescending(a => a.LastName).ThenBy(c => c.BirthDate).Where(b => b.Age < 18);

Entity Framework 4.1 query takes too long (5 seconds) to complete

I have DbContext (called "MyContext") with about 100 DbSets within it.
Among the domain classes, I have a Document class with 10 direct subclasses (like PurchaseOrder, RequestForQuotation etc).
The heirarchy is mapped with a TPT strategy.
That is, in my database, there is a Document table, with other tables like PurchaseOrder, RequestForQuotation for the subclasses.
When I do a query like:
Document document = myContext.Documents.First();
the query took 5 seconds, no matter whether it's the first time I run it or subsequently.
A query like:
Document document = myContext.Documents.Where(o => o.ID == 2);
also took as long.
Is this an issue with EF4.1 (if so, will EF4.2 help) or is this an issue with the query codes?
Did you try using SQL Profile to see what is actually sent to the DB? It could be that you have too many joins on your Document that are not set to lazy load, and so the query has to do all the joins in one go, bringing back too many columns. Try to send a simple query with just one return column.
As you can read here, there are some performance issues regarding TPT in EF.
The EF Team annouced several fixes in the June 2011 CTP, including TPT queries optimization, but they are not included in EF 4.2, as you can read in the comments to this answer.
In the worst case, these fixes will only be released with .NET 4.5. I'm hoping it will be sooner...
I'm not certain that the DbSet exposed by code-first actually using ObjectQuery but you can try to invoke the .ToTraceString() method on them to see what SQL is generated, like so:
var query = myContext.Documents.Where(o => o.ID == 2);
Debug.WriteLine(query.ToTraceString());
Once you get the SQL you can determine whether it's the query or EF which is causing the delay. Depending on the complexity of your base class the query might include a lot of additional columns, which could be avoided using projection. With using projections, you can perform a query like this:
var query = from d in myContext.Documents
where d.ID == 2
select new
{
o.Id
};
This should basically perform a SELECT ID FROM Documents WHERE ID = 2 query and you can measure how long this takes to gain further information. Of course the projected query might not fit your needs but it might get you on the right track. If this still takes up to 5 seconds you should look into performance problems with the database itself rather than EF.
Update
Apparently with code-first you can use .ToString() instead of .ToTraceString(), thanks Slauma for noticing.
I've just had a 5 sec delay in ExecuteFunction, on a stored procedure that runs instantaneously when called from SQL Management Studio. I fixed it by re-writing the procedure.
It appears that EF (and SSRS BTW) tries to do something like a "prepare" on the stored proc and for some (usually complex) procs that can take a very long time.
A quick and dirty solution is to duplicate and then replace your SP parameters with internal variables:
create proc ListOrders(#CountryID int = 3, #MaxOrderCount int = 20)
as
declare #CountryID1 int, #MaxOrderCount1 int
set #CountryID1 = #CountryID
set #MaxOrderCount1 = #MaxOrderCount
select top (#MaxOrderCount1) *
from Orders
where CountryID = #CountryID1

How do you deal with Linq to NHibernate's Fetch exception when selecting aggregates?

I'm using LINQ to NHibernate's IQueryable implementation on a asp.net mvc Grid (telerik specifically), where I know I'll need to fetch something eagerly for this particular grid.
So I have query that looks something like this:
var query = from s in repository.Query<MyClass>()
orderby s.Property.Name, s.Name
select s;
query = query.Fetch(x => x.Property);
Now, if I execute query.ToList(), everything is fine, and I can verify that it works in an integration test.
It's awesome.
However, if I execute query.Count() or something else that aggregates the query, I get an exception:
Query specified join fetching, but the
owner of the fetched association was
not present in the select list
[FromElement{explicit,not a collection
join,fetch join,fetch non-lazy
properties,classAlias=0,role=,tableName=[Property],tableAlias=property1,origin=MyClass
myclass0_,colums={myclass0_.PropertyGuid
,className=Property}}]
[.Count(.Fetch(.ThenBy(.OrderBy(NHibernate.Linq.NhQueryable`1[MyClass],
Quote((s, ) => (s.Property.Name)), ),
Quote((s, ) => (s.Name)), ), Quote((x,
) => (x.Property)), ), )]
I know that it's trying to tell me that I can't eagerly fetch Property because MyClass isn't in the select, but the problem is that Count() is actually being called via the Grid, and handled externally from my code.
All I'm supposed to need to do is give the grid an IQueryable and it should be able to handle paging, sorting, etc. by itself.
Has anyone else had to get around this issue with NHibernate Fetching and how did you resolve it?
var query = from s in repository.Query<MyClass>()
orderby s.Property.Name, s.Name
select s;
query = query.Fetch(x => x.Property).ToList();
and after you can go and do
query.Count()
and it should be in working order.
As to why is that i suspect that is something to do
AsEnumerable()
or
AsQueryable()
but not sure why is this
i had similar problem and this solved it...