Updating a many-to-many relationship - asp.net-mvc-3

I've asked the question a few different times in a few different ways and I haven't yet gotten any responses. I'm trying again because I feel like my solution is too convoluted and I must be missing something simpler to do.
Using EF 4.1, POCO, DbContext API, AutoMapper, and Razor in an MVC 3 application.
I have a many-to-many relationship between two of my entities: Proposals and CategoryTags. I can successfully map (Automapper) a Proposal to my ProposalViewModel including the collection of CategoryTags.
In my View, I use javascript to allow the user to add, update, and remove tags by dynamically creating elements, each one that stores the ID of the chosen tag.
I can successfully post my ViewModel back to my controller with it's CategoryTags collection populated (although only with the ID property for each CategoryTag).
When that ViewModel is posted back to my controller, I don't know how to get those tags from the ViewModel and add them to my Model in such a way that db.SaveChanges() updates the database properly.
The only way I've had any success is to disconnect the CategoryTags collection in mapping (by namig them differently), iterate through each tag and manually look it up in my context and then call the .add() method. This is sloppy for a number of reasons which leads me to believe I'm doing it wrong.
Can anyone offer any direction at all?
UPDATE:
For anyone who is interested, my functional code:
Dim p As New Proposal
Dim tempTag As CategoryTag
p = AutoMapper.Mapper.Map(Of ProposalViewModel, Proposal)(pvm)
db.Proposals.Attach(p)
db.Entry(p).Collection("CategoryTags").Load()
For Each ct In pvm.Tags
tempTag = db.CategoryTags.Find(ct.Id)
If tempTag Is Nothing Then
Continue For
End If
If ct.Tag = "removeMe" Then
p.CategoryTags.Remove(tempTag)
Continue For
End If
p.CategoryTags.Add(tempTag)
Next
db.Entry(p).State = EntityState.Modified
db.SaveChanges()
Return RedirectToAction("Index")

The only working way is doing this manually - you can read full description of the problem if you want. The description is related to ObjectContext API but DbContext API is just wrapper suffering same issues (actually DbContext API suffers even more issues in this scenario and because of that I will skip solution with manually setting relationships).
In short. Once you post your data back to the controller you must create new context instance and attach your Proposal and realated CategoryTags. But after that you must inform the context about changes you did. It means you must say context which tags have been added to proposal and which have been removed. Otherwise context cannot process your changes because it doesn't do any automatic merge with data in database.
The easiest way to solve this is loading current Proposal with related CategoryTags from database (= you will have attached instances) and merge incoming data into attached object graph. It means you will manually remove and add tags based on posted values.

Related

Linq Projection is not including all data from the original entity

