How to specify index in Entity Framework 5.0 - c#

I have a select statement where it returns thousands of records. i want to use Index hints with the query. How do i do this using Entity Framework
var actCosts = db.ActCosts.Where(t => t.ScenarioID == scenarioID).ToList();
like this
select * from ActCost WITH(INDEX(IX_ActCost_ScenarioID)) where ScenarioID = 797

There is no way of adding query hints to the current version of Entity Framework; however, they are considering implementing it in a future release.
See the proposal at https://entityframework.codeplex.com/workitem/261 as well as some possible work-arounds.

Related

Entity Framework equivalent of SQL relative update

If I want to increase the value in a table column with SQL I can do it as follows:
UPDATE mytable m SET m.mycolumn = m.mycolumn + 1;
This is great because it doesn't rely on being executed in any order and uses an absolute minimum of locking.
How can this be done using C# and Entity Framework, with the same (or as close as possible) minimal overhead?
In short, you can't. You can execute a sql statement through the ado.net properties available on the DbContext.Database. You could also created a stored procedure if this is a specific action that occurs where the stored proc does this. That is the closest you will get to this.
This answer assumes you already know how to retrieve all the records, iterate over them to change the value of the property, and then persist the changes using SaveChanges on the DbContext and that this is not what you are looking for as it generates 1 update statement per record.
As already said, it's not possible in Pure EF.
As always you're free to create your pure SQL statements and run them through your context.
The closest thing to your question is to use Entity Framework Extensions. The have an UpdateFromQuery method: https://entityframework-extensions.net/update-from-query
This would look like this:
context.mytable.UpdateFromQuery(x => new mytable() {mycolumn = x.mycolumn + 1});
You can use EF Core extension linq2db.EntityFrameworkCore (disclaimer: I'm one of the creators)
context.mytable
.Set(x => x.mycolumn, x => x.mycolumn + 1)
.Update();
Library has it's own LINQ Translator which eliminates a lot of EF Core limitations.
dbContext.Entity.ForEach(x -> x.property = value);
or
dbContext.Entity.Select(x -> {x.property =100; return c;}).ToList();
See Using LINQ to Update A Property in a List of Entities

Include() vs Select() performance

I have a parent entity with a navigation property to a child entity. The parent entity may not be removed as long as there are associated records in the child entity. The child entity can contain hundreds of thousands of records.
I'm wondering what will be the most efficient to do in Entity Framework to do this:
var parentRecord = _context.Where(x => x.Id == request.Id)
.Include(x => x.ChildTable)
.FirstOrDefault();
// check if parentRecord exists
if (parentRecord.ChildTable.Any()) {
// cannot remove
}
or
var parentRecord = _context.Where(x => x.Id == request.Id)
.Select(x => new {
ParentRecord = x,
HasChildRecords = x.ChildTable.Any()
})
.FirstOrDefault();
// check if parentRecord exists
if (parentRecord.HasChildRecords) {
// cannot remove
}
The first query may include thousands of records while the second query will not, however, the second one is more complex.
Which is the best way to do this?
I would say it depens. It depends on which DBMS you're using. it depends on how good the optimizer works etc.
So one single statement with a JOIN could be far faster than a lot of SELECT statements.
In general I would say when you need the rows from your Child table use .Include(). Otherwise don't include them.
Or in simple words, just read the data you need.
The answer depends on your database design. Which columns are indexed? How much data is in table?
Include() offloads work to your C# layer, but means a more simple query. It's probably the better choice here but you should consider extracting the SQL that is generated by entity framework and running each through an optimisation check.
You can output the sql generated by entity framework to your visual studio console as note here.
This example might create a better sql query that suites your needs.

Bulk deleting rows with RemoveRange()

I am trying to delete multiple rows from a table.
In regular SQL Server, this would be simple as this:
DELETE FROM Table
WHERE
Table.Column = 'SomeRandomValue'
AND Table.Column2 = 'AnotherRandomValue'
In Entity Framework 6, they have introduced RemoveRange() method.
However, when I use it, rather than deleting rows using the where clauses that I provided, Entity Framework queries the database to get all rows that match the where clauses and delete them one by one using their primary keys.
Is this the current limitation of EntityFramework?
Or am I using RemoveRange() wrong?
Following is how I am using RemoveRange():
db.Tables.RemoveRange(
db.Tables
.Where(_ => _.Column == 'SomeRandomValue'
&& _.Column2 == 'AnotherRandomValue')
);
I think we reached here a limitation of EF.
Sometimes you just have to use ExecuteSqlCommand to stay performant.
What you are looking for is a Batch Delete Library which deletes multiple records in a database from a LINQ Query without loading entities.
Multiple libraries supporting this feature exist.
You can find the list here: Entity Framework Batch Delete Library
Disclaimer: I'm the owner of the project Entity Framework Plus
// using Z.EntityFramework.Plus; // Don't forget to include this.
// DELETE directly in SQL (without loading entities)
db.Tables.Where(_ => _.Column == 'SomeRandomValue'
&& _.Column2 == 'AnotherRandomValue')
.Delete();
// DELETE using a BatchSize
db.Tables.Where(_ => _.Column == 'SomeRandomValue'
&& _.Column2 == 'AnotherRandomValue')
.Delete(x => x.BatchSize = 1000);
Wiki: EF+ Batch Delete
It's a bit broken, try
db.Tables.RemoveRange(
db.Tables
.Where(_ => _.Column == 'SomeRandomValue'
&& _.Column2 == 'AnotherRandomeValue').AsEnumerable().ToList()
);
db.SaveChanges();
var db1 = db.Tables
.Where(_ => _.Column == 'SomeRandomValue'
&& _.Column2 == 'AnotherRandomeValue').AsEnumerable().ToList();
db.Tables.RemoveRange(db1);
db.SaveChanges();
Use an Variable to Store Removable list and pass it to RemoveRange().
I Usually do like this, and That's Work.
Hope This also work in your case.
Step back and think. Do you really want to download the records from the database in order to delete them? Just because you can doesn't make it a good idea.
Perhaps you could consider deleting the items from the database with a stored procedure? EF also allows to do that...
I'm dealing with this myself, and agree with Adi - just use sql.
I'm cleaning up old rows in a log table, and EF RemoveRange took 3 minutes to do the same thing this did in 3 seconds:
DELETE FROM LogEntries WHERE DATEDIFF(day, GETDATE(), Date) < -6
Date is the name of the column containing the date. To make it correct, use a parameter, of course, like this:
context.Database.ExecuteSqlCommand
("DELETE FROM LogEntries WHERE DATEDIFF(day, GETDATE(), Date) < #DaysOld", new System.Data.SqlClient.SqlParameter(
"DaysOld", - Settings.DaysToKeepDBLogEntries));
Note that there are a lot of rows involved in my case. When I started the project and didn't have a lot of data, RemoveRange worked fine.
I have met this problem as well, this is my workaround with a library called entityframework.extended by LoreSoft (which you can get it from nuget package manager):
1.You first query them your list.
2.Then use .Delete(), which is a function from .extended library.
var removeList = db.table.Where(_ => _.Column == 'SomeRandomValue'&& _.Column2 == 'AnotherRandomValue')
removeList .Delete();
Note: According to Entity Framework EF extended, as of the time writing, this entityframework.extended is deprecated. Therefore one might need to consider entityframework plus library. While i have not tested on the plus extension, but i can confirmed working it works using .extended library.

Entity Framework 5 upgrade from 4

I'm having an issue with the Where clause in a search, in my original version EF4 I could add a Where clause with 2 parameters, the where clause (string predicate) and a ObjectParameter list such as
var query = context.entities.Where(WhereClause.ToString(), Params.ToArray());
since my upgrade to EF5 I don't seem to have that option am I missing something?
This was originally used to build dynamic where clause such as "it.entity_id = #entity_id" then holding the variable value in the ObjectParameter.
I'm hoping I don't have to rewrite all the searches that have been built out this way, so any assistance would be greatly appreciated.
Cheers
In order to use ESQL with DbContext, you will have to "drop down" to ObjectContext.
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
var query = objectContext.CreateQuery<MyEntity>(
WhereClause.ToString(),
Params.ToArray());

Entity Framework - How many trips to the database on DeleteObject

Is this entity framework call actually making two trips to the database?
var result = from p in entities.people where p.id == 6 select p;
entities.DeleteObject(result);
It strikes me that maybe DeleteObject would force the first trip to get results and THEN, having the object to work with, would execute the delete function.
If that is the case, how do I avoid the second trip? How does one do a remove-by-query in entity framework with a single database trip?
Thanks!
EDIT
My original example was misleading, because it was a query by primary key. I guess the real question is whether there is a way to have a single-trip function that can delete items from an IQueryable. For example:
var result = from p in entities.people where p.cityid == 6 select p;
foreach (var r in result)
{
entities.DeleteObject(r);
}
(Notice that the query is of a foreign key, so there may be multiple results).
You can do it like this:
entities.ExecuteStoreCommand("DELETE FROM people WHERE people.cityid={0}", 6);
this is one trip to the database for sure, and effective as it can be.
EDIT:
Also, take a look here, they suggest the same solution. And to answer the question, this is the only way to delete entities, not referenced by primary key, from a database using entity framework, without fetching these entities (and without writing some helper extension methods like suggested in this answer).
Direct delete:
var people = new people() { id = 6 };
entities.people.Attach(people);
entities.people.Remove(people);
entities.SaveChanges();
If you want to see it for yourself, fire up a profiler.
EDIT:
This will allow you to use Linq but it won't be one trip.
var peopleToDelete = entities.people.Where(p => p.id == 6);
foreach (var people in peopleToDelete )
entities.people.DeleteObject(people );
entities.SaveChanges();
There's no easy way to do that out of the box in EF, a big annoyance indeed (as long as one does not want to resort to using direct SQL, which personally I don't). One of the other posters links to an answer that in turn links to this article, which describes a way to make your own function for this, using ToTraceString.

Categories