C# Remove object from list stored in an ASP session - linq

I am making a small eBook Store as a project. I am storing the cart in the ASP session as a list of objects. Now, in the checkout page, I am showing that list of objects in a list box and allowing the user to delete an item if needed. This is my code
protected void btnCart_Click(object sender, EventArgs e)
{
List<Title> cartItems = (List<Title>)Session["eStoreCart"];
int itemToRemove = Int32.Parse(lbCartItems.SelectedItem.Value);
Title ttl = ebs.Titles.SingleOrDefault(t => t.TitleId == itemToRemove);
cartItems.Remove(ttl);
Session["eStoreCart"] = cartItems;
FillListBox();
}
Apparently, the number of items in cartItems are same before and after the Remove() method is called. Where am I going wrong?
A similar method was used in Add to Card with cartItems.Add(ttl), which is working flawlessly.

Instead of
Title ttl = ebs.Titles.SingleOrDefault(t => t.TitleId == itemToRemove);
Try
Title ttl = cartItems.SingleOrDefault(t => t.TitleId == itemToRemove);
i.e. instead of searching for the Title in 'ebs' (not sure what it contains, as not clear in OP code), search for items in Session Object directly and then remove it.

The .Remove() method is going to check for equality when trying to remove the item. Does Title implement IEquatable<Title>? If not then the check for equality is going to be default, which for objects is reference equality. And it's unlikely that reference equality is being satisfied here.
Implementing IEquatable<Title> is probably the ideal approach here. Just add that interface to the Title implementation and implement its one method:
public bool Equals(Title other)
{
if (other == null)
return false;
if (this.SomeValue == other.SomeValue)
return true;
else
return false;
}
This would put the equality logic on the model where it belongs. Failing that, your code would have to be more procedural in checking for equality. That is, you'd first have to find the element in cartItems that you're looking for and then remove that object, rather than trying to remove an object which itself exists in ebs.Titles. Something like:
cartItems.Remove(cartItems.Single(c => c.SomeValue == ttl.SomeValue));
That way the code is referencing the same in-memory object, not just an object that intuitively represents the same thing.

Related

Linq compared to IComparer

