Proper way to delete record in LINQ to Entities - c#

I just have a very simple situation where all I need is to delete record using Linq2Entities. I tried to do some research and still can't figure out the right way to do it.
Here's my simple code:
[DataObjectMethod(DataObjectMethodType.Delete)]
public void DeleteEmployee(Employee z)
{
using (var ctx = new MyEntity())
{
var x = (from y in ctx.Employees
where y.EmployeeId == z.EmployeeId
select y).FirstOrDefault();
ctx.DeleteObject(x);
ctx.SaveChanges();
}
}
[DataObjectMethod(DataObjectMethodType.Select)]
public List<Employee> GetAllEmployee()
{
using (var ctx = new MyEntity())
{
var x = from y in ctx.Employees
select y;
return x.ToList();
}
}
I can delete a particular record if for example I assign y.EmployeeName == "Harold Javier" to the Delete method above, but when I assign y.EmployeeId == z.EmployeeId to the above code, the delete doesn't work. (Note: EmployeeId is the primary key of the Employee table)

I think this is better option of delete
using (var ctx = new MyEntity())
{
var x = (from y in ctx.Employees
orderby y.EmployeeId descending
select y).FirstOrDefault();
ctx.Employees.Remove(x);
ctx.SaveChanges();
}
at my side DeleteObject is not working so i use Remove

you first need to verify that if a record exists before you actually delete it;
[DataObjectMethod(DataObjectMethodType.Delete)]
public void DeleteEmployee(Employee z)
{
using (var ctx = new MyEntity())
{
var x = (from y in ctx.Employees
where y.EmployeeId == z.EmployeeId
select y).FirstOrDefault();
if(x!=null)
{
ctx.Employees.DeleteObject(x);
ctx.SaveChanges();
}
}
}
Always check for nulls, before you delete something. Because a user may change the Id (at querystring) and try different combinations.

The above answer may be outdated... The DeleteObject method does not seem to exist in the current version of ENtity Framework. I had to use the Remove method.
var delobj = db.mytable.Where(p => p.ServiceLocation == serviceLocationID).SingleOrDefault();
db.myTable.Remove(delobj);

#Harold, I know this post is quite old, but I feel it is important to address your original question and answer. Your solution may have worked in your situation, but there are a couple of problems.
First, your original code was selecting the record to delete based on a passed in parameter. Your solution is deleting the record with the largest EmployeeId. That might be what you wish, but not likely.
The second issue is that two database accesses are required to accomplish the delete. The first is get the entity to delete the second to actually perform the delete.
The following code snippet will eliminate the need to to the read and will delete employee "z". This should yield the desired result and perform much better.
public void DeleteEmployeeId(Employee z)
{
using (var ctx = new MyEntityContext())
{
var x = new Employee{ EmployeeId = z.EmployeeId };
ctx.Entry(x).State = EntityState.Deleted;
ctx.SaveChanges();
}
}

I decided to answer my own question.
My delete function worked when I did the following:
using (var ctx = new MyEntity())
{
var x = (from y in ctx.Employees
orderby y.EmployeeId descending
select y).FirstOrDefault();
ctx.Employees.DeleteObject(x);
ctx.SaveChanges();
}
I know there could be a better approach than this, but it works for me for the mean time.

The following worked for me:
MyList.RemoveAll(x => x.MyField == 0);

This is probably because the context is different on each request (var ctx = new MyEntity()). Try using this
public static class ObjectContextPerHttpRequest
{
public static TestCasesModelContainer Context
{
get
{
string objectContextKey = HttpContext.Current.GetHashCode().ToString("ObjectContextPerHttpRequest");
if (!HttpContext.Current.Items.Contains(objectContextKey))
{
HttpContext.Current.Items.Add(objectContextKey, new TestCasesModelContainer());
}
return HttpContext.Current.Items[objectContextKey] as TestCasesModelContainer;
}
}
}
And delete is like
public static void Delete(Testcase tc)
{
var db = ObjectContextPerHttpRequest.Context;
db.DeleteObject((from p in db.TestcaseSet
where p.Id == tc.Id
select p).Single());
db.SaveChanges();
}

Related

How do I filter duplicates in Entity Framework minimize performance loss?