I have encountered a LINQ issue and hope that you can help me to figure it out.
Here is what is happening.
I get an IQueryable<LicenseEntity> of entities from the repository.
I look at the fields in these entities and see that they contain valid data. There is a field for a related entity Customer in the LicenseEntity. It contains valid data, too, because I loaded it with the LicenseEntity.
I use .Select to project each LicenseEntity to a LicenseViewModel.
For each LicenseEntity, a LicenseEntity is passed into AutoMapper.Mapper.Map and is loaded into a LicenceViewModel entity.
After all of the entities have been processed, when I look at the list of LicenseViewModels in the debugger, it reports a null reference exception and there are no items to view.
To determine whether AutoMapper what causing my problem, I replaced it with a MapMe(). When I stopped at the return statement in MapMe and looked at the s parameter, which is the original entity, I found that the data in it is okay except that the customer field is now null. I assume that Select has done something that I don't know about.
How I can make Select retain all of the information in the original entity when it is doing its projection? Our solution cannot materialize the list because it may be very, very large. I've included my test code below and would really appreciate your help.
// Get the IQueryable<LicenseEntity> list of licenses from the repository.
var list = LicenseRepository.List();
// Convert the IQueryable<LicenseEntity> to an IQueryable<LicenseViewModel>
var vmlist = list.Select(x => MapMe(x, new LicenseViewModel()));
//var vmlist = list.Select(x => AutoMapper.Mapper.Map(x, new LicenseViewModel()));
// This function was used to see the LicenseEntity that was passing into Map().
// I discovered that the entity has all the correct data except for a related
// entity field, which was present in the original LicenseEntity before
public LicenseViewModel MapMe(LicenseEntity s, LicenseViewModel d)
{
return d;
}
The following code works properly however it materializes the entities, which we cannot do.
List<LicenseViewModel> vms = new List<LicenseViewModel>();
foreach (var item in list)
{
var vm = AutoMapper.Mapper.Map(item, new LicenseViewModel());
vms.Add(vm);
}
You've tagged this LINQ-to-Entities but there's no mention of the underlying technology in the text. But it's very likely that the problem is caused by lazy loading of associated objects.
This is a design choice that applies to most ORMs that I've worked with. When you load an object, connected objects are not loaded by default. If they were loaded by default it's quite clear you'd quickly break everything
when you load a Licence, the related Customer is automatically loaded
when the Customer is loaded all related objects are loaded - Company, Address, all other Licences, etc
for each of those objects, every related object is loaded...
The answer is that you need to specify which related objects to load. In the Entity Framework you do this using the Include method.
Because you are using a repository abstraction you might find this more difficult than it needs to be, but without knowing more I can't give any advice. This type of functionality - pretty basic stuff - is always a difficulty with repositories and 'unit-of-work' patterns.
I think your mapping should be more like:
var vms = Mapper.Map<List<LicenseEntity>, List<LicenseViewModel>>(list);
(ie - you don't need the foreach loop).
But unfortunately I doubt very much that that'll fix your issue as I suspect that'll also materialize your entities.
I've found the solution for projecting domain entities to viewmodels. If you are struggling with the same kind of issue as I had, please review the following links:
http://lostechies.com/jimmybogard/2011/02/09/autoprojecting-linq-queries/
http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code
By the way, in one one my domain entities, I had a partial class with some "calculated" properties... Properties whose values were generated from other fields in the database record. These cannot be in the domain entity because they will interfere with the aforementioned solutions. I moved them to my ViewModel class, which is where they were really required, and all is well.
Hope that this info helps...
Mike

Generating Navigation for different user types, MVC, PHP

I have this idea of generating an array of user-links that will depend on user-roles.
The user can be a student or an admin.
What I have in mind is use a foreach loop to generate a list of links that is only available for certain users.
My problem is, I created a helper class called Navigation, but I am so certain that I MUST NOT hard-code the links in there, instead I want that helper class to just read an object sent from somewhere, and then will return the desired navigation array to a page.
Follow up questions, where do you think should i keep the links that will only be available for students, for admins. Should i just keep them in a text-file?
or if it is possible to create a controller that passes an array of links, for example
a method in nav_controller class -> studentLinks(){} that will send an array of links to the helper class, the the helper class will then send it to the view..
Sorry if I'm quite crazy at explaining. Do you have any related resources?
From your description it seems that you are building some education-related system. It would make sense to create implementation in such way, that you can later expand the project. Seems reasonable to expect addition of "lectors" as a role later.
Then again .. I am not sure how extensive your knowledge about MVC design pattern is.
That said, in this situation I would consider two ways to solve this:
View requests current user's status from model layer and, based on the response, requests additional data. Then view uses either admin or user templates and creates the response.
You can either hardcode the specific navigation items in the templates, from which you build the response, or the lit of available navigation items can be a part of the additional information that you requested from model layer.
The downside for this method is, that every time you need, when you need to add another group, you will have to rewrite some (if not all) view classes.
Wrap the structures from model layer in a containment object (the basis of implementation available in this post), which would let you restrict, what data is returned.
When using this approach, the views aways request all the available information from model layer, but some of it will return null, in which case the template would not be applied. To implement this, the list of available navigation items would have to be provided by model layer.
P.S. As you might have noticed from this description, view is not a template and model is not a class.
It really depends on what you're already using and the scale of your project. If you're using a db - stick it there. If you're using xml/json/yaml/whatever - store it in a file with corresponding format. If you have neither - hardcode it. What I mean - avoid using multiple technologies to store data. Also, if the links won't be updated frequently and the users won't be able to customize them I'd hardcode them. There's no point in creating something very complex for the sake of dynamics if the app will be mostly static.
Note that this question doesn't quite fit in stackoverflow. programmers.stackexchange.com would probably be a better fit

Lost in a simple MVC case - how do I return multiple Users?

I'm not sure which title would be more descriptive, so I kept it this way. I feel kinda lost in the world of MVC.
FYI: I use PHP, but that doesn't seem of much importance in this particular case.
My problem is as follows:
I have a UserController containing the following methods:
login
new
show
overview
Then I have my UserModel, containing - in this case - roughly the same methods:
login
create
fetch
The problem is: what do I keep my user data in once fetched from the database (or XML feed, or webservice, or whatever...)? I thought of a User 'business object', containing all (relevant) properties from the database. Then, when fetching the users from the database, I instantiate a new User object for each user I fetch. If only 1 user returned from the search, I return only the User object. If more users get returned, I instantiate a UserCollection object containing all User objects - in which case I can iterate over them, etcetera.
Is that a correct way of dealing with users in MVC?
And then: imagine I made an overview of 10 users. 5 of them get edited at once - imagine a status modification using checkboxes. How do I process the changes? Do I loop over all changed User objects and store them back in the database? Then it would start to look like an implementation of the Active Record Pattern, something I'm told not to use.
I hope someone can clarify which classes and/or methods I'd need to solve this 'architectural' problem.
Since it is a rather lengthy discussion. I will give the link to an article that I have written on MVC, trying to explain it in simple terms. You may want to take a look at it.
What is MVC pattern about?
If I understand correctly, your UserModel is a bit off;
the Model part of MVC is intended as a programmatic representation of the real world model.
Meaning- it represents all the properties and actions of the real-world subject. The classic example is the Car class, which has properties such as Wheel, CurrentSpeed, and actions such as GoForward(), GoReverse() etc..
So, in your case, I think your model should be what you described as a 'user business object'.
Your controller would be responsible for fetching the UserModels from storage (or wherever), and updating them back.
your workflow would be something like this:
View would call the Controller's GetUsers.
Controller goes to storage, and fetches a list of UserModels.
Controller returns them to the view.
View displays them in some way.
And the other way around for updating.
The UserModel class would be responsible for logic that pertains to individual users (for example- ChangePassword()).

Grails: add children to parent with AJAX

I have a simple 1:1 relationship:
class MyParentDomain{
String name
MyChildDomain onlyChild
}
class MyChildDomain{
String name
}
Now on a form where I want to make a new parent "Mom", there will be a list with all the existing children. Is there a current good-practice to add children on that same form? I'm imagining a "plus" button next to the drop-down list of "onlyChild" where I could see a form for new "MyChildDomain". I saw a link somewhere where people were talking about cracking this problem (will add the link as soon as I re-discover it). Has this been done? Is anyone doing something like this?
To my knowledge, this hasn't been generally applied to any templates or with a plugin (I might be wrong).
You can, however, use the "list" abilities that Grails has which allow you to submit a list of domain entity data and then build the list of child elements in the controller from the submitted data and persist that. I've never done this myself, however, so you will need to do a bit of digging on it.
As you may have guessed, attempting to create child entities on the fly via Ajax is likely not to work since the parent entity doesn't exist yet, so there's nothing to attach them to.

I don't understand [Bind(Exclude="ID")] in MVC

I'm really confused by this... still.
I asked a similar question to this a while before, but i'll ask it even simpler now.
I see this in a lot of samples and tutorials. How could you put [Bind(Exclude="ID")] on an entire Model, and expect to do Edits on the model? If you get pack all the properties of a model on a POST but not the ID, then how do you know which ID to edit?
Even if i'm using ViewModels... i'm probably creating them without IDs. So in that case... also... how do I know which ID was updated on an Edit?
Yes, i understand that there is a "security" element to this. People can hijack the ID... so we need to keep people from updating the value during a POST. But... what is the correct way to handle edits then? What's common practice?
I feel like i'm missing something VERY trivial.
In MVC requests are processed by the model binder when the client makes a request. If you include models on your controllers then, as far as I'm aware, you actually have to specify the model you wish to bind to by prefixing your arguments with the model name (unless you only have one argument which is the model)
SomeModel_ID
Now, in some cases you might want to exclude certain properties from being bound to because they pose a security risk, which you seem to be happy with as a concept. We will exclude ID on the model, preventing any client request from posting this value in plain text.
Now why might we exclude an entire model? Well not all controller arguments are pre-processed by a model binder. RedirectToAction for example does not pass through the model binder, so it is conceivable in this instance for you to create a new model in a POST controller action, and redirect to a GET controller action, passing along a sanitised model. That model cannot be populated by the client, but we are free to populate it ourselves on the server side.
The only time I bind to a model is when I have a view model and an associated editor for that model. This makes it really easy to inject a common editor into a page and to encapsulate those properties. If you have to exclude certain properties from being bound to I would argue that you are doing it wrong.
Update
Following your comments I think I can see why you might be confused. The model bind excluder prevents the client from ever setting a model property. If you need this property to do your updating then you simply can't exclude it. What this does mean then is that the user could potentially post back any ID. In this case you should check that the user has permission to be modifying any objects or database records associated with this ID before serving the requested update. Validating the arguments is a manual process. You can use data annotations for validating inputs, but this isn't likely to help very much with access permissions. It's something you should be checking for manually at some stage.
You know the ID because it's passed to you through the page address. So:
http://yoursite.com/admin/users/edit/20
Will populate your ID parameter with 20. If it's used in a POST (ie, the information is filled in), just manually fill in the ID field and pass it to the database controller in whatever manner you have devised.
This is also immune to (trivial) hijacks because if they were to write some other ID besides 20, they wouldn't be updating the user with ID 20 now would they? :)

Resources