I have seen this class that looks like this:
/// <summary>
/// Provides an internal structure to sort the query parameter
/// </summary>
protected class QueryParameter
{
public QueryParameter(string name, string value)
{
Name = name;
Value = value;
}
public string Name { get; private set; }
public string Value { get; private set; }
}
/// <summary>
/// Comparer class used to perform the sorting of the query parameters
/// </summary>
protected class QueryParameterComparer : IComparer<QueryParameter>
{
public int Compare(QueryParameter x, QueryParameter y)
{
return x.Name == y.Name
? string.Compare(x.Value, y.Value)
: string.Compare(x.Name, y.Name);
}
}
Then there is a call later in the code that does the sort:
parameters.Sort(new QueryParameterComparer());
which all works fine.
I decided that it was a waste of time creating a QueryParameter class that only had name value and it would probably be better to use Dictionary. With the dictionary, rather than use the Sort(new QueryParameterComparer()); I figured I could just do this:
parameters.ToList().Sort((x, y) => x.Key == y.Key ? string.Compare(x.Value, y.Value) : string.Compare(x.Key, y.Key));
The code compiles fine, but I am unsure whether it is working because the list just seems to output in the same order it was put in.
So, can anyone tell me if I am doing this correctly or if I am missing something simple?
Cheers
/r3plica
The List<T>.Sort method is not part of LINQ.
You can use OrderBy/ThenBy extension methods before calling ToList():
parameters = parameter.OrderBy(x => x.Key).ThenBy(x => x.Value).ToList();
From your code, I surmise that parameters is your dictionary, and you're calling
parameters.ToList().Sort(...);
and then carrying on using parameters.
ToList() creates a new list; you are then sorting this list and discarding it. You're not sorting parameters at all, and in fact you can't sort it because it's a dictionary.
What you need is something along the lines of
var parametersList = parameters.ToList();
parametersList.Sort(...);
where ... is the same sort as before.
You could also do
var parametersList = parameters.OrderBy(...).ToList();
which is a more LINQ-y way of doing things.
It may even be appropriate to just do e.g.
foreach(var kvp in parameters.OrderBy(...))
(or however you plan on using the sorted sequence) if you're using the sorted seqence more often than you're changing the dictionary (i.e. there's no point caching a sorted version because the original data changes a lot).
Another point to note - a dictionary can't contain duplicate keys, so there's no point checking x.Key == y.Key any more - you just need to sort via (x, y) => string.Compare(x.Key, y.Key)
I'd be careful here, though - by the look of it, the original code did support duplicate keys, so by switchnig to a dictionary you might be breaking something.
Dictionary are only equivalent to two hash map, and allow you to access to any alement (given the key) with costant time O(1) (because the make a lookup search on an hashtable).
So if you would order the elements because you intended to do a dicotomic search later, you do not need that you should use directly dictionary (or if you would query for both the value in dictionary you could use a couple of dictionary with the same elements but switching key value pairs).
As somebody write before me, if you question is how to order a list with linq you should work with linq and with orderby thenby.

Changing values of an object in a LINQ-statement

I want to add some calculated properties to an EntityObject without loosing the possibility of querying it agains the database.
I created a partial class and added the fields I need in the object. Than I wrote a static function "AttachProperties" that should somehow add some calculated values. I cannot do this on clientside, since several other functions attach some filter-conditions to the query.
The functions should look like this:
return query.Select(o =>
{
o.HasCalculatedProperties = true;
o.Value = 2;
return o;
});
In my case the calculated value depends on several lookups and is not just a simple "2". This sample works with an IEnumerable but, of course, not with an IQueryable
I first created a new class with the EntityObject as property and added the other necessary fields but now I need this extended class to be of the same basetype.
First, in my opinion changing objects in a Select() is a bad idea, because it makes something else happen (state change) than the method name suggests (projection), which is always a recipe for trouble. Linq is rooted in a functional programming (stateless) paradigm, so this kind of usage is just not expected.
But you can extend your class with methods that return a calculation result, like:
partial class EntityObject
{
public int GetValue()
{
return this.MappedProp1 * this.MappedProp2;
}
}
It is a bit hard to tell from your question whether this will work for you. If generating a calculated value involves more than a simple calculation from an object's own properties it may be better to leave your entities alone and create a services that return calculation results from an object graph.
Try something like this:
return from o in collection
select new O()
{
OtherProperty = o.OtherProperty,
HasCalculatedProperties = true,
Value = 2
};
This will create a copy of the original object with the changes you require and avoid all the messiness that come with modifying an entity in a select clause.

Handling parameters from dynamic form for one-to-many relationships in grails

My main question here is dealing with the pramas map when having a one-to-many relationship managed within one dynamic form, as well as best practices for dealing with one-to-many when editing/updating a domain object through the dynamic form. The inputs for my questions are as follows.
I have managed to hack away a form that allows me to create the domain objects shown below in one Dynamic form, since there is no point in having a separate form for creating phone numbers and then assigning them to a contact, it makes sense to just create everything in one form in my application. I managed to implement something similar to what I have asked in my Previous Question (thanks for the people who helped out)
class Contact{
String firstName
String lastName
// ....
// some other properties
// ...
static hasMany = [phones:Phone]
static mapping = {
phones sort:"index", cascade: "all-delete-orphan"
}
}
class Phone{
int index
String number
String type
Contact contact
static belongsTo = [contact:Contact]
}
I basically managed to get the values from the 'params' map and parse them on my own and create the domain object and association manually. I.e. i did not use the same logic that is used in the default scaffolding, i.e.
Contact c = new Contact(params)
etc...., i just looped through all the params and hand crafted my domain objects and saved them and everything works out fine.
My controller has code blocks that look like this (this is stripped down, just to show a point)
//create the contact by handpicking params values
def cntct = new Contact()
cntct.firstName = params.firstName
cntct.lastName = params.lastName
//etc...
//get array of values for number,type
def numbers = params['phone.number']
def types = params['phone.type']
//loop through one of the arrays and create the phones
numbers.eachWithIndex(){ num, i ->
//create the phone domain object from
def phone = new Phone()
phone.number = num
phone.type = types[i]
phone.index = i
cntct.addToPhones(phone)
}
//save
My questions are as follows:
What is the best practice of handeling such a situation, would using Command objects work in this case, if yes where can i found more info about this, all the examples I have found during my search deal with one-to-one relationships, I couldn't find an example for one-to-many?
What is the best way to deal with the relatiohsips of the phones in this case, in terms of add/removing phones when editing the contact object. I mean the creation logic is simple since I have to always create new phones on save, but when dealing with updating a contact, the user might have removed a phone and/or editing an exiting one and/or added some new phones. Right now what I do is just delete all the phones a contact has and re-create them according to what was posted by the form, but I feel that's not the best way to do it, I also don't think looping over the existing ones and comparing with the posted values and doing a manual diff is the best way to do it either, is there a best practice on how to deal with this?
Thanks, hopefully the questions are clear.
[edit] Just for more information, phone information can be added and deleted dynamically using javascript (jquery) within the form [/edit]
disclaimer: i do not know if the following approach works when using grails. Let me know later.
See better way for dynamic forms. The author says:
To add LineItems I have some js that calculates the new index and adds that to the DOM. When deleting a LineItem i have to renumber all the indexes and it is what i would like to avoid
So what i do
I have a variable which stores the next index
var nextIndex = 0;
When the page is loaded, i perform a JavaScript function which calculates how many child The collection has and configure nextIndex variable. You can use JQuery or YUI, feel free.
Adding a child statically
I create a variable which store the template (Notice {index})
var child = "<div>"
+= "<div>"
+= "<label>Name</label>"
+= "<input type="text" name=\"childList[{index}].name\"/>"
+= "</div>"
+= "</div>"
When the user click on the Add child button, i replace {index} - by using regex - by the value stored in the nextIndex variable and increment by one. Then i add to the DOM
See also Add and Remove HTML elements dynamically with Javascript
Adding a child dinamically
Here you can see The Paolo Bergantino solution
By removing
But i think it is the issue grow up when deleting. No matter how many child you remove, does not touch on the nextIndex variable. See here
/**
* var nextIndex = 3;
*/
<input type="text" name="childList[0].name"/>
<input type="text" name="childList[1].name"/> // It will be removed
<input type="text" name="childList[2].name"/>
Suppose i remove childList1 What i do ??? Should i renumber all the indexes ???
On the server side i use AutoPopulatingList. Because childList1 has been removed, AutoPopulatingList handles it as null. So on the initialization i do
List<Child> childList = new AutoPopulatingList(new ElementFactory() {
public Object createElement(int index) throws ElementInstantiationException {
/**
* remove any null value added
*/
childList.removeAll(Collections.singletonList(null));
return new Child();
}
});
This way, my collection just contains two child (without any null value) and i do not need to renumber all the indexes on the client side
About adding/removing you can see this link where i show a scenario wich can gives you some insight.
See also Grails UI plugin
Thanks,
Your answer brought some insight for me to do a wider search and I actually found a great post that covers all the inputs in my question. This is just a reference for anyone reading this. I will write a blog entry on how I implemented my case soon, but this link should provide a good source of ino with a working exmaple.
http://www.2paths.com/2009/10/01/one-to-many-relationships-in-grails-forms/
Most of the time I use ajax to manage such problem.
So when the user clicks add new phone I get the template UI from the server for manageability purpose ( the UI just same GSP template that I use to edit, update the phone), so this way you are not mixing your UI with your js code, whenever you want to change the UI you have to deal only with our GSP code.
Then after getting the UI I add it to the page using jquery DOM manipulation. Then after filling the form when they hit add(save) the request is sent to the server via ajax and is persisted immediately.
When the user clicks edit phone the same UI template is loaded from the server filled with existing phone data, then clicking update will update the corresponding phone immediately via ajax, and same thing applies to delete operation.
But one day I got an additional scenario for the use case that says, "until I say save contact no phone shall be saved on the backend, also after adding phones to the contact on the ui if navigate away to another page and come back later to the contact page the phones I added before must be still there." ugh..
To do this I started using the Session, so the above operations I explained will act on the phone list object I stored on the session instead of the DB. This is simple perform all the operation on the phonesInSession but finally dont forget to do this(delete update):
phonesToBeDeleted = phonesInDB - phonesInSession
phonesToBeDeleted.each{
contact.removeFromPhones(it)
it.delete()
}
I know I dont have to put a lot of data in session but this is the only solution I got for my scenario.
If someone has got similar problem/solution please leave a comment.
First, in all your input fields names you add an #:
<input type="text" name="references[#].name"/>
Second, add call a function before submitting:
<g:form action="save" onsubmit="replaceAllWildCardsWithConsecutiveNumbers();">
Third, this is the code for the function that you call before submitting the form:
function replaceAllWildCardsWithConsecutiveNumbers(){
var inputs = $('form').find("[name*='#']");
var names = $.map(inputs, function(el) { return el.name });
var uniqueNames = unique(names);
for (index in uniqueNames) {
var uniqueName = uniqueNames[index];
replaceWildCardsWithConsecutiveNumbers("input", uniqueName);
replaceWildCardsWithConsecutiveNumbers("select", uniqueName);
}
}
function unique(array){
return array.filter(function(el, index, arr) {
return index === arr.indexOf(el);
});
}
function replaceWildCardsWithConsecutiveNumbers(inputName, name){
counter = 0;
$(inputName + "[name='" + name + "']").each(function (i, el) {
var curName = $(this).attr('name');
var newName = curName.replace("#", counter);
$(this).attr('name', newName);
counter += 1;
});
}
Basically, what the code for replaceAllWildCardsWithConsecutiveNumbers() does, is to create a list for all input (or select) elements whose name contains an #. Removes the duplicates. And then iterates over them replacing the # with a number.
This works great if you have a table and you are submitting the values to a command object's list when creating a domain class for the first time. If you are updating I guess you'll have to change the value of counter to something higher.
I hope this helps someone else since I was stuck on this issue for a while myself.

ADO.NET Data Services, LINQ

I have C# code to populate a dropdown list in Silverlight which works fine except when there are duplicates. I think because IEnumerable<Insurance.Claims> is a collection, it filters out duplicates. How would I code my LINQ query to accept duplicates?
My Sample Data looks like:
Code => CodeName
FGI Field General Initiative
SRI Static Resource Initiative
JFI Joint Field Initiative - This is "overwritten" in results
JFI Joint Friend Initiative
IEnumerable<Insurance.Claims> results;
// ADO.NET Data Service
var claim = (from c in DataEntities.Claims.Expand("Claimants").Expand("Policies")
where c.Claim_Number == claimNumber
select c);
DataServiceQuery<Insurance.Claims> dataServiceQuery =
claim as DataServiceQuery<Insurance.Claims>;
dataServiceQuery.BeginExecute((asyncResult) =>
{
results = dataServiceQuery.EndExecute(asyncResult);
if (results == null)
{
// Error
}
else
{
// Code to populate Silverlight form
}
});
(Not sure if you're still struggling with this but anyway...)
I'm pretty sure it's not the IEnumerable interface but the actual drop down that is causing this behaviour. The code is being used as the key, and so obviously each time the same code is encountered, the item is being overwritten.
I don't think you can override this unless you change the code, or use another identifier as the key field in the dropdown.
You may want to add a try-catch block around dataServiceQuery.EndExecute(asyncResult) to properly handle errors.

DataSource containing a null value makes ComboBox fail

I've thrown myself headfirst into C# and .Net 2.0 using Linq, and I'm having a few problems debugging some of the problems, namely the following:
I have a ComboBox control (cmbObjects) I want to populate with a set of objects retrieved using Linq. I've written a helper method to populate a List<T> generic:
class ObjectProvider
{
public static List<T> Get<T>(bool includeNull) where T : class, new()
{
List<T> list = new List<T>();
LutkeDataClassesDataContext db = ConnectionManager.GetConnection();
IQueryable<T> objects = db.GetTable<T>().AsQueryable();
if (includeNull) list.Add(null);
foreach (T o in objects) list.Add(o);
return list;
}
public static List<T> Get<T>() where T : class, new()
{
return Get<T>(false);
}
}
I verified the results when calling the function with true or false - the List does contain the right values, when passing true, it contains null as the first value, followed by the other objects.
When I assign the DataSource to the ComboBox however, the control simply refuses to display any items, including the null value (not selectable):
cmbObjects.DataSource = ObjectProvider.Get<Car>(true);
Passing in false (or no parameter) does work - it displays all of the objects.
Is there a way for me to specify a "null" value for the first object without resorting to magic number objects (like having a bogus entry in the DB just to designate a N/A value)? Something along the lines of a nullable would be ideal, but I'm kind of lost.
Also, I've tried adding new T() instead of null to the list, but that only resulted in an OutOfMemoryException.
The combo box control has an option to append data bound items to the hard-coded items in the list. So you hard-code your n/a value, and data bind the real values.
Okay, it seems the DataSource becomes invalid if you try to add a null value. The solution was to just add the items via a simple foreach loop with an empty string at the start instead of assigning the List<>.

Resources