Remove a record in entity framework - c#

I'm working with entity framework for sometimes now and one thing that really irritates me is the fact that to delete an item we have to find the object and then remove it. so if we have the PK of the record we have to get the object and then remove the object.
ex:
Category category = db.Categories.Find(categoryId);
db.Categories.Remove(category);
db.SaveChages();
In this method we are hitting database twice..!!!
is there a way to remove the record with just hitting the database once?
For those none-believers this is the glimpse out come: :)

// no trip to database
var rec = db.TableName.Local.SingleOrDefault(r => r.Id == primaryKey);
if (rec == null) throw NotFoundOrWhateverException();
// still no trip to database, if I remember right
db.TableName.Remove(rec);
// trip to database
db.SaveChanges();

IF you don't want to get the complete object you can try this way using the primary key property of it:
Category category = new Category () { Id = categoryId } ;
db.Categories.Attach(category);
db.DeleteObject(category);
db.Savechanges();
If you are using EF 5 then you can use EntityFramework.Extended Library using NUGETand can do like this:
db.Categories.Delete(c => c.Id == categoryId);

[Answer turned out to be incorrect. Removed content to keep from confusing others. Kept the post for comment thread.]

Related

EF Core dirty check before save entity

If I want to update a Book entity in DB with EF core code like this
using (var db = new MyContextDB())
{
var bookEntity = db.Books.SingleOrDefault(b => b.Id == 123);
if (result != null)
{
bookEntity.Title = "Get rich in 10 days for dummies";
db.SaveChanges();
}
}
My question is, if the bookEntity's title is "Get rich in 10 days for dummies" before update. Will EF core skip the update or it will issue update regardless?
Thanks.
My question is, if the bookEntity's title is "Get rich in 10 days for
dummies" before update. Will EF core skip the update or it will issue
update regardless?
No, it will not.
EF issues SQL command for an entity based on its state. For an entity with Unchanged state EF doesn't issues any SQL command.
When you fetched the bookEntity from database EF started tracking it with Unchanged state, and it knows what are the values in database for each property of this entity. If you modify any property, EF will mark the entity as Modified, and issue an update command on next SaveChanges() call. But if you set the already existing value to a property, you really didn't modify the entity. Therefore, the entity state remains Unchanged and EF will not issue any update for that.
You can check the entity state with following code -
using (var db = new MyContextDB())
{
var bookEntity = db.Books.SingleOrDefault(b => b.Id == 123);
if (result != null)
{
var stateBefore = dbCtx.Entry(bookEntity).State; // state is "Unchanged"
bookEntity.Title = "Get rich in 10 days for dummies";
var stateAfter = dbCtx.Entry(bookEntity).State; // state is sill "Unchanged"
db.SaveChanges();
}
}
EF core will skip the update. If you want to save changes you can use this syntax for example:
using (var db = new MyContextDB())
{
var bookEntity = db.Books.SingleOrDefault(b => b.Id == 123);
if (bookEntity != null)
{
bookEntity.Title = "Get rich in 10 days for dummies";
db.Entry(bookEntity).Property(i=> i.Title).IsModified = true;
db.SaveChanges();
}
}
if the bookEntity's title is "Get rich in 10 days for dummies" before update. Will EF core skip the update or it will issue update regardless?
No, Entity Framework uses an ChangeTracker internaly.
So if you assign the exact same value to the entity again, it will not issue an update query for this property.
To override this behaviour, you need to explict set it, as Sergey already answered.
db.Entry(bookEntity).Property(i=> i.Title).IsModified = true;

How to select specific fields to update in EF