How can I make the performance better of the code below?
I'm loading the carItems from an external webservice in a list.
carItem is checked whether it exists in EF.
If carItem is new, then it's mapped to carsCol and added to the database. What are some easy ways to improve the performance of this using code?
carItems = carItems.Where(x => x.Name == "Tesla");
// Filter existing cars
List<Car> carsCol = new List<Car>();
foreach (var item in carItems)
{
if (GetById(item.Id) == null)
{
carsCol.Add(item);
}
}
Entities.AddRange(carsCol);
Depending on the situation, you can try to find out which ids already exist in the database by making a single query before the foreach.
var newCarItemIds = carItems.Select(x => x.Id);
var alreadyExistentCarItemIds = Entities.CarItems.Where(x => newCarItemIds.Contains(x.Id)).Select(x=>x.Id);
foreach(var item in carItems)
{
if(!alreadyExistentCarItemIds.Contains(x))
{
carsCol.Add(item);
}
}
You can use Distinct Linq functions: example
You must to implement IEquatable interface
I would propose this. You can do a left outter join with the cars that you get from your API and the existing one. Than you get the new cars that will be added.
var newCars = (from c in carItems
join e in Entities.CarItems on c.Id equals e.Id into g
from x in g.DefaultIfEmpty()
select new { c, IsNew = x == null }).Where(x = x.IsNew).ToList()
With that you do only one access to the database. Also when working with IEnumerable is always good to convert it to either a list or array, that way each time that you iterates through that object you don't run a query in your database.

How to load another table and use it - using linq to sql

I have a table in my database called Profile, I have another table called ProfileConfirmed. The purpose of this table is to confirm that the person confirmed his email address. I would like to have it that when I loop through all the profiles, the profiles that have not been confirmed do not show up.
Here is my foreach
#foreach (var c in Model.Profiles)
{
}
Here is where I am getting the profiles in my models
public List<Cleaner> GetProfiles()
{
using (var context = new CleanerDataContext(_connectionString))
{
var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Cleaner>(c => c.ProfileConfirmed);
context.LoadOptions = loadOptions;
return context.Cleaners.ToList();
}
}
I suggest you disregard the 2nd table and add an 'IsConfirmed' with a bit data type column on your 1st table. Then
var query = (from profiles in context.ProfileTable
where IsConfirmed == true select profiles).ToList();
return query;
Less code. Less hassle.
The problem is with this part:
return context.Cleaners.ToList();
ToList() method will always get a new copy of the array, though the objects in it aren't copies, they are the same references as in the original array.
public List<Cleaner> GetProfiles()
{
using (var context = new CleanerDataContext(_connectionString))
{
var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Cleaner>(c => c.ProfileConfirmed);
context.LoadOptions = loadOptions;
var confirmedProfilers =
from cust in db.SomeTable
where c.ProfileConfirmed == true
select cust;
return confirmedProfilers.ToList();
}
}

Copy the duplicate records in MVC using Entity Framwork

I am new in MVC Entity Framework.
I have one Table called Product. it contain 40 fields.
I have one task to copy the Product or to create the duplicate record in same table with new Product ID..
How can I do this in efficient ways?
I tried using the below code
Public ActionResult CopyProduct(long ProductID)
{
var oldProductScript = db.Products.FirstOrDefault(x=>x.ProductID == ProductID)
Product p = new Product();
p.name = oldProductScript.name;
p.price =oldProductScript.price;
p.model =oldProductScript.model;
p.image = oldProductScript.image;
p.status =oldProductScript.status;
.
.
.
.
.
like so till 40th field
db.Products.AddObject(p);
db.SaveChanges();
}
Is this the proper way to complete this task?
Please suggest.
Thanks
If you want this to be done much easier(reduced coding), I would recommend you to use Code First Approach.
Use this link to know what is it and code sample.
After you add the tables with models(DBContext) as using Code First Approach, you would be able to easily get and set properties of the table even faster than your usual method.
public class InheritanceMappingContext : DbContext
{
public DbSet<TableName> TableProperty { get; set; }
}
Use a polymorphic query to retrieve the fields of the table.
IQueryable<TableName> linqQuery = from b in context.TableName select b;
List<TableName> tableFields = linqQuery.ToList();
linqQuery returns list of objects of the type
Warning: I've tested this with one of my classes and it worked. Not sure if it will work with yours:
var prod = context.Products.FirstOrDefault(p => p.ProductID == ProductID);
var prod2 = new Products();
foreach (PropertyInfo pi in prod.GetType().GetProperties())
{
prod2.GetType().GetProperties().First(p=>p.Name==pi.Name).SetValue(prod2, pi.GetValue(prod, null), null);
}
//prod2 is now a clone of prod. Make sure to adjust your product ID before adding the new product.
Try something like this:
Products productToCopy = db.Products.FirstOrDefault(p => p.ProductId == productID);
db.Entry(productToCopy).State = EntityState.Detached;
productToCopy.ProductId = 0;
db.Products.Add(productToCopy);
db.SaveChanges();

