How to delete elements by ID? - c#

I have a list of ids
IEnumerable<long> ids
How can I delete from a table where the ID matches?

The "standard" way according to the MSDN docs is to use those IDs to pull up each of the objects, then delete them with the DeleteObject command:
context.Where(x=>ids.Contains(x.Id)).ToList().ForEach(context.DeleteObject);
This will produce N+1 roundtrips to the DB. This is a common downside of ORMs; they're excellent at 99% of everyday use of SQL by an app (querying for results, creating/updating/deleting single objects) but are not really designed for these bulk operations.
You could also construct a query using ExecuteStoreCommand, where you "DELETE FROM table WHERE id IN #p1" and specify the list of IDs as a parameter.

Assuming you have Id as primary key in your entities and you have an entity called SampleEntity you could do something like this:
foreach(long id in ids)
{
var sampleEntity = context.SampleEntities.SingleOrDefault( e => e.Id == id);
if(sampleEntity!=null)
context.SampleEntities.DeleteObject(sampleEntity);
}
context.SaveChanges();
EF does not support batch operation, so you will have to delete entities one by one, or alternatively do a direct store query (SQL) to make the deletion.

Generically
var db = GetYourDBContext();
var ItemsToDelete = (from id in ids
from item in db.TableWithItems
where item.id == id
select item).ToList();
foreach (Item item in ItemsToDelete)
db.DeleteObject(item);
db.SaveChanges();

How about something like,
context.Entities.Where(e => ids.Contains(e.id))
.ToList()
.ForEach(e => context.SampleEntities.DeleteObject(e) );
context.saveChanges();

Related

Better way to join tables with Entity Framework

Good morning,
I have inherited a database with no foreign key relations and the project is such that i have to ignore this major issue and work around it. Obviously this eliminates some of the cooler features of Entity Framework providing me related entities automatically.
So i have been forced to do something like this:
using (var db = new MyEntities())
{
Entities.Info record = db.Infoes.Where(x => x.UserId == authInfo.User.Id).FirstOrDefault();
//Get all the accounts for the user
List<Entities.AcctSummary> accounts = db.AcctSummaries.Where(x => x.InfoId == record.Id).ToList();
//Loop through each account
foreach (Entities.AcctSummary account in accounts)
{
//pull records for account
List<Entities.Records> records= db.Records.Where(x => x.AcctSummaryId == account.Id).ToList();
}
}
If there a better way to join the "record" and "accounts" Entities, or perhaps a more efficient way for getting "records" in a single query?
TIA
Are you just looking for the .Join() extension method? As an example, joining Infoes and Accounts might look like this:
var accounts = db.Infoes.Join(db.Accounts,
i => i.Id,
a => a.InfoId,
(info, account) => new { info, account });
This would result in accounts being an enumeration of an anonymous type with two properties, one being the Info record and the other being the Account record. The collection would be the full superset of the joined records.
You can of course return something other than new { info, account }, it works just like anything you'd put into a .Select() clause. Whatever you select from these joined tables would be what you have an enumeration of in accounts. You can further join more tables by changing .Join() extensions, returning whatever you want from each.

Inefficient entity framework queries