I want to get all records from a database with #where, then update them. To do this, I have created a query like this:
public async Task MarkAllAsActive()
{
var currentUserId = _userManager.GetCurrentUserId();
await _workOrders.Where(row => row.Status == WorkOrderStatus.Draft).ForEachAsync(row =>
{
row.Status = WorkOrderStatus.Active;
_uow.MarkAsChanged(row, currentUserId);
});
}
But this query selects all fields from the database which isn't good. To solve this I try to select just specific fields like ID, Status:
public async Task MarkAllAsActive()
{
var currentUserId = _userManager.GetCurrentUserId();
await _workOrders.Select(row=>new WorkOrder { Id=row.Id,Status=row.Status}).Where(row => row.Status == WorkOrderStatus.Draft).ForEachAsync(row =>
{
row.Status = WorkOrderStatus.Active;
_uow.MarkAsChanged(row, currentUserId);
});
}
But it return this error:
The entity or complex type 'DataLayer.Context.WorkOrder' cannot be constructed in a LINQ to Entities query.
I've seen a similar post and the same error, but my problem is different because I want to update.
How can I do this?
Sadly you have to fetch the entire entity.
In order to update an entity with EF, the class type edited has to be a DbContext mapped entity .
If you want to Update without fetching Entities to the server , and without writing any SQL you can use Entity Framework Extended Library .
See the update section on the site.
Fetching entity within same entity will not work in your case, as you are getting only selected columns. e.g. You are fetching WorkOrder entity in WorkOrder again.
I would suggest you to use DTO to load selected columns only. It should work. But at the time of update you will have to copy same to db object.

Entity framework select an existing item and only pull back one of its fields to update

I'm trying to do something that should be "simple", I want to pull out a piece of data from my database but I only want to pull out the description (the database table for this item has first name, last name, address etc etc).
So when I call my database call I want to just grab the description and then update it, I don't want to grab anything else as this will cost network power and may cause lag if uses multiple times in a few seconds.
Here is my code that i'm trying to fix
using (var context = new storemanagerEntities())
{
var stock = context.stocks.Where(x => x.id == model.Id).Select(
x => new stock()
{
description = x.description
}).FirstOrDefault();
stock.description = model.Description;
context.SaveChanges();
}
The error I am catching is this
**The entity or complex type 'StoreManagerModel.stock' cannot be constructed in a LINQ to Entities query.**
I'm sure using the "new" keyword is probably the problem, but does anyone have any ideas on how to solve this?
--update
This code works, but it doesn't seem to actually update the database
public void UpdateDescription(StockItemDescriptionModel model)
{
using (var context = new storemanagerEntities())
{
var stock = context.stocks.Where(x => x.id == model.Id)
.AsEnumerable()
.Select(
x => new stock
{
description = x.description
}).FirstOrDefault();
stock.description = model.Description;
context.SaveChanges();
}
}
At the moment it would seem it maybe my MySQl driver which is 6390, it seems to work in another version I tried, sorry I haven't found the answer yet
You can do it even without getting any entity from the database by creating a stub entity:
context.Configuration.ValidateOnSaveEnabled = false;
// Create stub entity:
var stock = new stock { id = model.Id, description = model.Description };
// Attach stub entity to the context:
context.Entry(stock).State = System.Data.Entity.EntityState.Unchanged;
// Mark one property as modified.
context.Entry(stock).Property("description").IsModified = true;
context.SaveChanges();
Validation on save is switched off, otherwise EF will validate the stub entity, which is very likely to fail because it may have required properties without values.
Of course it may be wise to check whether the entity does exist in the database at all, but that can be done by a cheap Any() query.
You can't project to a mapped entity type during an L2E query, you would need to switch the context back to L2F. For optimal performance it's recommended to use AsEnumerable over ToList to avoid materializing the query too early e.g.
var stock = context.stocks.Where(x => x.id == model.Id)
.AsEnumerable()
.Select(x => new stock
{
description = x.description
})
.FirstOrDefault();
As to your actual problem, the above won't allow you to do this as is because you have effectively created a non-tracking entity. In order for EF to understand how to connect your entity to your DB you would need to attach it to the context - this would require that you also pull down the Id of the entity though i.e.
Select(x => new stock
{
id = x.id,
description = x.description
})
...
context.stocks.Attach(stock);
stock.description = model.Description;
context.SaveChanges();

How to perform delete rows on some condition with EF?

