I'm creating a shopping basket in ASP.NET using session variables to pass the data from a shopping.aspx page to basket.aspx, currently I have the pages passing the primary key of the product with a gridview on the basket.aspx used to display the data from the database.
However this only works for one item at a time, how can I extended the session variable so multiple products can be added, as well as quantities etc?
You can use your own object, eg. Basket which can have one or more properties.
Object should be market as Serializable.
For example:
[Serializable]
public class Basket
{
public List<BasketItem> Items {get;set;}
public int UserId {get;set;}
}
[Serializable]
public class BasketItem
{
//...
}
You can put (almost) any object into the session, not just strings. So you could use a List<string> for a list of keys, or even a List<Product>.
EDIT
So in the first page you would get
var bookids = new List<string>();
// collect all book IDs into the 'bookids' list
Session["bookIDs"] = bookids;
and in the second page:
var bookids = Session["bookIDs"] as List<string>;
// use all IDs
Related
class Student{
public string Name {get; set;}
public EntityCollection<Info> Infos {get; set;}
}
class Info{
public string Title {get; set;}
public Student Student {get; set;}
}
I have two entities like this. First I will query one student entity
var student = db.Students.FirstOrDefault(s => s.StudentId = 1);
Then I query Info list of this student in a separate query
var infos = from c in db.Info where c.StudentId = 1 and ....
If I loop though infos and add it manual into student.Infos, it will cause insert new row
foreach(info in infos){
student.Infos.Add(info);
}
How to attach list of info into student entity without insert new row into Info table when db.SaveChanges(). Like
student.Infos = infos
EF does the work for you behind the scenes when you use navigation properties. It's not just a data layer to load data singularly but rather it's set up with the relationships between the data and is capable of loading an entire object graph of related data either in one hit (eager loaded) or on-demand (lazy loaded)
Firstly: you can update your Info collections to ICollection<Info> or List<Info>. I opt for List<Info> because I commonly use .AddRange(). Also, mark it as virtual to enable EF proxies and lazy loading.
From there, to access the Infos on a Student you can just use:
var student = db.Students.Include(s => s.Infos).SingleOrDefault(s => s.StudentId = 1);
This will eager-load the Infos for the selected student. No need to load them separately.
If you leave off the .Include(..) then you can still access the Infos (provided the DbContext is still in scope) though this will trigger additional SQL calls to load the Infos. (Lazy loaded)
When loading data to send outside of the scope of the DbContext, such as returned from an API call, or sent to a view, it's recommended to compose a DTO or ViewModel with just the fields that you need from the various entities, then perform a .Select() to populate them, and return the DTOs not the entities. This avoids problems with lazy loading calls after a DbContext has been disposed and unexpected performance issues if lazy loading is triggered due to serialization or the like.
I'm working on a simple project which is based on the popular ContosoUniveristy tutorial. I want to extend some of the functionalities present in this tutorial.
I have created a table named School where I keep each schools properties like address, phone number, courses, students and so on. Later I added a foreignKey property named SchoolID to student, course and few other tables.
I have SchoolIndex page with basic layout view where all the schools are listed and user can click one to go to the details page. This details page has a _DitLayout layout with additional menu on the left where one can find links to appropriate informations e.g. contact, courses, students (like the ones stored in School table). _DitLayout is shared by all the contact, courses and students views.
Here I have a problem. When I click school on the SchoolIndex page I want the links in the menu on the left to point to this particular school properties. To do that I would have to somehow pass SchoolID to the layout page (not a good idea?). The other way is to somehow store the SchoolID when running trough views, controllers and actions. So that in the controller i could write
public class SchoolController : Controller
{
private SchoolContext db = new SchoolContext();
public ActionResult Contact()
{
int ID = //here I pass SchoolID;
// I fetch school from the database
SchoolModel school = db.School.Find(ID);
//and I map the properties to the ViewModel
ContactViewModel contact = new ContactViewModel();
contact.Address = school.Address;
contact.Phone = school.Phone;
//etc.
return View(contact);
}
}
Question is: How can I pass or store SchoolID between controllers? YES I need to pass ID not only between actions but also between controllers.
I thought that maybe i could store this ID in the cookie. Is it a good idea? Is there a better way to do it?
If you want to store data, without keeping it inside the URL (or HTTP request), then you would have to save it either in Session or Cookie.
Personally I would modify the MVC routing to incorporate the school id.
eg: /{schoolId}/{controller}/{action}.
This way schoolId will be available in any action, regardless of the controller.
You can use Session object or TempData to pass data between controllers.
public class SchoolController : Controller
{
private SchoolContext db = new SchoolContext();
public ActionResult Contact()
{
int ID = TempData["SchoolID"];
// I fetch school from the database
SchoolModel school = db.School.Find(ID);
//and I map the properties to the ViewModel
ContactViewModel contact = new ContactViewModel();
contact.Address = school.Address;
contact.Phone = school.Phone;
//etc.
return View(contact);
}
}
public class OtherController : Controller
{
public ActionResult School(int id)
{
TempData["SchoolID"] = id;
return RedirectToAction("/School/Contact");
}
}
I'm having a [Serializable] class with some properties,methods and some web controls.
Using this class i were made a Dictionary<string,object> variable.
This Dictionary variable contains various objects of my class.
Now i need to store this Dictionary variable into view-state so that i can use this Dictionary variable on every post-back of my web form.
When i use this line of code to store my Dictionary variable into view-state
ViewState[this.ClientID + "_CtrAdd"] = dictControl;
It throws error:
Type 'System.Web.UI.WebControls.TextBox' in Assembly 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' is not marked as serializable.
Note:
My class objects contains some web controls.
Can any one tell me how can i store this Dictionary variable into an View-state .
Your exception is realy clear about what to do. You need to store the data inside your dictonary, not the controls. Controls refrence to many objects, all these object whould have to be saved, that is why controls are not serializable. You also want to keep your ViewState as small as possible, the size will have a significant inpact on your performance.
As the error suggests, you can't store certain classes, i.e. those that aren't marked as serializable, in ViewState. This is because ViewState is stored as a BASE64-encoded string in a hidden field on the page, and as such any class that you attempt to store in ViewState must be serializable.
You would have more success building a separate class that just stores data that you need to store in order to have it available in the next postback.
Web controls will store data in view state without you needing to do anything, so perhaps your class can just store the control's ID which you can then use to reference the control later on.
For example:
[Serializable]
class MyCustomData
{
public string TextBoxID1 { get; set; }
public int MyCounter { get; set;}
public decimal MyTotal { get; set; }
}
var data = new MyCustomData { TextBoxID1 = txtMyTextBox.ID, MyCounter = anInt, MyTotal = aDecimal };
ViewState[this.ClientID + "_Data"] = data;
I'm new to ASP.NET MVC and want to create a small order management tool. My database contains the tables Orders and Articles (and a few other ones), and I generated an EF Model from my database, so I can use the full power of the EF mappings (e.g. db.Orders.Articles)
My two main relations which I'm concerned about are Orders and Articles.
An order can have many articles
An article can only belong to one order.
I've created an OrdersController with an Create action to create an order:
//
// GET: /Orders/Create
public ActionResult Create()
{
Order order = new Order()
{
// filling some order columns, e.g. date
};
Article article = new Article()
{
// ... article columns
};
order.Articles.Add(article);
return View(order);
}
//
// POST: /Orders/Create
[HttpPost]
public ActionResult Create(Order order)
{
// i know i should care more about error handling, but now ommit it
db.Orders.AddObject(order);
db.SaveChanges();
return RedirectToAction("index");
}
So I'm directly binding an EF Object to a view (read somewhere not to do that and use a view model instead, but don't really know what that view model should look like)
My view contains the Order form as well as the article form (because i want to create a order and articles at the same time and not seperate). I used these greate EditorFor Methods to do that.
And now to my problem: If i hit the submit button, the app crashes as soon as it comes to the HttpPost Create Method (when mapping the order) with this error message:
Error Message: The EntityCollection
has already been initialized. The
InitializeRelatedCollection method
should only be called to initialize a
new EntityCollection during
deserialization of an object graph.
If i hit continue in VS2010, it will complete saving the order - so my question is how to solve this problem in a reliable way.
Thanks in advance and sorry for that long story :)
I solved my problem now by using a separate ViewModel like #Yakimych advised me. However I did not copy all the attributes from the EF models, instead I just refer to them. My ViewModel looks like this:
public class NewOrderViewModel {
public Order { get; set; }
public List<Article> { get; set; }
}
I am writing a class to save searches on my site. I want to have in the class an "Array" of all the parameters that were specified. I tried a NameValueCollection but the problem I ran into is when I have a multi-select (e.g. states) it only stores one of the entries because the key gets taken. I need a collection type that will let me have something like the following:
Name => Bob
State => Alaska
State => Oregon
State => Washington
Company => Acme
What type of collection should I use?
EDIT: ==============================
I'm not sure the comments so far will help. Let me explain a little further. This search class will be used to save the parameters for any search on my site. Different searches may or may not have the same parameters. When this classes save method is called the search will be dumped into a database. One record will be created in the Searches table and as many records an there are items in the collection will be created in the SearchesParameters table. The SearchesParamaters table has these columns (ID,searches_ID,key,value).
The database could care less if there are two parameters with a key of "State". In order to keep my class generic enough to use on all searches without having to be updated I want to have a collection/array that will let me have key/value pairs and also let me have multiple instances of the same key. Really I just want to be able to call searchObj.addParameter(KEY,VALUE); How the class handles that on the back end is mostly irrelevant so long as i can reliably get the correct keys paired up with the correct values.
Is a collection the way to go with this or should I be considering something like two arrays one storing the keys and one storing the values?
A Dictionary that maps String to an List<string>. Something like Dictionary<string, List<string>>.
If an element isn't there in the Dictionary, create a new List for the Key and add to it. Otherwise, simply add the new Value to the existing List.
Create a class, and store that class in a collection.
class Search
{
public string Name { get; set; }
public List<string> State { get; set; }
public string Company { get; set; }
}
Then you can have multiple states per search. Add instances of this to List and away you to.
what about a generic list (System.Collections.Generic)?
e.g.,
string name;
List<string> states;
string company;
You can read up about generic lists here
You should use a List<KeyValuePair<string, string>>
I would use Dictionary<string, HashSet<string>>.