I have a following foreach statement:
foreach (var articleId in cleanArticlesIds)
{
var countArt = context.TrackingInformations.Where(x => x.ArticleId == articleId).Count();
articleDictionary.Add(articleId, countArt);
}
Database looks like this
TrackingInformation(Id, ArticleId --some stuff
Article(Id, --some stuff
what I want to do is to get all the article ids count from TrackingInformations Table.
For example:
ArticleId:1 Count:1
ArticleId:2 Count:8
ArticleId:3 Count:5
ArticleId:4 Count:0
so I can have a dictionary<articleId, count>
Context is the Entity Framework DbContext. The problem is that this solution works very slow (there are > 10k articles in db and they should rapidly grow)
Try next query to gather grouped data and them add missing information. You can try to skip Select clause, I don't know if EF can handle ToDictionary in good manner.
If you encounter Select n + 1 problem (huge amount of database requests), you can add ToList() step between Select and ToDictionary, so that all required information will be brought into memory.
This depends all your mapping configuration, environment, so in order to get good performance, you need to play a little bit with different queries. Main approach is to aggregate as much data as possible at database level with few queries.
var articleDictionary =
context.TrackingInformations.Where(trackInfo => cleanArticlesIds.Contains(trackInfo.ArticleId))
.GroupBy(trackInfo => trackInfo.ArticleId)
.Select(grp => new{grp.Key, Count = grp.Count()})
.ToDictionary(info => "ArticleId:" + info.Key,
info => info.Count);
foreach (var missingArticleId in cleanArticlesIds)
{
if(!articleDictionary.ContainsKey(missingArticleId))
articleDictionary.add(missingArticleId, 0);
}
If TrackingInformation is a navigatable property of Article, then you can do this:
var result=context.Article.Select(a=>new {a.id,Count=a.TrackingInformation.Count()});
Putting it into a dictionary is simple as well:
var result=context.Article
.Select(a=>new {a.id,Count=a.TrackingInformation.Count()})
.ToDictionary(a=>a.id,a=>a.Count);
If TrackingInforation isn't a navigatable property, then you can do:
var result=context.Article.GroupJoin(
context.TrackingInformation,
foo => foo.id,
bar => bar.id,
(x,y) => new { id = x.id, Count = y.Count() })
.ToDictionary(a=>a.id,a=>a.Count);

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

Linking Multiple Tables in LINQ to SQL

I would like to get the list of albums (Distinct) which was sung by the artistId=1
I am very new to LINQ to SQL and do not know how to join multiple tables. Please see the database diagram below:
alt text http://a.imageshack.us/img155/8572/13690801.jpg
SingBy is the middle table between Track and Artist.
How could I achieve this?
var albums = from singer in artist
from sb in singby
from t in track
from a in album
where singer.artistId == 1 &&
sb.artistId == 1 &&
sb.trackId == t.trackId &&
a.albumId == track.albumId
select a;
I'm sure there must be a better way. You should look into creating Navigation Properties on your entities. Navigation Properties are like foreign keys.
Edit - corrected to get albums, not artists.
Now, I wrote the codes like the following and it works.
var albums = (from a in db.artists
where a.artistId == 1
join sb in db.singbies on a equals sb.artist
join t in db.tracks on sb.track equals t
join al in db.albums on t.album equals al
select al).Distinct();
return albums.ToList() as List<album>;
I tested the Chad's version and it works too. I would like to know which way is better and good for query optimization? Thanks all.
If you have all the foreign key relationship defined, you should be able to issue call like below:
dc.GetTable<Album>().Where(a => a.Track.Singby.ArtistId == 1).ToList();
This is relying on Linq to perform lazy load for Track and Singby automatically when required. Obviously this is not optimal to use when you have a large set of data in the db and performance is critical. You can chain the query with GroupBy or Distinct operation to return only the distinct set such as
dc.GetTable<Album>().Where(a => a.Track.Singby.ArtistId == 1).Distinct().ToList();
I would like to get the list of albums
(Distinct) which was sung by the
artistId=1
DBDataContext = new DBDataContext();
album[] = db.artists.Where(a => a.artistId == 1) /* Your artist */
.SelectMany(a => a.singbies) /* Check if `singby` converted to `singbies` */
.Select(sb => sb.track) /* The tracks */
.Select(t => t.album) /* The albums */
.GroupBy(al => al.albumId) /* Group by id */ /* "Distinct" for objects */
.Select(alG => alG.First()) /* Select first of each group */
.ToArray();
IEnumerable<Album> query =
from album in myDC.Albums
let artists =
from track in album.Tracks
from singBy in track.SingBys
select singBy.Artist
where artists.Any(artist => artist.ArtistId == 1)
select album;
List<int> Ids = dc.Albums.Where(a => a.Track.Singby.ArtistId == 1).Select(a=> a.albumId).Distinct().ToList();
List<Album> distinctAlbums = dc.Albums.Where(a => distinctAlbumIds.Contains(a.albumId)).ToList();
Hey TTCG, above is the simplest way to do it. This is because doing a Distinct on a List of objects won't do it based on the albumId.
Either you do it in two steps as above, or, you write your own Album Comparer which specifies uniqueness based on AlbumId and pass it to the Distinct call on a List.
NOTE:
The above will only work if you've defined the constraints in your DBML, but better still in your DB.
For best practices, always define your relationships IN THE DATABASE when using Linq to SQL, as Linq to SQL is not like EF, or NHibernate, in that is does not "abstract" your db, it simply reflects it. It's a tool for Data Driven Design, not Domain Driven, so define the relationships in the db.

Categories

Resources