in ADO.NET I can use delete statement
to delete some rows from an SQL table.
what is the equivalent in Entity Framework?
How can I achieve that same result?
updateing with null objects isn't the same.
Replies telling you, that you need to first fetch objects (strictly speaking keys are enough, but then you need to do some work manually) into memory and mark them for deletion and finally call SaveChanges. Though that's the "normal" approach, there's bunch of extensions, helpers, ... that allow you to do i.e. batch deletes, batch updates and other helpful stuff.
You can check EntityFramework.Extended (also on GitHub) or Entity Framework Extensions (sources there as well).
You need to retrieve the object to be deleted first.
For example :
// Assuming ID is primary key in `Customer` entity
Customer cust = (from c in context.Customers where c.ID = "1" select c);
Then delete the object using DataContext.entity.DeleteObject
context.Customers.DeleteObject(cust);
context.SaveChanges();
More : DataContext
First of all you need to create instance from your Database entities,after that you should select your desired object,then delete it :
TestEntities db = new TestEntities();
Test ts = (from rows in db.Tests
where rows.ID == 1
select rows).FirstOrDefault();
if (ts != null)
{
db.Tests.DeleteObject(ts);
db.SaveChanges();
}
Update :
If your result set is a list, I mean more than one record you can use this solution :
List<Test> lst = (from rows in db.Tests select rows).ToList();
foreach (Test item in lst)
{
db.Tests.DeleteObject(item);
}
db.SaveChanges();

What is the recommended practice to update or delete multiple entities in EntityFramework?

In SQL one might sometimes write something like
DELETE FROM table WHERE column IS NULL
or
UPDATE table SET column1=value WHERE column2 IS NULL
or any other criterion that might apply to multiple rows.
As far as I can tell, the best EntityFramework can do is something like
foreach (var entity in db.Table.Where(row => row.Column == null))
db.Table.Remove(entity); // or entity.Column2 = value;
db.SaveChanges();
But of course that will retrieve all the entities, and then run a separate DELETE query for each. Surely that must be much slower if there are many entities that satisfy the criterion.
So, cut a long story short, is there any support in EntityFramework for updating or deleting multiple entities in a single query?
EF doesn't have support for batch updates or deletes but you can simply do:
db.Database.ExecuteSqlCommand("DELETE FROM ...", someParameter);
Edit:
People who really want to stick with LINQ queries sometimes use workaround where they first create select SQL query from LINQ query:
string query = db.Table.Where(row => row.Column == null).ToString();
and after that find the first occurrence of FROM and replace the beginning of the query with DELETE and execute result with ExecuteSqlCommand. The problem with this approach is that it works only in basic scenarios. It will not work with entity splitting or some inheritance mapping where you need to delete two or more records per entity.
Take a look to Entity Framework Extensions (Multiple entity updates). This project allow set operations using lambda expressions. Samples from doc:
this.Container.Devices.Delete(o => o.Id == 1);
this.Container.Devices.Update(
o => new Device() {
LastOrderRequest = DateTime.Now,
Description = o.Description + "teste"
},
o => o.Id == 1);
Digging EFE project source code you can see how automatize #Ladislav Mrnka second approach also adding setting operations:
public override string GetDmlCommand()
{
//Recover Table Name
StringBuilder updateCommand = new StringBuilder();
updateCommand.Append("UPDATE ");
updateCommand.Append(MetadataAccessor.GetTableNameByEdmType(
typeof(T).Name));
updateCommand.Append(" ");
updateCommand.Append(setParser.ParseExpression());
updateCommand.Append(whereParser.ParseExpression());
return updateCommand.ToString();
}
Edited 3 years latter
Take a look to this great answer: https://stackoverflow.com/a/12751429
Entity Framework Extended Library helps to do this.
Delete
//delete all users where FirstName matches
context.Users.Delete(u => u.FirstName == "firstname");
Update
//update all tasks with status of 1 to status of 2
context.Tasks.Update(
t => t.StatusId == 1,
t2 => new Task {StatusId = 2});
//example of using an IQueryable as the filter for the update
var users = context.Users.Where(u => u.FirstName == "firstname");
context.Users.Update(users, u => new User {FirstName = "newfirstname"});
https://github.com/loresoft/EntityFramework.Extended

Categories

Resources