How to reduce request to my database? - database

i have a partial view with a gridview in it. so when user clicks add button request will redirect to Add method of unitsController. After add it to database I should refetch all data from database. Is there a way to prevent controller from get all database records?
Below is my current controller
public class UnitsController : Controller
{
TList<Units> model=null;
public ActionResult UnitsPartial()
{
if(model==null)
model = database.GetAll();
return PartialView(model);
}
[HttpPost]
public ActionResult Add(Units unit)
{
if (ModelState.IsValid)
{
database.Save(unit);
model.Add(unit);
}
return PartialView("UnitsPartial", model);
}
In the last line I want to use return PartialView("UnitsPartial", model) instead of return database.GetAll() to prevent a database query. But model is null in Add method.
Is my approach correct or not? And why is model is null in add() method?
--UPDATED
first of all control redirect to UnitsPartial() and will fill model object correctly. after press add button, control will redirect to Add(...) method but this time model is equal to null !!!
what is the problem with it? i tried to pass model.Clone() to partial view
return PartialView("UnitsPartial", model.Clone());
but the result is the same

You can't cache values in the controller class like this using member variables. HTTP is stateless and MVC 3 follows that approach. Each individual call to an action method is going to have a brand new instance of Controller class with the model set to null.
So start by calling database.GetAll() in both action methods and then ask the question "How do I make this more efficient".

I don't know if it is the right approach or not, since I do not fully understand what you try to do, but your model is null because you initialize it as null when the controller is created. you should do a model = new TList() before adding something to it....

Related

Spring MVC REST with AngularJS: error handling methods

Spring MVC | Angularjs | Hibernate
I have a very simple web app that list all books from database.
Page looks something like this....
-------------------------------------------
Problem
1. My update method returns not only book object but also other information such as error message, error code...etc. This causes a problem in my view when I update.
-------------------------------------------
Angularjs $resource
Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. This means that in most cases one never has to write a callback function for the action methods.
Now this is actually very convenient as you don't have to re-render new data to the view. But for my case, I really want to return not only the object its self but also other necessary data if when an error occurs.
This is what my update method looks like in my controller
#RequestMapping(path="/booklist/{id}", method = RequestMethod.PUT, produces="application/json")
#ResponseBody
public ResponseBuilder<Book> save(#PathVariable("id") Integer id, #RequestBody #Valid Book book, BindingResult result){
if(result.hasErrors()){
/*...
* Some error process
*/
ResponseBuilder<Book> rrBuilder = new ResponseBuilder.Builder<Book>(book)
.httpStatus(HttpStatus.BAD_REQUEST)
.map(errorMap)
.message(result.getAllErrors().toString())
.build();
return rrBuilder;
}else{
bookDao.saveOrUpdate(book);
ResponseBuilder<Book> rrBuilder = new ResponseBuilder.Builder<Book>(
book)
.httpStatus(HttpStatus.ACCEPTED)
.build();
return rrBuilder;
}
};
Questions
What is a proper way of doing this? I could use ResponseEnitity but this doesn't allow me to pass error codes when needed.
Should I include Error Object with in my Book class?
Or should all Object implements an Error interface?
Look something like this..
#Entity
#Table(name="books")
#Component
public class Book implements Serializable{
#Id
#GeneratedValue
private int id;
#NotBlank
private String name;
/**
* other fields
*/
#Transient
private ErrorHandler errorHandler;
How do you usually handle errors?
thank you...

Invoking cells directly from the controller

I am working with cakephp 3.1.7 and figuring out how to invoke view cells or retrieve cell data from the controller. I implemented basic cells with the help of cakephp docs and also http://josediazgonzalez.com/2014/03/20/view-cells/ document which is working fine. However, when I try to return cells directly from the controller I get the following error.
Error: Call to undefined method App\Controller\ProductsController::decorate()
This is what I have:
use Cake\View\Cell;
use Cake\ORM\TableRegistry;
class ProductupdateCell extends Cell
{
public function display($options = []){
if (!empty($options['displaylist'])) {
$this->set('productlist', $options['displaylist']);
return $this;
}else{
$category = $this->request->query['category'];
$this->loadModel('Products');
$query = $this->Products-> find()
-> where(['Products.category' => $category])
-> hydrate(false);
$productlist = $query->toArray();
$this->set('productlist',$productlist);
return $this;
}
}
}
In my controller,
<?php
class ProductsController extends Controller
{
use CellTrait;
public function view($id)
{
$products = $this->Products->findById($id);
$this->set('displaylist', $this->decorate('ProductupdateCell', $products));
}
}
Please correct me where I am going wrong. Is it efficient to use this to update my product list based on user input with ajax request? Can I selectively update the particular cell rendered in my view page? Is there any other method to update the cell directly. Please forgive me if this is a dumb question.
I am working with cakephp 3.1.7 and figuring out how to invoke view cells or retrieve cell data from the controller.
This is an architecturally wrong. They're supposed to be used from the view level.
If you want to have modular and abstracted controller logic either use the CRUD plugin. Or simply go for components. Components are packages of logic that are shared between controllers.
Error: Call to undefined method App\Controller\ProductsController::decorate()
There is no such method in the Controller, CellTrait nor the View class. I don't know from where you got that code, it's also not in the documentation of the cells.

Calling DAL from ViewModel asynchronously

I am building composite WPF application using MVVM-light. I have Views that have ViewModels injected into them using MEF:
DataContext = App.Container.GetExportedValue<ViewModelBase>(
ViewModelTypes.ContactsPickerViewModel);
In addition, I have ViewModels for each View (Screens and UserControls), where constructor usually looks like this:
private readonly ICouchDataModel _couchModel;
[ImportingConstructor]
public ContactsPickerControlViewModel(ICouchDataModel couchModel)
{
_couchModel = couchModel;
_couchModel.GetContactsListCompleted+=GetContactsListCompleted;
_couchModel.GetConcatcsListAsync("Andy");
}
Currently, I have some performance issues. Everything is just slow.
I have 2 kind of related questions
What is the right way of calling DAL methods asynchronously (that access my couchdb)? await/async? Tasks? Because currently I have to write a lot of wrappers(OnBegin, OnCompletion) around each operation, I have GetAsyncResult method that does some crazy things with ThreadPool.QueueUserWorkItem , Action etc.
I hope there is the more elegant way of calling
Currently, I have some screens in my application and on each screen, there are different custom UserControls, some of them need same data (or slightly changed) from DB.
Questions: what is the right way to share datasource among them? I am mostly viewing data, not editing.
Example: On Screen A: I have Contacts dropdown list user control (UC1), and contact details user control(UC2). In each user control, their ViewModel is calling DAL:
_couchModel.GetConcatcsListAsync("Andy");
And on completion I assign result data to a property:
List<ContactInfo> ContactsList = e.Resuls;
ContactsList is binded to ItemsSource of DropDownListBox in UC1. The same story happens in UC2. So I end up with 2 exactly same calls to DB.
Also If I go to Screen B, where I have UC1, I’ll make another call to DB, when I’ll go to Screen B from Screen A.
What is the right way to making these interaction ? e.g. Getting Data and Binding it to UC.
Thank you.
Ad.1
I think you can simply use Task.Factory to invoke code asynchronously (because of that you can get rid off OnBegin, OnCompletion) or if you need more flexibility, than you can make methods async.
Ad. 2
The nice way (in my opinion) to do it is to create DatabaseService (singleton), which would be injected in a constructor. Inside DatabaseService you can implement some logic to determine whether you want to refresh a collection(call DAL) or return the same (it would be some kind of cache).
Then you can call DatabaseService instead of DAL directly and DatabaseService will decide what to do with this call (get collection from DB or return the same or slightly modified current collection).
Edit:
DatabaseService will simply share a collection of objects between ViewModels.
Maybe the name "DBCacheService" would be more appropriate (you will probably use it only for special tasks as caching collections).
I don't know your architecture, but basically you can put that service in your client application, so the plan would be:
Create DatabaseService.cs
[Export(typeof(IDatabaseService))]
public class DatabaseService : IDatabaseService
{
private List<object> _contacts = new List<object>();
public async Task<List<object>> GetConcatcsList(string name)
{
if (_contacts.Count == 0)
{
//call DAL to get it
//_contacts = await Task.Factory.StartNew(() => dal.GetContactsList(name));
}
else
{
//refresh list if required (there could be some condition)
}
return _contacts;
}
}
Add IDatabaseService to your ViewModel's constructor.
Call IDatabaseService instead of DAL.
If you choose async version of DatabaseService, then you'll need to use await and change your methods to async. You can do it also synchronously and call it (whenever you want it to be asynchronous) like that:
Task.Factory.StartNew(() =>
{
var result = dbService.GetContactsList("Andy");
});
Edit2:
invoking awaitable method inside Task:
Task.Factory.StartNew(async () =>
{
ListOfContacts = await _CouchModel.GetConatcsList ("Andy");
});

Pass a collection to viewmodel and return a selected item

I have a View / ViewModel where a ProductList is loaded. This list is not visible on the screen.
What I need to do is show a new View/ViewModel (e.g. SelectProductView / SelectProductViewModel), pass the ProductList to them, and after a user selects a particular Product, close this view, and make use of selected product.
What is the best way to achieve this?
I am using MVVMLight, but I guess the ideas should not be restricted just to it.
The easiest way is to create a view, and pass collection to it, but that doesn't sound MVVM friendly. I was thinking of creating a SelectProductViewModel from the first ViewModel and pass the collection to it, but I don't know how would I automatically create SelectProductView and bind it to created SelectProductViewModel.
Edit: in my application view structure is a bit complex. I have a main view, which basically needs to host a SelectProductView, since this view must cover whole screen. MainView contains lots of child and grandchild views (through tabs), so there could be 3 different child views or grand childViews that could issue a request for a product to be selected. Also, some view will not have products preloaded, so this task should probably be propagated to a SelectProductViewModel.
Example of Structure:
MainView
/ \
ChildViewA ChildViewB
/ \ / \
GrandChildViewA1 GrandChildViewA2 GrandChildViewB1 GrandChildViewB2
So, GrandChildViewA1, ChildViewB and GrandChildViewB2 could issue a request for a product to be selected. Only the view that issued a request should get the selected product, others should not bother with it. GrandChildViewA1 will have loaded products in it, but GrandChildViewB2 will not have ProductList loaded in it. This means, for performance sake, that GrandChildViewA1 should pass product list to SelectProductViewModel, while GrandCHildViewB2 will not have Product list in it, so SelectProductViewModel should fetch data from database.
I would create a generic viewModel which defines a contract for receiving data.
public abstract class PassDataViewModel<T> : ObservableObject
{
public T Data { get; }
}
I would then create a more general ViewModel for your product list like so:
public class SelectProductViewModel : PassDataViewModel<Product>
{
private Product _selectedProduct;
private ObservableCollection<Product> _products = new ObservableCollection<Product>();
public SelectProductViewModel(IList<Product> products)
{
_selectedProduct = _products.First();
}
public IEnumerable<Product> Products
{
get { return _products; }
}
public Product SelectedProduct
{
get { return _selectedProduct; }
set
{
_selectedProduct = value;
OnPropertyChanged("SelectedProduct");
OnPropertyChanged("Data");
}
}
public Product Data
{
get { return _selectedProduct; }
}
}
You would use this in the following way:
Your first viewModel can create an instance of the SelectProductViewModel (when a command is invoked, for example)
You pass your products list to the new SelectProductViewModel instance.
Use a DataTemplate to change the view on your screen (this post will show you how to do this).
Have a property in the parent viewModel that returns the product returned from the data property of the SelectProductViewModel (you will need to propagate the PropertyChanged event to your parent viewModel).
the most easy way is to go the viewmodel first approach and use a dialogservice to show the selection view.
your viewmodel with ProductionList simply call the dialogservice and put a ProductSelectionViewmodel with ProductionList as parameter. because this is viewmodel first you have to create a datatemplate so WPF knows how to render your ProductSelectionViewmodel.
here is a link for a simple dialogservice.
btw: in my opinion viewmodel first approach is much easier when doing mvvm.
EDIT:
in your ProductionListViewModel in your SelectProductCommand
var selectProductViewModel = new SelectProductViewModel(this.ProductionList);
var result = this.uiDialogService.ShowDialog("Select Product", selectProductViewModel );
//if result true, simple get the selected product
this.SelectedProduct = selectProductViewModel.MySelectedProduct;
thats all - simple and easy

MVVM Light, Windows Phone, View & ViewModel navigation between pages

I have a page where you basically select a set of options (configuration), and then you go to a next page, where you do some stuff
Using the MVVM Light toolkit, I have a viewmodel that binds to the view of the first page. when the user hits a button, it redirects to another view, which would be the 2nd page
i.e.:
Page2Command = new DelegateCommand((obj) =>
Messenger.Default.Send<Uri>(new Uri("/DoStuffView.xaml", UriKind.Relative),
Common.CommonResources.GoToDoStuffRequest)) });
The problem is, the viewmodel for the 2nd view (the way that I see it) has a couple of parameters in the constructor, which are basically the dependencies on the configuration that was set on the first page.
i.e. :
public DoStuffViewModel(ICollection<Note> availableNotes, SoundMappers soundType)
{
}
The problem lies here.. How can I instantiate the viewmodel with this data that was dynamically selected by the user on the 1st page?.
I can't use the ViewModelLocator pattern that MVVM light provides, since those viewmodels don't have any dependencies, they are just by themselves (or they can retrieve data from a db, file or whatever, but they don't have any dynamic input data). I could do it through the view's constructor, instantiate there the viewmodel, and assign to the view's DataSource the newly created viewmodel, but I think that's not very nice to do.
suggestions?
As I see you send messsage using Messenger class so you are familiar with messaging in MVVM light. You have to define your own message type that should accept your parameters from page 1:
public class Page2ViewModelCreateMessage : MessageBase
{
public ICollection<Note> AvailableNotes{get;set;}
public SoundMappers SoundType{get;set;}
public Page2ViewModelCreateMessage ()
{
}
public Page2ViewModelCreateMessage(ICollection<Note> availableNotes, SoundMappers soundType)
{
this.AvailableNotes = availableNotes;
this.SoundType = soundType;
}
}
You have to send an Page2ViewModelCreateMessage instance with you parameters and send it on navigating:
var message = new Page2ViewModelCreateMessage(myAvailableNotes, mySoundType)
Messenger.Default.Send(message);
On Page2 you have to register for recieving message of type Page2ViewModelCreateMessage:
Messenger.Default.Register<Page2ViewModelCreateMessage>(this, OnPage2ViewModelCreateMessage);
..
public void OnPage2ViewModelCreateMessage(Page2ViewModelCreateMessage message)
{
var page2ViewModel = new Page2ViewModel(messsage.AvailableNotes, message.SoundType);
}
As you can see I have replace your DoStuffViewModel with Page2ViewModel to be more clear.
I hope this will help you.
NOTE:I dont guarantee that code will work as its written in notepad.
The way I do this is to have a central controller class that the ViewModels all know about, via an interface. I then set state into this before having the phone perform the navigation for me. Each ViewModel then interrogates this central class for the state it needs.
There are a number of benefits to this for me:
It allows me to have non-static ViewModels.
I can use Ninject to inject the concrete implementation of the controller class and have it scoped as a singleton.
Most importantly, when tombstoning, I only need to grab the current ViewModel and the controller class.
I ran into a problem with messaging where my ViewModel was the registered listener, because I was View First and not ViewModel First, I was forced to use static ViewModel references. Otherwise the ViewModel wasn't created in time to receive the message.
I use the controller class in conjunction with messages (it is basically the recipient of all messages around the UI) so in future if I refactor, I don't need to change much, just the recipients of the messages.
Come to think of it, the controller class is also my navigation sink - as I have some custom navigation code that skips back paging on certain pages etc.
Here's an example of my current set up:
public interface IController
{
Foo SelectedFoo { get; }
}
public class ViewModel
{
private IController _controller;
public ViewModel(IController controller)
{
_controller = controller;
}
private void LoadData()
{
// Using selected foo, we load the bars.
var bars = LoadBars(_controller.SelectedFoo);
}
}
You could use PhoneApplicationService dictionary to save data you need when navigation from first event, and parse it when you navigateTo second page. you can also use that data in your ViewModels.
Something like this:
PhoneApplicationService.Current.State["DatatFromFirstPage"] = data;
and when navigating to second page:
if (PhoneApplicationService.Current.State.ContainsKey("DatatFromFirstPage"))
{
var dataUsedOnSeconPage= PhoneApplicationService.Current.State["DatatFromFirstPage"];
}
you can use this data globally in entire app

Resources