How to delete in Entity Framework

I have a query:
var q = (from c in session.db.students
where c.id==5
select c);
How can I delete this record? I've tried deleteonsubmit, deleteobject, delete... but none of them are not known.
For example in code below, delete not known:
foreach (student s in q)
{ s.deleteobject;}
session.db.savechanges();
or:
var q = (from c in session.db.students
where c.id==5
select c).deleteOnSubmit();
None of them is not defined.... where is the problem?
You should use Remove:
var q = (from c in session.db.students
where c.id==5
select c);
foreach(student s in q)
{
session.db.students.Remove(s);
}
session.db.SaveChanges();
You want to call .remove([record]) on the DbContext object. Using your code you would do the following:
var q = (from c in session.db.students where c.id == 5 select c);
foreach (student s in q)
{
session.db.Remove(s);
}
session.db.SaveChanges();
or using method based querying (to remove a single record with id 5):
var s = session.db.students.Where(p => p.id == 5).FirstOrDefault();
if(s != null) { session.db.Remove(s); }
session.db.SaveChanges();
Look this answer. maybe it will help
https://stackoverflow.com/a/17723658/4571664
then also you can use this
((DbContext)dbContext).Set<objectName>().Remove(singleObject);
dbContext.SaveChanges();
if you need multiple object delete, you can use this code in foreach.
Try using dbcontext, you can use remove or removerange.
using (var MyContext= new CRMDBContext(connString))
{
MyContext.[Table].RemoveRange(MyContext.[Table].Where(x => x.[column]== [column]));
MyContext.SaveChanges();
}
You can use Remove() or RemoveRange() methods on your context for deleting objects.
If you have collection of objects:
session.db.students.RemoveRange(collectionOfStudents);
session.db.SaveChanges();
If you have just one object:
session.db.students.Remove(oneStudent);
session.db.SaveChanges();

Entity Framework 4.1. Updating many-to-many relationships. Is this the right way?

The code below works, however, I suspect that I'm missing something. Is there a 'better' way?
private void UpdateNew(MarketProduct marketproduct)
{
context.MarketCategories.Load();
MarketProduct dbProd = context.MarketProducts.Find(marketproduct.Id);
dbProd.Categories.Clear();
foreach (var c in marketproduct.Categories ?? Enumerable.Empty<MarketCategory>())
{
var cc = context.MarketCategories.Find(c.Id);
dbProd.Categories.Add(cc);
}
context.Entry(dbProd).CurrentValues.SetValues(marketproduct);
}
I thought it would be possible to do this without using Find
You have three database queries: 1) context.MarketCategories.Load() (hopefully the category table is small, otherwise this would be a no-go as it loads the whole table into memory), 2) ...Find and 3) dbProd.Categories.Clear(): Here must be a lazy loading involved, otherwise this would crash because dbProd.Categories would be null.
An alternative to update with a single database query is the following:
private void UpdateNew(MarketProduct marketproduct)
{
MarketProduct dbProd = context.MarketProducts
.Include(p => p.Categories)
.Single(p => p.Id == marketproduct.Id);
var categories = marketproduct.Categories
?? Enumerable.Empty<MarketCategory>();
foreach (var category in categories)
{
if (!dbProd.Categories.Any(c => c.Id == category.Id))
{
// means: category is new
context.MarketCategories.Attach(category);
dbProd.Categories.Add(category);
}
}
foreach (var category in dbProd.Categories.ToList())
{
if (!categories.Any(c => c.Id == category.Id))
// means: category has been removed
dbProd.Categories.Remove(category);
}
context.Entry(dbProd).CurrentValues.SetValues(marketproduct);
// context.SaveChanges() somewhere
}
I believe you could just do this:
var dbProd = context.MarketProducts.Find(marketproduct.Id);
dbProd.Categories = dbProd.Categories
.Union(marketproduct.Categories).ToList();
context.SaveChanges();
The Union() call will keep any existing products, add new ones, and update ones that overlap. Since your navigation property Categories is probably defined as an ICollection<Category> you have to use the ToList() extension method during assignment.

Categories

Resources