I'm having a problem on what is the best approach to design my service layer and use them in my controller. Here is my concern.
Currently I'm using this to delete categories
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Delete(List<Guid> ids)
{
if(ids == null || ids.Count == 0)
return RedirectToAction("List");
_categoryService.DeleteCategories(_categoryService.GetCategoryByIds(ids));
_categoryService.SaveChanges();
return RedirectToAction("List");
}
my concern is should I just pass ids to DeleteCategories then call the GetCategoryByIds inside the DeleteCategories. And If I'm only going to delete 1 Category, is it better to add another method like DeleteCategory then in the controller check the length of the ids and if it is only 1, use DeleteCategory instead,
my concern is should I just pass ids to DeleteCategories then call the GetCategoryByIds inside the DeleteCategories.
Just pass the ID's to the DeleteCategories method. I wouldn't even bother calling GetCategoryByIds inside of it. There's no need to query the database for all the rest of the category information if you're just planning on deleting it.
And If I'm only going to delete 1 Category, is it better to add another method like DeleteCategory then in the controller check the length of the ids and if it is only 1, use DeleteCategory instead
I wouldn't bother with creating another method. You could just pass a list with one value in it. There's nothing a DeleteCategory method could do that you can't already do with DeleteCategories.
It all depends on your business logic
If the user has the option to select more than one category and delete them at once, then it makes sense to have the delete method accepts a list of ID and delete them all, if the user can delete only one category, then it should be DeleteById(int categoryId).
As for calling GetCategoryByIds, still depends on your logic, if you have some kind of authorization, then you must retrieve the category first, make sure the user has an access to delete the provided category and proceed if everything is fine.
A note about your code, your service should have the logic for data manipulation encapsulated inside, you should not expose the SaveChanges method and give the control to the controller to call it, or at least implement the Unit of Work pattern if you need to implement some kind of transaction.
Related
I am trying to build sth pretty simple, but I try to do it the correct way. But I struggle to figure out what is best.
I have a process chain where the user has to fill in some fields in different forms. Sometimes it depends from the user inputs which form the user is shown next.
[HttpGet]
public IActionResult Form1(Form1Vm f1vm)
{
return View(f1vm);
}
[HttpPost]
[ActionName("Form1")]
public IActionResult Form1Post(Form1Vm f1vm)
{
//process the data etc
//prepare the new viewmodel for the next form view (f2vm)
//Option1:
return View("Form2", f2vm);
//Option2:
return RedirectToAction("Form2", f2vm);
//for Option 2 I would need an additional HttpGet Action Method in which I
//would have to call Modelstate.Clear(); in order to not have the
//immediate validation errors on page load
//also all the properties of my viewmodel are passed as get parameters
//what looks pretty nasty for me
}
//More form views action methods should be added here...:
What is the better way? As mentioned in my comments above I have quite a big disadvantage for using the RedirectToAction option. However if I use the direct View(); call, I don't take care on https://en.wikipedia.org/wiki/Post/Redirect/Get and the user cannot simply refresh a page without getting a warning that his form is submitted once again.
Do I miss another way or don't see something obvious?
Edit: I just thought about a 3rd way, which I have seen quite often: Not transfering the whole VM to a HttpGet method but only the ID. I'd then have to load all the data stored previously directly from the db, map it again to my new VM and then call the View(); with this VM. Right now I think this is the "best" solution, however I feel like it is pretty laborious...
As per the dicussions, I would suggest using depending on your preference :
1) Save to db at the end of each form post and as you suggested use the I'd to redirect to a GET.
2) Depending on the the number of form pages and your requirements, retrieving values that a form needs on the get would be standard practice. This ensures that if a user drops off a form at any stage you can then start them off where they left off.
3) I wouldn't setup the viewmodel for the next form in the post of the previous. Generally as part of the single responsibility principle you want to ensure that your methods have only one reason to change.
4) PostRedirectGet pattern should be implemented with this to ensure data is not saved multiple times if a user refreshes after a post.
Lets say I have Order resource, and an action public ActionResult UpdateOrder(Order order).
I am trying to make REST api. And I want to push this order to next status.
For this purpose I have a method named ChangeOrderStatus(string newStatus, int orderId) on backend which does everything about status change (send some mails, do logging, insert some things into DB. etc...) and that method will be called from controller action. The point is that changing order status is complex operation, not just replace old filed value with new one.
But my question is should I write new controller action (route) for status change, for instance public ActionResult UpdateOrderStatus(string newStatus, int orderId) and call ChangeOrderStatus there or I should put everything in UpdateOrder(Order order) method? For instance, part of the UpdateOrder(Order order) method in that case would be:
if (order.Status != oldOrder.Status) {
ChangeOrderStatus(order.Status, order.Id);
}
I would do it with first approach, but some people tell me that the second approach is better, because there should be a single entry point for resource update, so my status update or any other update related to order resource should be in UpdateOrder method... So I am not sure what is the right approach...
If you only want to update an OrderStatus I would use a resource like /orders/{id}/status. The backing controller should be capable of handling all steps neccessary. It you would alter the items of an order, this would be /orders/{id}/items or /orders/{id}/items/{id} for a single one.
To update the Order itself this would got to /orders/{id}.
I currently get an item in a collection for a user like so:
me.user = Backbone.Collection.Users.collection().get(id);
This returns the default set of attribute required in the app. On the user profile page, I want to show additional attributes that aren't necessary anywhere else.
How can I get an item in a collection (which queries the server) with additional attributes that I can specify?
Thanks
So to go along with the comment, what I think you want is to produce extra models instead of creating two user models, one with redundant + extra data.
One way you could do this is to give a relationship between different models.
Say a user model consists of simply a name and email. That's fine and dandy but you also want to render a user profile on the page (or whatever 'extras' you intend.) This seems like a good opportunity to create a separate model representing the extra data you desire.
You can do it a few ways. For example, if every user has a profile you could bake it into your user model. Something like when you create a user model:
user.profile = new Profile(); // model
I've seen some people put other models inside a model's attributes user.set('profile', new Profile()) but I'm not sure if this is a great idea. I like to keep my model attributes isolated to just that model.
Each profile model would have a url that corresponds to the model.id.
So then you could just user.profile.fetch() and use that profile attributes to populate the data in your view. Maybe it does something like /user/1/profile
Another aspect about your question that I think you might be alluding to is sending data from the server in one go when you fetch the collection. Maybe your server replies with data like this:
[{"name":"Jake", "email":"j#stack.com", "profile":"{"aboutme":"Some story"}"}, ... ]
and the profile data is only available for those who have it etc. In this case, you can then use the parse() function to pull out that extra data out and doing something before sending the name and email attributes through to the model set method.
Although, recently I think I read that using the parse to do stuff with the extra data is bad form. Override set So instead of parsing, you might just want to save that for namespacing and then in your overridden set method do something like:
set: function(attributes, options) {
if (!_.isUndefined(this.profile) && attributes.profile) {
this.profile = new Profile();
this.profile.set(attributes.profile);
} else if (attributes.profile) {
this.profile.set(attributes.profile);
}
delete attributes.profile;
return Backbone.Model.prototype.set.call(this, attributes, options);
}
You can do something similar for really unique users such as the main user using your app. When I instantiate a user model for my app (the one representing user him/herself) I also initialize a few other special models only that user would have (like an auth model for fetching authentication data etc.)
I'm not sure if I hit what you were asking but I hope I hit something.
Is collection an instance already, and I assume so? If so, you should only do:
me.user = Backbone.Collection.Users.collection.get(id);
I.e. removing the brackets () after collection.
I'm just starting out learning ASP.NET MVC 3. I've been going through the Music store sample on the ASP.NET website, as well as starting to develop my own site, but I'm having some trouble understanding how I should setup my controller action methods.
On my site each user that is logged in will be able to perform standard CRUD operations on their Projects. I've set this up similar to the Music Store sample with the following action methods on a ProjectController. So far this makes sense to me.
ActionMethod View
ProjectController.Index() Lists the active users's projects
ProjectController.Details(int id) Shows details for project 123
ProjectController.Create() Shows a form to edit a new project
ProjectController.Create(FormCollection col) Adds a new project with the form contents
ProjectController.Edit() Shows a form to edit a new project
ProjectController.Edit(int id, FormCollection col) Adds a new project with the form contents
ProjectController.Deiete(int id) Shows a delete confirmation form
ProjectController.Delete(int id, FormCollection col) Deletes a project with the provided id.
In addition, users will be able to add Items to each project. Items can not exist on their own and must be associated to a project when being created. What I'm having trouble understanding is how to pass along the reference to the project an Item should be created in. For example in my item controller I have a pair of Create() action methods similar to the controller above.
ItemController.Create() Shows a form to create a new item
ItemController.Create(FormCollection col) Creates a new item with the details from the form.
Yet I don't understand how the first Create() method passes a reference to the project which the new Item should be created in since the View() helper method can only accept one object parameter. Should I just add a reference to a project to a property of the ViewBag? I'm new to dynamic types as well and the ViewBag just seems magic to me at the point. So I'm a little hesitant to use it. I've also always thought strongly typed design is better. So should I create a separate "NewItemData" model object that contains a reference to a new Item as well as the project it is being added to?
Once the form knows which project it is adding an item to how should it pass this information back when submitted? Should there be a hidden "ProjectID" field in the form? Or should the form POST back to a URL with the project id in the query string?
www.mysite.com/Item/Create?ProjectID=1234
Finally, I also want to be able to list the items that are added to each project. Should this be part of the ItemController or the ProjectController. For simplicities sake I'm sticking with the default Controller\Action[ID] URL routing. A few of my ideas are listed below. I'm leaning towards the last option, but would really like to hear what others with more experience with this stuff think.
Action Method URL
ItemController.Index(int ProjectID) \Item?ProjectID=1234
ItemController.List(int id) \Item\List\1234
ProjectController.Items(int id) \Project\Items\1234
To answer your last question, it depends. Do Items in your model exist independently of a project? If the answer is no, then I would tend to do
ProjectController.AddItem(int id)
ProjectController.Items(int id)
where id represents the projectID.
The name of the parameters you use in the action signature directly correspond to values from the routedata and request values. {controller}/{action}/{id} is a pattern that uses the braced names as keys in the route dictionary. If you wanted you could change the routes to be {controller}/{action}/{projectid} for that action and your method signature could be the (int projectid) signature.
I don't recommend you do this just to get awesome signatures. Use comments instead if you think people will get confused.
Without changing the route pattern, if you would prefer your urls to be /project/items?projectid=3 than /project/items/3 then the action would be this:
ProjectController.Items(int projectId)
I like the prettier urls, so i'd be more apt to use the id version. That being said, if Items do not exist independently of the Project object, I would be be more likely to do this. However, if you are going to have a TON of different actions that can be performed on an Item, it would make sense to separate them into ItemController and ProjectController.
It comes down, to a large extent, about what makes sense for your application and how many actions you think a controller should have on it.
In this case you'd create a hidden field with the name=projectId and then in your Create controller have an action method.
[HttpPost]
public ActionResult Create( int projectId, FormCollection postData )
Usually you'd also use a strongly typed viewmodel so instead the FormCollection parameter use:
[HttpPost]
public ActionResult Create( int projectId, Item or ItemViewModel postData )
And as long as the name attributes match the properties in Item or ItemViewModel MVC's ModelBinder will take care of hydrating those values.
Grails offers the ability to automatically create and bind domain objects to a hasMany List, as described in the grails user guide.
So, for example, if my domain object "Author" has a List of many "Book" objects, I could create and bind these using the following markup (from the user guide):
<g:textField name="books[0].title" value="the Stand" />
<g:textField name="books[1].title" value="the Shining" />
<g:textField name="books[2].title" value="Red Madder" />
In this case, if any of the books specified don't already exist, Grails will create them and set their titles appropriately. If there are already books in the specified indices, their titles will be updated and they will be saved. My question is: is there some easy way to tell Grails to remove one of those books from the 'books' association on data bind?
The most obvious way to do this would be to omit the form element that corresponds to the domain instance you want to delete; unfortunately, this does not work, as per the user guide:
Then Grails will automatically create
a new instance for you at the defined
position. If you "skipped" a few
elements in the middle ... Then Grails
will automatically create instances in
between.
I realize that a specific solution could be engineered as part of a command object, or as part of a particular controller- however, the need for this functionality appears repeatedly throughout my application, across multiple domain objects and for associations of many different types of objects. A general solution, therefore, would be ideal. Does anyone know if there is something like this included in Grails?
removeFrom*
Opposite of the addTo method in that it removes instances from an association.
Examples
def author = Author.findByName("Stephen King")
def book = author.books.find { it.title = 'The Stand' }
author.removeFromBooks(book)
Just ran into this issue myself. It's easy to solve. Grails uses java.util.Set to represent lists. You can just use the clear() method to wipe the data, and then add in the ones you want.
//clear all documents
bidRequest.documents.clear()
//add the selected ones back
params.documentId.each() {
def Document document = Document.get(it)
bidRequest.documents.add(document)
log.debug("in associateDocuments: added " + document)
};
//try to save the changes
if (!bidRequest.save(flush: true)) {
return error()
} else {
flash.message = "Successfully associated documents"
}
I bet you can do the same thing by using the "remove()" method in the case that you don't want to "clear()" all the data.
For a good explanation of deleting a collection of child objects with GORM have a look at the Deleting Children section of this blog post - GORM gotchas part 2
It's recommended reading, as are parts 1 and 3 of the series.
I am just starting to learn Grails myself and saw your question as an interesting research exercise for me. I do not think you can use the conventional data binding mechanism - as it fills in the blanks using some kind of Lazy map behind the scenes. So for you to achieve your goal your "save" method (or is it a function?) is unlikely to contain anything like:
def Book = new Book(params)
You need a mechanism to modify your controller's "save" method.
After some research, I understand you can modify your scaffolding template which is responsible for generating your controller code or runtime methods. You can get a copy of all the templates used by Grails by running "grails install-templates" and the template file you would need to modify is called "Controller.groovy".
So in theory, you could modify the "save" method for your whole application this way.
Great! You would think that all you need to do now is modify your save method in the template so that it iterates through the object entries (e.g. books) in the params map, saving and deleting as you go.
However, I think your required solution could still be quite problematic to achieve. My instinct tells me that there are many reasons why the mechanism you suggest is a bad idea.
For one reason, off the top of my head, imagine you had a paginated list of books. Could that mean your "save" could delete the entire database table except the currently visible page? Okay, let us say you manage to work out how many items are displayed on each page, what if the list was sorted so it was no longer in numerical order - what do you delete now?
Maybe multiple submit buttons in your form would be a better approach (e.g. save changes, add, delete). I have not tried this kind of thing in Grails but understand actionSubmit should help you achieve multiple submit buttons. I certainly used to do this kind of thing in Struts!
HTH
I'm just running into this same issue.
My application's domain is quite simple: it has Stub objects which have a hasMany relationship with Header objects. Since the Header objects have no life of their own, they're entirely managed by the Stub controller and views.
The domain class definitions:
class Stub {
List headers = new ArrayList();
static hasMany = [headers:Header]
static mapping = {headers lazy: false}
}
class Header {
String value
static belongsTo = Stub
}
I've tried the "clear and bind" method but the end result is that the "cleared" objects are left over in the database and grails will just create new instances for the ones that were not removed from the relationship. It does seem to work from an user's perspective, but it will leave lots of garbage objects in the database.
The code in the controller's update() method is:
stubInstance.headers.clear()
stubInstance.properties = params
An example: while editing the -many side of this relationship I have (for a given Stub with id=1):
<g:textField name="headers[0].value" value="zero" id=1 />
<g:textField name="headers[1].value" value="one" id=2 />
<g:textField name="headers[2].value" value="two" id=3 />
in the database there are 3 Header instances:
id=1;value="zero"
id=2;value="one"
id=3;value"two"
after removing header "one" and saving the Stub object the database will have headers:
id=1;value="zero"
id=2;value="one"
id=3;value"two"
id=4;value="zero"
id=5;value="two"
and the Stub object will now have an association with Headers with id=4 and id=5...
Furthermore, without the clearing of the list, if an index is not present in the submitted request.headers list, on data binding grails will keep the existing object at that location unchanged.
The solution that occurs to me is to bind the data, then check the Stub's headers for elements that are not present in the submitted list and remove them.
This looks like a pretty simple scenario, isn't there any built-in functionality to address it?
It's a bit overkill to have to write your own synchronization logic for maintaining relationships, especially when the quirks that make it non-trivial are caused by grails itself.
What about deletion, shouldn't the clear()'ed elements be gone from the database? Am I missing something in the relationship or domain object definitions?
class Stub {
List headers = new ArrayList();
static hasMany = [headers:Header]
static mapping = {
headers lazy: false
**headers cascade: "all-delete-orphan"**
}
}
class Header {
String value
static belongsTo = Stub
}
I have added the cascade property on the owning side of relationship and Now if you try to save the stub, it will take care of removing deleted items from the collection and delete them from the DataBase.