Entity Framework query with NOLOCK - entity-framework

This issue has been asked a lot.
And I find this Entity Framework with NOLOCK
When I test it, I notice that query with join
set transaction isolation level read committed
It seems that the solution only works on Single Table Query,
How can I mark the Multiple Table Join Query
set transaction isolation level read uncommitted
Belowing is my test code:
class Program
{
static void Main(string[] args)
{
TransactionOptions transactionOptions = new TransactionOptions();
transactionOptions.IsolationLevel = IsolationLevel.ReadUncommitted;
using (var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
{
using (var context = new BloggingContext())
{
(from a in context.Set<Post>()
join b in context.Set<Blog>() on a.BlogId equals b.BlogId
select new { a, b }).FirstOrDefault();
context.Set<Blog>().FirstOrDefault();
context.Set<Blog>().ToArray();
scope.Complete();
}
}

Related

Entity Framework 6: Multiple contexts from same database in 1 transaction

With 2 different context classes which use the same database what is the best way include changes to both in the same transaction?
You can use TransactionScope for distributed transaction. Concept:
using(var transaction = new TransactionScope())
{
using (var context1 = new DbContext1())
{
...
context1.SaveChanges();
}
using (var context2 = new DbContext2())
{
...
context2.SaveChanges();
}
transaction.Complete();
}
Only when TransactionScope is completed (committed), changes will reflect in database.

Mocking entity framework inner join

I need to unit test an inner join method from my Data Access Layer.
MY DAL looks like this:
public class MyDAL:IMyDAL
{
private MyContext context;
public MyDAL(MyContext Context)
{
this.context = Context;
}
public IEnumerable <Parent> Read(int childId)
{
var query = from parent in context.Parent
join child in context.Child on parent.Id equals child.Id
where child.Id == childId
select env;
return query.ToList();
}
And I want to unit test the Read method by mocking Entity framework, following this link http://msdn.microsoft.com/en-us/data/dn314429.aspx.
[TestMethod]
public void ReadMethod()
{
var data = new List<Parent>
{
new Parent { Id = 20 },
}.AsQueryable();
var data2 = new List<Child>
{
new Child { Id = 8 },
}.AsQueryable();
var mockSetPar = new Mock<DbSet<Parent>>();
var mockSetChild = new Mock<DbSet<Child>>();
mockSetPar.As<IQueryable<Parent>>().Setup(m => m.Provider).Returns(data.Provider);
mockSetPar.As<IQueryable<Parent>>().Setup(m => m.Expression).Returns(data.Expression);
mockSetPar.As<IQueryable<Parent>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSetPar.As<IQueryable<Parent>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
moockSetChild.As<IQueryable<Child>>().Setup(m => m.Provider).Returns(data2.Provider);
mockSetChild.As<IQueryable<Child>>().Setup(m => m.Expression).Returns(data2.Expression);
mockSetChild.As<IQueryable<Child>>().Setup(m => m.ElementType).Returns(data2.ElementType);
mockSetChild.As<IQueryable<Child>>().Setup(m => m.GetEnumerator()).Returns(data2.GetEnumerator());
var customDbContextMock = new Mock<MyContext>();
customDbContextMock.Setup(x => x.Parent).Returns(mockSetPar.Object);
customDbContextMock.Setup(x => x.Child).Returns(mockSetChild.Object);
var myDAL = new MyDAL(customDbContextMock.Object);
var actual = myDAL.Read(8);
Assert.IsNotNull(actual);
The result actual is empty because the join method hasn't been mocked so it returns nothing.
How can I mock the join method to return a value?
Thank you
In-memory test of DB interactions might be misleading because the LINQ to Entities capabilities are a subset of LINQ to Objects capabilities, so you can write a test that will be green but the query will always throw an exception in production.
This is also wrong on sole conceptual level. The DAL is a code that lays on a boundry of two systems - app and db. Its responsibility is to integrate them. So if you isolate those integration components your test becomes meaningless as it mocks away the core responsibility of the SUT.
To test the query logic, you have to use a database provider that behaves like the production one. So you need integration tests. = A useful solution is to use SQLite in-memory database. It will behave as the real database in most scenarios covered by Entity Framework yet perform almost as fast as mocks based on in-memory collections in unit tests.
You can consider SQLite as a database mock on steroids if you like.
I think you already noticed, that mocking EF queries is time-consuming and brittle. My suggestion - do not mock it. You can hide as much of data-access logic as you can under repository interfaces which is easy to mock:
public interface IParentRepository
{
IEnumerable<Parent> GetParentsOfChild(int childId);
}
Then test will look like:
[TestMethod]
public void ReadMethod()
{
int childId = // get sample id
var expected = // get sample parents
var repositoryMock = new Mock<IParentRepository>();
repositoryMock.Setup(r => r.GetParentsOfChild(childId))
.Returns(expected);
var myDAL = new MyDAL(repositoryMock.Object);
var actual = myDAL.Read(childId);
repositoryMock.VerifyAll();
CollectionAssert.AreEqual(actual, expected);
}
If you want to verify query implementation, then best way to do this is an acceptance/integration test which involves real database. Keep in mind - analyzing generated IQueryable is not enough to be sure your query will work in real environment. E.g. you can use operator Last() with IQueryable but this query will fail to be translated to SQL by Entity Framework.

Calling SP from EF using same transaction of SaveChanges

Does someone knows how to call a StoredProc using the same transaction of an objectContext SaveChanges method (EntityFramework 5)?
The goal is to apply the objects changes and call a stored Proc that does some "magic" on the DB, but, if something goes wrong (either with the SaveChanges or with the SP execution) no changes would be committed at all.
Steps:
Create the context
get the connection from the context
Create the transaction (TransactionScope)
Open the connection (will enlist the connection into the ambient transaction created in 3. and will prevent from closing the connection by the context)
Do SaveChanges()
Execute your stored procedure
Commit the transaction
Close the connection
Some code (MyContext is derived from DbContext):
using (var ctx = new MyContext())
{
using (var trx = new TransactionScope())
{
var connection = ((IObjectContextAdapter)ctx).ObjectContext.Connection;
try
{
ctx.Entities.Add(new MyEntity() { Number = 123 });
ctx.SaveChanges();
ctx.Database.ExecuteSqlCommand("INSERT INTO MyEntities VALUES(300)");
trx.Complete();
}
finally
{
connection.Close();
}
}
}

EF4.1 Code First - How to Assign/Remove from Many-To-Many?

I have a Many to Many relationship between Products and ProductGroups.
Using EF4.1 Code First, I'm getting strange and incosistent results when adding/removing Products to/from a ProductGroup.
My view works perfectly; it retunrs a GroupId and a List productIds. The problem is in the controller where I loop through the list of productIds and assign/remove to a ProductGroup.
Here's an extract from my code to remove Products from a ProductGroup:
ProductGroup productGroup = _Repository.GetProductGroup(groupId);
using (var db = GetDbContext())
{
foreach (var pId in productIds)
{
Product p = _Repository.GetProduct(Convert.ToInt32(pId));
productGroup.Products.Remove(p);
db.Entry(productGroup).State = System.Data.EntityState.Modified;
p.ProductGroups.Remove(productGroup);
db.Entry(p).State = System.Data.EntityState.Modified;
db.SaveChanges();
}
}
Basically, I have have to affect both the ProductGroup and individual Products to get any result... and then the results are mixed. For example, when inspecting the DB table (ProductGroupProducts) only some records will get removed, but I can't figure out the pattern of which are and which aren't.
I have similar issues when assigning a Products to a ProductGroup. The code is almost identical with the obvious .Add() instead of .Remove().
What am I missing here? Anybody know of a better, and hopefully more consistent, way of doing this?
Many thanks in advance!
Radu
What is GetDbContext()? If this creates a new context then db is obviously another context than the context you are using in _Repository. (If it returns the same context as _Repository is using then the using block is weird because it disposes the context at the end and therefore destroys also the context in _Repository).
You must attach the productGroup and p to the context where you are doing the modifications in:
ProductGroup productGroup = _Repository.GetProductGroup(groupId);
using (var db = GetDbContext())
{
db.ProductGroups.Attach(productGroup);
foreach (var pId in productIds)
{
Product p = _Repository.GetProduct(Convert.ToInt32(pId));
db.Products.Attach(p);
productGroup.Products.Remove(p);
}
db.SaveChanges();
}
I've removed p.ProductGroups.Remove(productGroup) because I think EF will do that automatically when you remove the product from the group (but I'm not sure; you can watch the collections in the debugger to see.)
If GetDbContext() indeed creates a new context rethink the design. You should only have one context for such operations (reading and updating).
Edit
This is possibly easier:
ProductGroup productGroup = _Repository.GetProductGroup(groupId);
using (var db = GetDbContext())
{
db.ProductGroups.Attach(productGroup);
foreach (var pId in productIds)
{
var p = productGroup.Products
.SingleOrDefault(p1 => p1.ID == Convert.ToInt32(pId))
if (p != null)
productGroup.Products.Remove(p);
}
db.SaveChanges();
}
It saves you the database query for the product. I'm assuming that you either using lazy loading or that _Repository.GetProductGroup has an Include for the products collection.

How do I delete multiple rows in Entity Framework (without foreach)

I want to delete several items from a table using Entity Framework. There is no foreign key / parent object, so I can't handle this with OnDeleteCascade.
Right now I'm doing this:
var widgets = context.Widgets
.Where(w => w.WidgetId == widgetId);
foreach (Widget widget in widgets)
{
context.Widgets.DeleteObject(widget);
}
context.SaveChanges();
It works, but the foreach bugs me. I'm using EF4, but I don't want to execute SQL. I just want to make sure I'm not missing anything -- this is as good as it gets, right? I can abstract the code with an extension method or helper, but somewhere we're still going to be doing a foreach, right?
EntityFramework 6 has made this a bit easier with .RemoveRange().
Example:
db.People.RemoveRange(db.People.Where(x => x.State == "CA"));
db.SaveChanges();
Warning! Do not use this on large datasets!
EF pulls all the data into memory, THEN deletes it. For smaller data sets this might not be an issue but generally avoid this style of delete unless you can guarantee you are only doing very small changes.
You could easily run your process out of memory while EF happily pulls in all the data you specified just to delete it.
using (var context = new DatabaseEntities())
{
context.ExecuteStoreCommand("DELETE FROM YOURTABLE WHERE CustomerID = {0}", customerId);
}
Addition: To support list of ids you can write
var listOfIds = String.Join(',',customerIds.Select(id => $"'{id}'").ToList());
var sql= $#"DELETE [YOURTABLE] WHERE CustomerID in ({listOfIds})";
Note: if CustomerID Is a string, you should double-check for potential SQL injection risks, for integer CustomerID it’s safe
this is as good as it gets, right? I can abstract it with an extension
method or helper, but somewhere we're still going to be doing a
foreach, right?
Well, yes, except you can make it into a two-liner:
context.Widgets.Where(w => w.WidgetId == widgetId)
.ToList().ForEach(context.Widgets.DeleteObject);
context.SaveChanges();
I know it's quite late but in case someone needs a simple solution, the cool thing is you can also add the where clause with it:
public static void DeleteWhere<T>(this DbContext db, Expression<Func<T, bool>> filter) where T : class
{
string selectSql = db.Set<T>().Where(filter).ToString();
string fromWhere = selectSql.Substring(selectSql.IndexOf("FROM"));
string deleteSql = "DELETE [Extent1] " + fromWhere;
db.Database.ExecuteSqlCommand(deleteSql);
}
Note: just tested with MSSQL2008.
Update:
The solution above won't work when EF generates sql statement with parameters, so here's the update for EF5:
public static void DeleteWhere<T>(this DbContext db, Expression<Func<T, bool>> filter) where T : class
{
var query = db.Set<T>().Where(filter);
string selectSql = query.ToString();
string deleteSql = "DELETE [Extent1] " + selectSql.Substring(selectSql.IndexOf("FROM"));
var internalQuery = query.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(field => field.Name == "_internalQuery").Select(field => field.GetValue(query)).First();
var objectQuery = internalQuery.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(field => field.Name == "_objectQuery").Select(field => field.GetValue(internalQuery)).First() as ObjectQuery;
var parameters = objectQuery.Parameters.Select(p => new SqlParameter(p.Name, p.Value)).ToArray();
db.Database.ExecuteSqlCommand(deleteSql, parameters);
}
It requires a little bit of reflection but works well.
If you don't want to execute SQL directly calling DeleteObject in a loop is the best you can do today.
However you can execute SQL and still make it completely general purpose via an extension method, using the approach I describe here.
Although that answer was for 3.5. For 4.0 I would probably use the new ExecuteStoreCommand API under the hood, instead of dropping down to the StoreConnection.
For anyone using EF5, following extension library can be used: https://github.com/loresoft/EntityFramework.Extended
context.Widgets.Delete(w => w.WidgetId == widgetId);
Entity Framework Core
3.1 3.0 2.2 2.1 2.0 1.1 1.0
using (YourContext context = new YourContext ())
{
var widgets = context.Widgets.Where(w => w.WidgetId == widgetId);
context.Widgets.RemoveRange(widgets);
context.SaveChanges();
}
Summary:
Removes the given collection of entities from the context underlying the set
with each entity being put into the Deleted state such that it will be deleted
from the database when SaveChanges is called.
Remarks:
Note that if System.Data.Entity.Infrastructure.DbContextConfiguration.AutoDetectChangesEnabled
is set to true (which is the default), then DetectChanges will be called once
before delete any entities and will not be called again. This means that in some
situations RemoveRange may perform significantly better than calling Remove multiple
times would do. Note that if any entity exists in the context in the Added state,
then this method will cause it to be detached from the context. This is because
an Added entity is assumed not to exist in the database such that trying to delete
it does not make sense.
Still seems crazy to have to pull anything back from the server just to delete it, but at least getting back just the IDs is a lot leaner than pulling down the full entities:
var ids = from w in context.Widgets where w.WidgetId == widgetId select w.Id;
context.Widgets.RemoveRange(from id in ids.AsEnumerable() select new Widget { Id = id });
Finally bulk delete has been introduced in Entity Framework Core 7 via the ExecuteDelete command:
context.Widgets
.Where(w => w.WidgetId == widgetId)
.ExecuteDelete();
Something to note here is that ExecuteDelete does not need a SaveChanges, as per its documentation:
This operation executes immediately against the database, rather than being deferred until DbContext.SaveChanges() is called. It also does not interact with the EF change tracker in any way: entity instances which happen to be tracked when this operation is invoked aren't taken into account, and aren't updated to reflect the changes.
I know that the question was asked for EF4, but if you upgrade this is a good alternative!
EF 6.1
public void DeleteWhere<TEntity>(Expression<Func<TEntity, bool>> predicate = null)
where TEntity : class
{
var dbSet = context.Set<TEntity>();
if (predicate != null)
dbSet.RemoveRange(dbSet.Where(predicate));
else
dbSet.RemoveRange(dbSet);
context.SaveChanges();
}
Usage:
// Delete where condition is met.
DeleteWhere<MyEntity>(d => d.Name == "Something");
Or:
// delete all from entity
DeleteWhere<MyEntity>();
For EF 4.1,
var objectContext = (myEntities as IObjectContextAdapter).ObjectContext;
objectContext.ExecuteStoreCommand("delete from [myTable];");
The quickest way to delete is using a stored procedure. I prefer stored procedures in a database project over dynamic SQL because renames will be handled correctly and have compiler errors. Dynamic SQL could refer to tables that have been deleted/renamed causing run time errors.
In this example, I have two tables List and ListItems. I need a fast way to delete all the ListItems of a given list.
CREATE TABLE [act].[Lists]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY,
[Name] NVARCHAR(50) NOT NULL
)
GO
CREATE UNIQUE INDEX [IU_Name] ON [act].[Lists] ([Name])
GO
CREATE TABLE [act].[ListItems]
(
[Id] INT NOT NULL IDENTITY,
[ListId] INT NOT NULL,
[Item] NVARCHAR(100) NOT NULL,
CONSTRAINT PK_ListItems_Id PRIMARY KEY NONCLUSTERED (Id),
CONSTRAINT [FK_ListItems_Lists] FOREIGN KEY ([ListId]) REFERENCES [act].[Lists]([Id]) ON DELETE CASCADE
)
go
CREATE UNIQUE CLUSTERED INDEX IX_ListItems_Item
ON [act].[ListItems] ([ListId], [Item]);
GO
CREATE PROCEDURE [act].[DeleteAllItemsInList]
#listId int
AS
DELETE FROM act.ListItems where ListId = #listId
RETURN 0
Now the interesting part of deleting the items and updating Entity framework using an extension.
public static class ListExtension
{
public static void DeleteAllListItems(this List list, ActDbContext db)
{
if (list.Id > 0)
{
var listIdParameter = new SqlParameter("ListId", list.Id);
db.Database.ExecuteSqlCommand("[act].[DeleteAllItemsInList] #ListId", listIdParameter);
}
foreach (var listItem in list.ListItems.ToList())
{
db.Entry(listItem).State = EntityState.Detached;
}
}
}
The main code can now use it is as
[TestMethod]
public void DeleteAllItemsInListAfterSavingToDatabase()
{
using (var db = new ActDbContext())
{
var listName = "TestList";
// Clean up
var listInDb = db.Lists.Where(r => r.Name == listName).FirstOrDefault();
if (listInDb != null)
{
db.Lists.Remove(listInDb);
db.SaveChanges();
}
// Test
var list = new List() { Name = listName };
list.ListItems.Add(new ListItem() { Item = "Item 1" });
list.ListItems.Add(new ListItem() { Item = "Item 2" });
db.Lists.Add(list);
db.SaveChanges();
listInDb = db.Lists.Find(list.Id);
Assert.AreEqual(2, list.ListItems.Count);
list.DeleteAllListItems(db);
db.SaveChanges();
listInDb = db.Lists.Find(list.Id);
Assert.AreEqual(0, list.ListItems.Count);
}
}
You can use extensions libraries for doing that like EntityFramework.Extended or Z.EntityFramework.Plus.EF6, there are available for EF 5, 6 or Core. These libraries have great performance when you have to delete or update and they use LINQ. Example for deleting (source plus):
ctx.Users.Where(x => x.LastLoginDate < DateTime.Now.AddYears(-2))
.Delete();
or (source extended)
context.Users.Where(u => u.FirstName == "firstname")
.Delete();
These use native SQL statements, so performance is great.
This answers is for EF Core 7 (I am not aware if they merged EF Core with EF now or not, before they kept the two separately).
EF Core 7 now supports ExecuteUpdate and ExecuteDelete (Bulk updates):
// Delete all Tags (BE CAREFUL!)
await context.Tags.ExecuteDeleteAsync();
// Delete Tags with a condition
await context.Tags.Where(t => t.Text.Contains(".NET")).ExecuteDeleteAsync();
The equivalent SQL queries are:
DELETE FROM [t]
FROM [Tags] AS [t]
DELETE FROM [t]
FROM [Tags] AS [t]
WHERE [t].[Text] LIKE N'%.NET%'
If you want to delete all rows of a table, you can execute sql command
using (var context = new DataDb())
{
context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
}
TRUNCATE TABLE (Transact-SQL) Removes all rows from a table without logging the individual row deletions. TRUNCATE TABLE is similar to the DELETE statement with no WHERE clause; however, TRUNCATE TABLE is faster and uses fewer system and transaction log resources.
You can execute sql queries directly as follows :
private int DeleteData()
{
using (var ctx = new MyEntities(this.ConnectionString))
{
if (ctx != null)
{
//Delete command
return ctx.ExecuteStoreCommand("DELETE FROM ALARM WHERE AlarmID > 100");
}
}
return 0;
}
For select we may use
using (var context = new MyContext())
{
var blogs = context.MyTable.SqlQuery("SELECT * FROM dbo.MyTable").ToList();
}
UUHHIVS's is a very elegant and fast way for batch delete, but it must be used with care:
auto generation of transaction: its queries will be encompassed by a transaction
database context independence: its execution has nothing to do with context.SaveChanges()
These issues can be circumvented by taking control of the transaction. The following code illustrates how to batch delete and bulk insert in a transactional manner:
var repo = DataAccess.EntityRepository;
var existingData = repo.All.Where(x => x.ParentId == parentId);
TransactionScope scope = null;
try
{
// this starts the outer transaction
using (scope = new TransactionScope(TransactionScopeOption.Required))
{
// this starts and commits an inner transaction
existingData.Delete();
// var toInsert = ...
// this relies on EntityFramework.BulkInsert library
repo.BulkInsert(toInsert);
// any other context changes can be performed
// this starts and commit an inner transaction
DataAccess.SaveChanges();
// this commit the outer transaction
scope.Complete();
}
}
catch (Exception exc)
{
// this also rollbacks any pending transactions
scope?.Dispose();
}
In EF 7 you can use bulk delete
var ids = widgets.Select(x => x.Id).ToList();
await _mrVodDbContext.Widgets.Where(x => ids.Contains(x.Id)).ExecuteDeleteAsync();
EF core generate
DELETE FROM [i]
FROM [Widgets] AS [i]
WHERE [i].[Id] IN (4,3,2,1)
More about deleting or updating in release notes. https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-7.0/whatsnew#basic-executedelete-examples
You can also use the DeleteAllOnSubmit() method by passing it your results in a generic list rather than in var. This way your foreach reduces to one line of code:
List<Widgets> widgetList = context.Widgets
.Where(w => w.WidgetId == widgetId).ToList<Widgets>();
context.Widgets.DeleteAllOnSubmit(widgetList);
context.SubmitChanges();
It probably still uses a loop internally though.
Thanh's answer worked best for me. Deleted all my records in a single server trip. I struggled with actually calling the extension method, so thought I would share mine (EF 6):
I added the extension method to a helper class in my MVC project and changed the name to "RemoveWhere". I inject a dbContext into my controllers, but you could also do a using.
// make a list of items to delete or just use conditionals against fields
var idsToFilter = dbContext.Products
.Where(p => p.IsExpired)
.Select(p => p.ProductId)
.ToList();
// build the expression
Expression<Func<Product, bool>> deleteList =
(a) => idsToFilter.Contains(a.ProductId);
// Run the extension method (make sure you have `using namespace` at the top)
dbContext.RemoveWhere(deleteList);
This generated a single delete statement for the group.
I came up with a great library Zack.EFCore.Batch. It will convert your expression into simple DELETE FROM .... WHERE query. (Like some answers proposed) https://github.com/yangzhongke/Zack.EFCore.Batch
The usage example:
await ctx.DeleteRangeAsync<Book>(b => b.Price > n);
The Zack.EFCore.Batch library has lots of benefits over Z.EntityFramework.Extended https://entityframework-extensions.net/ which does not have true Async methods. (They are just wrappers around sync methods) You can get lots of unexpected issues by using this library in high load environment.
EF 6.=>
var assignmentAddedContent = dbHazirBot.tbl_AssignmentAddedContent.Where(a =>
a.HazirBot_CategoryAssignmentID == categoryAssignment.HazirBot_CategoryAssignmentID);
dbHazirBot.tbl_AssignmentAddedContent.RemoveRange(assignmentAddedContent);
dbHazirBot.SaveChanges();
Best : in EF6 => .RemoveRange()
Example:
db.Table.RemoveRange(db.Table.Where(x => Field == "Something"));
If you are using Generic Repository:
Inside Generic repository, following could be new method.
public void RemoveMultiple(Expression<Func<T, bool>> predicate)
{
IQueryable<T> query = _context.Set<T>().Where(predicate);
_context.Set<T>().RemoveRange(query.AsNoTracking());
}
Usage:
_unitOfWork.YOUR_ENTITY.RemoveMultiple(x => x.AccountId == accountId);
_unitOfWork.Complete();
context.Widgets.RemoveRange(context.Widgets.Where(w => w.WidgetId == widgetId).ToList());
db.SaveChanges();
See the answer 'favorite bit of code' that works
Here is how I used it:
// Delete all rows from the WebLog table via the EF database context object
// using a where clause that returns an IEnumerable typed list WebLog class
public IEnumerable<WebLog> DeleteAllWebLogEntries()
{
IEnumerable<WebLog> myEntities = context.WebLog.Where(e => e.WebLog_ID > 0);
context.WebLog.RemoveRange(myEntities);
context.SaveChanges();
return myEntities;
}
In EF 6.2 this works perfectly, sending the delete directly to the database without first loading the entities:
context.Widgets.Where(predicate).Delete();
With a fixed predicate it's quite straightforward:
context.Widgets.Where(w => w.WidgetId == widgetId).Delete();
And if you need a dynamic predicate have a look at LINQKit (Nuget package available), something like this works fine in my case:
Expression<Func<Widget, bool>> predicate = PredicateBuilder.New<Widget>(x => x.UserID == userID);
if (somePropertyValue != null)
{
predicate = predicate.And(w => w.SomeProperty == somePropertyValue);
}
context.Widgets.Where(predicate).Delete();