I am using MVC3 and EF4 to write a web application. I am using an action header like below to capture the form values submitted by the user.
<HttpPost()>
Public Function Edit(ByVal prod as Product) As ActionResult
I use the below code for updating the record.
db.Attach(prod)
db.ObjectStateManager.ChangeObjectState(prod, EntityState.Modified)
db.SaveChanges()
I get the submitted values in prod object which I update in the database. The problem is that there are some users who are not allowed to modify certain fields in a Product, say ProductCost. I have disabled the textboxes for such fields in the HTML. But since it is clientside, the user can easily enable it using some tool like Firebug and modify the value.
The only solution I could come up was to retrieve the existing record from the database and copy its ProductCost value into prod.ProductCost. But I don't like firing a query for achieving this. Is there a better way to achieve this?
Edit: I found the below link to update particular fields. How to update only one field using Entity Framework?
You can use the below code to modify a particular field.
context.ObjectStateManager.GetObjectStateEntry(user).SetModifiedProperty("FieldName");
Now the question is do I have to write the above statement for every field the user is able to modify? If yes, suppose the Product model has 10 fields (1 primary key) and the user is allowed to modify all of them except the primary key, I need to write 9 statements?? Is there a method where you can specify multiple properties at once. Or even better something where you specify the properties which are not modified. (Note: I know I can run a loop over an array of field names to avoid writing 9 statements. I am asking for an alternative method and not refactoring the above)
Never trust client data. Always have your server code to validate the input and do appropriate actions.
I would create separate overloads of my Respiratory method update the product in different ways and then check what is the current user's access type, If he is admin, i will call the overload which updates everything, if he is a manager, i will call the method which updates name,imageUrl and price and if he is an employee, i will call the method which updates only name and ImageURL
[HttpPost]
public ActionResult Edit(Product prod)
{
if(ModelState.IsValid)
{
string userType=GetCurrentUserTypeFromSomeWhere();
if(userType=="admin")
{
repo.UpdateProduct(prod);
}
else if(userType=="manager")
{
repo.UpdateProduct(prod.ID, prod.Name, prod.ImageUrl, prod.Price);
}
else if(userType=="employee")
{
repo.UpdateProduct(prod.ID, prod.Name, prod.ImageUrl);
}
return RedirectToAction("Updated",new {id=prod.ID});
}
}
Related
I have a call to getActivitylogOptions() in a model.
But I need the data saved in the log to be different in the case of insert/update/delete.
For example, when inserting a new line, I only want to save one or two info fields. But in case of an update, I need to save all the fields that have been modified to know what exactly the user modified.
If I leave it like the following code, the update is correct, but when inserting, it saves all the fields which I don't need.
public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults()
->logAll()
->logOnlyDirty();
}
Is there any way to change the log according to the action?
My issue involved using Entity Framework / Kendo Grid and Web API 2 controllers and no ASP.NET MVC / Razor. All my code is either C# in controllers or straight up HTML / JavaScript.
It would appear that Kendo Grid are more geared for using tables / views directly rather than using stored procedures, am I correct in this assessment, or not?
I am trying to use one stored procedure in EF with a custom action name to return an IEnumerable and it populates the grid just fine, but when I try to hit the 'save changes' button, it attempts to do a POST and a PUT (I actually do think it's doing a POST because one of the rows does not have a primary key defined).
I should also mention that I think the model is not entirely the same, as the fields that get returned in the grid, don't necessarily correlate 1:1 with what gets fired in my save/update procedure. I have more fields being returned to me in the GET, and I have the model specified in the kendoDataSource, but can I customize and pick out what's being sent back when I click save changes?
During debugging, I see the correct lines in the network inspector show up, but when I look in the POST method that its hitting in the Web API 2 Controller I can't even see any values when I hover over the object being returned - which could be another issue.
So at the core, my questions are...
Is it possible to have one model return values in a GET procedure to the kendo grid, and have an entirely different model get returned in the PUT/POST procedures on this grid, during batch save? It really seems that Kendo Grids prefer using tables directly, or views, but it's policy that I can't be touching tables at all, and we prefer not to use views, we prefer to go entirely stored procedures.
Does the kendo grid, when doing a batch update/save, even though it says it's batch, is it ultimately sending data over per row, so one at a time? Or is it literally sending data over as one batch?
We're using the grids to retrieve dynamic data, the rows will not be fixed, I've worked with templates a little to add CSS classes to the elements that wrap the cells, but that won't be flexible enough, but in saying that, I wonder if there's a way to yank the data out of the grid, and throw it into some hidden table or values on the front end and have a separate save button out of scope of the grid itself, to do a save of the user's newly typed in values...?
Thank you in advance
So, I figured out my issue.
1.) In the controller I needed to have a method declaration similar to this...
public IHttpActionResult UpdateProcedure([FromBody]IEnumerable<somevalue> models)
I think the key here was the [FromBody]IENumerable models
and
2.) In the Kendo Grid, I need to sure that...
I have this line in the DataSource (I put on the READ, UPDATE and CREATE calls
contentType: "application/json; charset=utf-8",
and
batch: true
and
parameterMap: function(options, operation) {
if (operation !== "read" && options) {
return JSON.stringify(options.models);
}
}
The combination of these things at least enabled me to see the model and values in the Web API 2 Controller.
Thanks for all the assistance.
For updates it is very easy to use stored procedures. You will have a method like
public ActionResult Products_Update([DataSourceRequest]DataSourceRequest request, Product product)
And here you can fish out all properties and use them as parameters in a stored procedure.
For selecting then it would be hard to avoid tables. This is because all paging and sorting is based on an IQueryable that basically is a piece of sql. it is then given the paging and sorting in an extension method. You have a method like this:
public ActionResult Products_Read([DataSourceRequest]DataSourceRequest request)
And you can ofcourse fish everything out of the request and handle sorting and paging manually, but with a view or table you can just call the extension method and get everything:
var result = products.ToDataSourceResult(request);
Is it possible to write a validation function to ensure a field of a new document is unique?
Imagine I'm trying to write a validation function that does not allow for two users to have the same email. Every time I create a new user, the validation function will be called and will probably look something like this:
function (newDoc, oldDoc) {
//How do I get this array to contain the emails of all the users?
var allEmail;
if (allEmail.indexOf(newDoc.email) !== -1) {
throw "This email adress is already taken";
}
};
How can I fill the array allEmail to contain all emails of the users?
Is it possible to call views in the validation function?
Not possible. Validation function only operates with updated doc and his previous revision and it cannot access to other documents. The only field that guaranteed to be unique is document _id. If it's possible and doesn't produce security/privacy issues, use email as doc _id to be ensure that it's unique.
Otherwise you have to create a view with target field as a key and check for it existence first before create a new doc on the client side. However, this logic easily becomes ruined when you'll replicate docs from other instance.
If the application is in offline, the above suggested solution how will react. Local pouch view can check and return the pouch results alone. There may be a high chance of same value entered from some other end and updated to couch db.
Do you have workaround for this case ?
I need some help with MVC architecture. I use the following architecture for an object named User.
UserRepository -> IUserRepository -> UserService -> IUserService -> UserController
The User object comes from my database and I'm using EntityFramework. I have a function that returns a list of users Return_All_Users(). One of the fields that gets returned is "UserType". This comes out as a number, but when I show the list in my Index.aspx page, I would like it to show as a string. The number for "UserType" needs to look into a Dictionary to find the string that goes along with the number like "Administrator" and I would like this string to show in my Index page.
How would I go about doing this? I'm currently using this function:
public IEnumerable<User> Return_All_Users()
{
//my code here
}
I had another post for a similar question, and it was suggested that my IEnumerable should return a string, not the User object. I tried that, but then I'm working with a Dynamic model and I didn't want to do that. Nor do I know how to work with a Dynamic model, so I thought maybe there is a better way of doing this.
Should this happen in my UserService? Maybe I need to create a new class called NewUser, and define the UserType as a string, then instantiate a new NewUser and pass the value from User. Before the UserType is passed, I would look in the dictionary and get the correct value for the key.
Should I do that, or is there a better way?
After I posted this question, I just thought of doing this with a stored procedure. Maybe use a stored procedure in my database to return the data, as opposed to looking up my data straight from my database table.
I would create a View Model UserView that was formatted to the representation of how your view would best use that data. You could perform the mapping from User to UserView within your Repository or Controller depending on where you prefer doing this kind of mapping.
I'm using Entity Framework Code First and whilst I have working code, I'm having to make what are strictly unnecessary database calls in order to process the following update.
I have a simple POCO class for an album with a collection of related tags:
public class Album
{
public int Id { get; set; }
public string Title { get; set; }
public decimal Price { get; set; }
public virtual IList<Tag> Tags { get; private set; }
}
public class Tag
{
public int Id { get; set; }
public string Name { get; set; }
}
This is updated via an MVC form - with the tags represented by a series of check-boxes.
So when I get to my Update method in the respository, I have an album class populated with a list of tags - with in theory all I need to make the update.
However the only way I could find to get the list of tags to update (to delete any that were previously set but are now unchecked, and to add any that are currently checked) was to retrieve the original Album from the context and update it.
And secondly because in my implementation the Name field of the Tag is marked with [Required], and that in my Album object populated from the form I only have the IDs of the tags, I also have to retrieve each tag before updating.
Here's my code:
public void Update(Album album)
{
var albumToUpdate = GetById(album.Id); // - need to retrieve album with tags in order to update tags
albumToUpdate.Title = album.Title;
albumToUpdate.Price = album.Price;
albumToUpdate.Tags.Clear();
if (album.Tags != null)
{
foreach (var tag in album.Tags)
{
var tagToAdd = context.Tags.Find(tag.Id); // - need to retrieve full details of tag so doesn't fail validation
albumToUpdate.AddTag(tagToAdd);
}
}
}
Appreciate any thoughts as to how I could accomodate this with fewer database hits. It's not a major deal for this particular function (part of a site admin tool) but would like to know I'm doing things the best way.
Your approach - reloading the entity graph from the database and merge the changes manually into it - is correct in my opinion and the best you can do.
Forget for a moment that you use Entity Framework. What would you do if you had to write SQL statements manually? (EF is a wrapper around a SQL statement generator.) You get posted back an object graph - an Album with a list of Tags. How would you decide now which tags you have to write an INSERT, which tags a DELETE and which tags an UPDATE statement for? (I assume that your relationship between Album and Tag is many-to-many, so you write into a join table.) If you don't know the original state in the database you can't decide. Does the tag relation exist in the database or not? You have to query the database to find the answer, no matter if you use EF or direct SQL.
I see only two alternatives:
Track the entity changes yourself. For you MVC web application it would mean that you have to store the original state with the former GET request somewhere, for example in a session state or in hidden input fields in the page. With the POST request you can retrieve then the original state, build and attach the orginal graph and merge changes into it.
Write a Stored Procedure which takes the album and tag collection and let the SP do the work to create the appropriate SQL statements.
The first way is complicated and has its costs in HTTP payload (hidden input fields) or is depending on a fragile session state. And the second conflicts with why you are using an ORM. Unless you have really serious performance problems or are a SQL master I would not consider a Stored Procedure.
Firstly, I think that this pattern of updates is wrong somehow in that instead of passing in an Album which I assume is a replica or partial replica of the one you want to update (same ID at least), why don't you load the actual one first and apply your changes to it?
If you cannot do that, it might be less confusing to not pass in the same entity (Album) but instead use a data transfer object (DTO) or other message with just the fields you need and then apply that to the loaded Album.
As to the main problem of how to avoid loading each tag, EF should do that for you, but I don't know that it does. For example, NHibernate will not load a lazy entity if you are only setting a relationship because you have not touched any properties of Tag, so it only needs the Id to use it. Hopefully, EF does the same but maybe not (I'm assuming you've profiled it).
If EF does not behave like that you could try two things: firstly, so long as there is no cascade update on Tag, use a skeleton one with just the ID (that is, create the object yourself and just set the Id); this won't work if EF cascade updates the Tag. Secondly, you could implement your own cache for Tags and get them from memory.