I am trying to remove an item in my gcNumber but it is not getting removed. Below is my code. i know i am doing some silly thing but don't know where :(
var gcn=gcNumber.ToList();
foreach (var selectGc in gcn)
{
var countToRemove = _uow.GetRepository<TripSheetGcDetail>().GetAll().Where(x => x.FkGcId == selectGc.Id && x.IsActive == true).Select(y => y);
if(countToRemove .Count()>0)
{
gcNumber.ToList().Remove(selectGc);
}
else
{
}
}
return gcNumber.ToList();
if my CountToRemove.count()>0 then i want to remove that item in my gcNumber list. Kindly help where i am doing wrong.
gcNumber.ToList().Remove(selectGc);
This line creates a new list, which you remove stuff from, then since you don't do anything else (like assign the list any where) throws the modified list away.
I'm guessing what you want to do instead is something like:
gcn.Remove(selectGc);
You also want to modify your foreach so that it isn't looping over something that is getting modified.
foreach(var selectGg in gcNumber)
This will loop over the original thing, allowing you to modify the copy.
And you'll probably want to return gcn, as your return statement just creates another new list based on gcNumber which hasn't been modified.
In summary: .ToList() creates a new list every time, so modifying that list won't do anything to the original.
instead of gcNumber.ToList().Remove(selectGc); just do gcNumber.Remove(selectGc);
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public class MyClass
{
public string Name {get; set;}
}
public static void Main()
{
var list = new List<MyClass>();
list.Add(new MyClass() {Name = "aaa"});
list.Add(new MyClass() {Name = "bbb"});
list.Add(new MyClass() {Name = "ccc"});
list.Add(new MyClass() {Name = "ddd"});
var indexesToRemove = new List<int>();
foreach(var item in list)
{
if(item.Name == "aaa")
indexesToRemove.Add(list.IndexOf(item));
}
foreach (var num in indexesToRemove)
list.RemoveAt(num);
Console.WriteLine(list.First().Name);
}
}
Maby it is not the best way to remove items from list but it's clear. You can't remove items form list which is enumerating.
Related
Currently I am doing like this:
For Example:
public update(Person model)
{
// Here model is model return from form on post
var oldobj = db.Person.where(x=>x.ID = model.ID).SingleOrDefault();
db.Entry(oldobj).CurrentValues.SetValues(model);
}
It works, but for example,
I have 50 columns in my table but I displayed only 25 fields in my form (I need to partially update my table, with remaining 25 column retain same old value)
I know it can be achieve by "mapping columns one by one" or by creating "hidden fields for those remaining 25 columns".
Just wondering is there any elegant way to do this with less effort and optimal performance?
This is a very good question. By default I have found that as long as change tracking is enabled (it is by default unless you turn it off), Entity Framework will do a good job of applying to the database only what you ask it to change.
So if you only change 1 field against the object and then call SaveChanges(), EF will only update that 1 field when you call SaveChanges().
The problem here is that when you map a view model into an entity object, all of the values get overwritten. Here is my way of handling this:
In this example, you have a single entity called Person:
Person
======
Id - int
FirstName - varchar
Surname - varchar
Dob - smalldatetime
Now let's say we want to create a view model which will only update Dob, and leave all other fields exactly how they are, here is how I do that.
First, create a view model:
public class PersonDobVm
{
public int Id { get; set; }
public DateTime Dob { get; set; }
public void MapToModel(Person p)
{
p.Dob = Dob;
}
}
Now write the code roughly as follows (you'll have to alter it to match your context name etc):
DataContext db = new DataContext();
Person p = db.People.FirstOrDefault();
// you would have this posted in, but we are creating it here just for illustration
var vm = new PersonDobVm
{
Id = p.Id, // the Id you want to update
Dob = new DateTime(2015, 1, 1) // the new DOB for that row
};
vm.MapToModel(p);
db.SaveChanges();
The MapToModel method could be even more complicated and do all kinds of additional checks before assigning the view model fields to the entity object.
Anyway, the result when SaveChanges is called is the following SQL:
exec sp_executesql N'UPDATE [dbo].[Person]
SET [Dob] = #0
WHERE ([Id] = #1)
',N'#0 datetime2(7),#1 int',#0='2015-01-01 00:00:00',#1=1
So you can clearly see, Entity Framework has not attempted to update any other fields - just the Dob field.
I know in your example you want to avoid coding each assignment by hand, but I think this is the best way. You tuck it all away in your VM so it does not litter your main code, and this way you can cater for specific needs (i.e. composite types in there, data validation, etc). The other option is to use an AutoMapper, but I do not think they are safe. If you use an AutoMapper and spelt "Dob" as "Doob" in your VM, it would not map "Doob" to "Dob", nor would it tell you about it! It would fail silently, the user would think everything was ok, but the change would not be saved.
Whereas if you spelt "Dob" as "Doob" in your VM, the compiler will alert you that the MapToModel() is referencing "Dob" but you only have a property in your VM called "Doob".
I hope this helps you.
I swear by EntityFramework.Extended. Nuget Link
It lets you write:
db.Person
.Where(x => x.ID == model.ID)
.Update(p => new Person()
{
Name = newName,
EditCount = p.EditCount+1
});
Which is very clearly translated into SQL.
Please try this way
public update(Person model)
{
// Here model is model return from form on post
var oldobj = db.Person.where(x=>x.ID = model.ID).SingleOrDefault();
// Newly Inserted Code
var UpdatedObj = (Person) Entity.CheckUpdateObject(oldobj, model);
db.Entry(oldobj).CurrentValues.SetValues(UpdatedObj);
}
public static object CheckUpdateObject(object originalObj, object updateObj)
{
foreach (var property in updateObj.GetType().GetProperties())
{
if (property.GetValue(updateObj, null) == null)
{
property.SetValue(updateObj,originalObj.GetType().GetProperty(property.Name)
.GetValue(originalObj, null));
}
}
return updateObj;
}
I have solved my Issue by using FormCollection to list out used element in form, and only change those columns in database.
I have provided my code sample below; Great if it can help someone else
// Here
// collection = FormCollection from Post
// model = View Model for Person
var result = db.Person.Where(x => x.ID == model.ID).SingleOrDefault();
if (result != null)
{
List<string> formcollist = new List<string>();
foreach (var key in collection.ToArray<string>())
{
// Here apply your filter code to remove system properties if any
formcollist.Add(key);
}
foreach (var prop in result.GetType().GetProperties())
{
if( formcollist.Contains(prop.Name))
{
prop.SetValue(result, model.GetType().GetProperty(prop.Name).GetValue(model, null));
}
}
db.SaveChanges();
}
I still didn't find a nice solution for my problem, so I created a work around. When loading the Entity, I directly make a copy of it and name it entityInit. When saving the Entity, I compare the both to see, what really was changed. All the unchanged Properties, I set to unchanged and fill them with the Database-Values. This was necessary for my Entities without Tracking:
// load entity without tracking
var entityWithoutTracking = Context.Person.AsNoTracking().FirstOrDefault(x => x.ID == _entity.ID);
var entityInit = CopyEntity(entityWithoutTracking);
// do business logic and change entity
entityWithoutTracking.surname = newValue;
// for saving, find entity in context
var entity = Context.Person.FirstOrDefault(x => x.ID == _entity.ID);
var entry = Context.Entry(entity);
entry.CurrentValues.SetValues(entityWithoutTracking);
entry.State = EntityState.Modified;
// get List of all changed properties (in my case these are all existing properties, including those which shouldn't have changed)
var changedPropertiesList = entry.CurrentValues.PropertyNames.Where(x => entry.Property(x).IsModified).ToList();
foreach (var checkProperty in changedPropertiesList)
{
try
{
var p1 = entityWithoutTracking.GetType().GetProperty(checkProperty).GetValue(entityWithoutTracking);
var p2 = entityInit.GetType().GetProperty(checkProperty).GetValue(entityInit);
if ((p1 == null && p2 == null) || p1.Equals(p2))
{
entry.Property(checkProperty).CurrentValue = entry.Property(checkProperty).OriginalValue; // restore DB-Value
entry.Property(checkProperty).IsModified = false; // throws Exception for Primary Keys
}
} catch(Exception) { }
}
Context.SaveChanges(); // only surname will be updated
This is way I did it, assuming the new object has more columns to update that the one we want to keep.
if (theClass.ClassId == 0)
{
theClass.CreatedOn = DateTime.Now;
context.theClasses.Add(theClass);
}
else {
var currentClass = context.theClasses.Where(c => c.ClassId == theClass.ClassId)
.Select(c => new TheClasses {
CreatedOn = c.CreatedOn
// Add here others fields you want to keep as the original record
}).FirstOrDefault();
theClass.CreatedOn = currentClass.CreatedOn;
// The new class will replace the current, all fields
context.theClasses.Add(theClass);
context.Entry(theClass).State = EntityState.Modified;
}
context.SaveChanges();
In EF you can do like this
var result = db.Person.Where(x => x.ID == model.ID).FirstOrDefault();
if(result != null){
result.Name = newName;
result.DOB = newDOB;
db.Person.Update(result);
}
Or you can use
using (var db= new MyDbContext())
{
var result= db.Person.Where(x => x.ID == model.ID).FirstOrDefault();
result.Name= newName;
result.DOB = newDOB;
db.Update(result);
db.SaveChanges();
}
For more detail please EntityFramework Core - Update Only One Field
No Worry guys
Just write raw sql query
db.Database.ExecuteSqlCommand("Update Person set Name='"+_entity.Name+"' where Id = " + _entity.ID + "");
I have created this loop in MVC:
//this identify my user
string tmpUser = System.Web.HttpContext.Current.User.Identity.Name;
//this find user in database and compare his username with Identity name and returns userID
using (var dbUs = new userDbEntities())
{
var whoisloged = (from user in dbUs.UsersTables
where user.username == tmpUser
select user.userID).FirstOrDefault();
//get all destinations for user userid
var list1 = dbUs.CustomerTables.Where(m => m.UserId == whoisloged).Select(m => m.Customer);
var list2 = dbUs.CustomTypes.Where(m => list1.Contains(m.Id_NewCustomerType)).Select(m => m.CustomerType);
//this is LOOP that must return my values
foreach (var customer in list2)
{
string test = customer;
return new SolrQuery(test);
}
Now Problem is in my LOOP foreach... Why is returning only first value? no matter that I have more data in the database.
My result sholud be something like this:
e.g. user Somebody login in app. He/She have in database saved his/her roles (CustomerTable in code) that are e.g. A, B and C, so loop should return me something like this:
return new SolrQuery(A) + return new SolrQuery(B) + return new SolrQuery(C); // + is refer as AND
Realy thanks for help and any ideas...
The first return leaves not only the foreach, but the whole function (as return is intended to do). If you want to do more than one query in the loop, you have to collect the results and return them afterwards...
string result ="";
foreach (var customer in list2)
{
result = result + new SolrQuery(customer);
}
return result;
should do the trick.
The trouble is that:-
return new SolrQuery(test);
returns a single SolrQuery and then exits the function breaking out of your loop.
What you probably want to do is modify your method signature:-
public SolrQuery MyMethod(...)
to:-
public IEnumerable<SolrQuery> MyMethod(...)
to indicate that you want the method to return a sequence of items, rather than a single one.
Then you can use the yield keyword to create the sequence:-
foreach (var customer in list2)
{
yield return new SolrQuery(customer);
}
Or, better, you can just return the result of your LINQ query (which is already a sequence). Replace:-
var list2 = dbUs.CustomTypes.Where(m => list1.Contains(m.Id_NewCustomerType))
.Select(m => m.CustomerType);
with:-
return dbUs.CustomTypes.Where(x => list1.Contains(x.Id_NewCustomerType))
.Select(x => new SolrQuery(x.CustomerType))
.ToList();
and then remove everything after.
I have solve it:
List<string> result = new List<string>();
foreach (var customer in seznam2)
{
result.Add(customer);
}
SolrQueryInList queryInList = new SolrQueryInList("destination", result);
return queryInList;
I've look at some of the answers to similar questions and they don't really seem to fit mine.
I'm trying to incorporate a pattern from Entity Framework: DbContext(page 90) and it doesn't seem to work. The code that I'm using is given below:
[HttpPost]
public ActionResult Edit(Order order)
{
if (ModelState.IsValid)
{
db.Orders.Add(order);
db.Entry(order).State = EntityState.Modified;
foreach (var orderDetail in order.OrderDetails)
{
if (orderDetail.OrderId == 0)
{
db.Entry(orderDetail).State = EntityState.Added;
}
else
{
db.Entry(orderDetail).State = EntityState.Modified;
}
// The example order that I'm updating has two child entities
// so this orderId will be for the third, added one.
int addedOrderDetailId = order.OrderDetails[2].OrderId;
}
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CustomerId = new SelectList(db.Customers, "CustomerId", "CompanyName", order.CustomerId);
return View(order);
}
I've been running an example where the Order object has two existing OrderDetail objects and I'm attempting to add a third. I included the addedOrderDetailId variable, so that I could add it to the 'Watch' and see when it changed
What I've found is happening is that the OrderId of the added OrderDetail object (which is 0 when the foreach loop is entered) is being updated by entity framework to the OrderId of the Order object. This is happening at after the first iteration through the foreach loop (when the first child entity is having its state changed to modified. This means that all three children are being marked as modified. This is causing SaveChanges() to try to update an entry into the database that doesn't exist.
If anyone else has had this problem, then I would be greatful for any advice as to get around this. I will also have to deal with existing child objects being deleted, but I haven't got around to this yet, so if anyone knows of a pattern for this, that would also be appreciated.
Edit:
After taking Slauma's advice and removing db.Orders.Add(order). I was able to move the call to db.Entry(order).State underneath the foreach loop. This allowed me to loop through the loop and set the state of each OrderDetail object to modified for the existing ones and added for the added one. I then simply had to assign the OrderId of the parent to the OrderId of the child and the update was successful. I've also included the code that I've used to delete child objects during the edit. I'm not sure how efficient this is, but it works. Here is the revised code:
[HttpPost]
public ActionResult Edit(Order order)
{
if (ModelState.IsValid)
{
List<int> previousProductIds = db.OrderDetails
.Where(ep => ep.OrderId == order.OrderId)
.Select(ep => ep.ProductId)
.ToList();
List<int> currentProductIds = order.OrderDetails
.Select(o => o.ProductId)
.ToList();
List<int> deletedProductIds = previousProductIds
.Except(currentProductIds).ToList();
foreach (var deletedProductId in deletedProductIds)
{
OrderDetail deletedOrderDetail = db.OrderDetails
.Where(od => od.OrderId == order.OrderId && od.ProductId == deletedProductId)
.Single();
db.Entry(deletedOrderDetail).State = EntityState.Deleted;
}
foreach (var orderDetail in order.OrderDetails)
{
if (orderDetail.OrderId == 0)
{
db.Entry(orderDetail).State = EntityState.Added;
orderDetail.OrderId = order.OrderId;
}
else
{
db.Entry(orderDetail).State = EntityState.Modified;
}
}
db.Entry(order).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CustomerId = new SelectList(db.Customers, "CustomerId", "CompanyName", order.CustomerId);
return View(order);
}
Remove this line from your code:
db.Orders.Add(order);
This will actually put the order including all orderDetails into Added state. Relationship fixup (which happens automatically in Add) will set the OrderId of all OrderDetails to the key of the order. When you enter the loop orderDetail.OrderId is != 0 for all detail items and you always enter the branch which sets the state to Modified. No orderDetail item is in Added state anymore when the loop is finished.
I have an action
[HttpPost]
public string Edit(Member member)
and Member has a collection of children entities ICollection<AgeBracket> AgeBrackets.
Currently I do retrieve all AgeBrackets associated with the member, mark everyone as deleted, then loop through new collection and create a new entry for each. Then I update my parent entity. It works, but there should be a better way to do it:
for example, if I would wrote SQL, I could delete all existing children with just one line
DELETE FROM AgeBrackets WHERE MemberId = #MemberId
In my situation it makes a select to retrieve existing items, then generate delete for each of them, then generate insert for each new child and then it generates update for parent.
Here is how my code looks now:
IList<AgeBracket> ageBrackets = db.AgeBrackets.Where<AgeBracket>(x => x.MemberId == member.MemberId).ToList();
foreach (AgeBracket ab in ageBrackets)
db.Entry(ab).State = EntityState.Deleted;
if (member.AgeBrackets != null)
foreach (AgeBracket ab in member.AgeBrackets)
{
ab.MemberId = member.MemberId;
db.AgeBrackets.Add(ab);
}
db.Entry(member).State = EntityState.Modified;
Initially I was trying to query existing children and compare each of them to new set, but it seems to be over-complicated.
What is the best way to update member and all it's children?
There's another way to do
var originalAgeBrackets = db.AgeBrackets.Where(x => x.MemberId == member.MemberId).ToArray();
var currentAgeBrackets = member.AgeBrackets;
foreach (var original in originalAgeBrackets) {
// check if the original age brackets were modified ou should be removed
var current = currentAgeBrackets.FirstOrDefault(c => c.AgeBracketId == original.AgeBracketId);
if(current != null) {
var entry = db.Entry(original);
entry.OriginalValues.SetValues(original);
entry.CurrentValues.SetValues(current);
} else {
db.Entry(original).State = EntityState.Deleted;
}
}
// add all age brackets not listed in originalAgeBrackets
foreach (var current in currentAgeBrackets.Where(c => !originalAgeBrackets.Select(o => o.AgeBracketId).Contains(c.AgeBracketId))) {
db.AgeBrackets.Add(current);
}
db.SaveChanges();
Unfortunately what you want to do haven't native support to EF Code First. What will help you would be EntityFramework.Extended. This will allow you to do something like:
db.AgeBrackets.Delete(a => a.MemberId == member.MemberId);
You should take care of change-tracks by yourself.
Hope it helps you.
I parse an xml results from a webservice using linq :
XElement items = XElement.Parse(e.Result);
MyListBox.ItemsSource = from item in items.Descendants("node")
select new MyViewModel
{
...
};
This automatically populate my ListBox. But the problem is, I usually access my ObservableCollection like this :
App.MyViewModel.MyItems;
having in my xaml :
ItemsSource="{Binding MyItems,}"
How can I modify directly my ObservableCollection ? I read Cast LINQ result to ObservableCollection
and tried this :
var v = from item in items.Descendants("node")
select new MyViewModel
{
...
};
OApp.MyViewModel.MyItems = new ObservableCollection<MyViewModel>(v);
But I can't since this in WP7 (Silverlight 3), and there is no constructor like this
Thanks !
I'd just invent a static method like this:-
public static ObservableCollection<T> CreateObservableCollect<T>(IEnumerable<T> range)
{
var result = new ObservableCollection<T>();
foreach (T item in range)
{
result.Add(item);
}
return result;
}
Now your last line of code becomes:-
OApp.MyViewModel.MyItems = new CreateObservableCollection<MyViewModel>(v);
The constructor you're trying to use is in Silverlight, just not available on the phone. (as per MSDN)
Unfortunately, you'll have to populate your ObservableCollection yourself.
Do you need ObservableCollection? Do you need add or delete objects from collection or just update?
If only update, you can change MyViewModel.MyItems to:
public MyTypeOfCollection MyItems
{
get { return _myItems; }
set
{
_myItems = value;
OnNotifyPropertyChanged("MyItems");//invoke INotifyPropertyChanged.PropertyChanged
}
}
If you need adding or deleting of items, you can extend your collection to:
public static class Extend
{
// Extend ObservableCollection<T> Class
public static void AddRange(this System.Collections.ObjectModel.ObservableCollection o, T[] items)
{
foreach (var item in items)
{
o.Add(item);
}
}
}