Handle GUIDs in ASP.Net MVC 3 - asp.net-mvc-3

I have a bunch of tables in my database that have a column which is of type GUID. I do not want this to be a part of scaffolding when i generate my views, so i am using [ScaffoldColumn(false)]. I don't want the user to enter an actual GUID when "creating" a new entity. Is there any way to automate the process of automatically adding a new GUID (thru data annotations or some other way??) when a user creates a new Entity or do i have to modify the controller for every table that has a GUID so that every time a user creates a new entry i make sure i generate a new GUID before saving it?
Thanks.

This is where (IMHO) the new scaffolding features encourages bad code.
You should define separate ViewModels for your views. These contain only the fields you wish the user to change along with any view specific validation/rules.
Within your controller action, you can check whether the user input is valid (ModelState.IsValid) and if so, do some lefty-righty mapping between your ViewModel properties and those of your entity.
See ViewModel Best Practices for more details.
However, to answer your question, you can use the HiddenInput attribute on an Id field so that it is rendered as a <input type="hidden"...
With regard with setting the Id, create a base class for your entities e.g:
public abstract class BaseEntity {
public Guid Id {get;set;}
public BaseEntity() {
Id = Guid.NewGuid();
}
}
You can then inherit your entities from this class and when you call new MyEntity() the base class constructor will be invoked, thus setting the Id.

Related

Map extra column from stored procedure to Entity Framework code first model

I am using Entity Framework code first with a generic repository pattern with ASP.NET MVC. I have two tables Category and Product.
My model class of product is like this
Public class Product
{
public int ProductID{get;set;}
Public int CategoryID{get;set;}
[ForeignKey("CategoryID")]
public virtual Category Category{get;set;}
[NotMapped]
public string CategoryName{get;set;}
}
The model is binding correctly as long as I am getting data using DBContext.
But I am having a problem when I am getting list of products from stored procedure mapped to Product object. So it is not mapping the Category property of Product object and hence I cannot able to get Category.CategoryName.
So I added a new property with [NotMapped] attribute in product class as CategoryName. But it is also not binding from stored procedure.
And if I remove the [NotMapped] attribute then it is correctly binding from stored procedure but error occurs again when getting product by DbContext (Linq).
Please help me in this regards.
You don't need to add an extra property, use the DbSet.SqlQuery method for queries that return entity types. The returned objects must be of the type expected by the DbSet object, and they are automatically tracked by the database context unless you turn tracking off.
var products= _context.Products.SqlQuery("storedProcedureName",params);
The columns returned by SP should match the properties of your entity type otherwise, it will throw an exception.
After execute your SP, you should be able of get the CategoryName through your Category navigation property:
var catName=someProduct.Category.CategoryName;
On the other hand, the returned data by the Database.SqlQuery isn't tracked by the database context, even if you use this method to retrieve entity types. If you want to track the entities that you get after execute your SP using this method, you can try this:
//Attach the entity to the DbContext
_context.Product.Attach(someProduct);
//The Category navigation property will be lazy loaded
var catName=someProduct.Category.CategoryName;
If you have disabled lazy loading you can load explicitly your navigation property:
//Load the Category navigation property explicitly
_context.Entry(someProduct).Reference(c => c.Category).Load();

Not tracking a single property of an entity with EF4

My MVC action method receives an entity object (Page) that the default model binder creates from form collection data. Some of the fields are wrong or null because they were not sent in the request to the server, for example I do not send "CreateDate" and the default model binder sets this property to some default value which I don't need.
Once the object is attached it of course tries to persist all the values (including invalid/not needed ones to the database). I could of course assign manually on a per property basis but was wondering if maybe I can somehow flag a property so it is not persisted when EntityState is set to modified and SaveChanges() is called..
public ActionResult SomeMethod(Page page)
{
page.ModifyDate = DateTime.Now;
_db.NewsPages.Attach(page);
_db.ObjectStateManager.ChangeObjectState(page, System.Data.EntityState.Modified);
_db.SaveChanges();
_db.Dispose();
}
The correct way to handle this is using different class for view model, attach empty entity to the context and assign real values per property (or let AutoMapper to handle this scenario) as #Darin suggested in the comment.
If you want to go your way you must not change state of the POCO entity but you must change state of every changed property:
public ActionResult SomeMethod(Page page)
{
page.ModifyDate = DateTime.Now;
_db.NewsPages.Attach(page);
ObjectStateEntry entry = _db.ObjectStateManager.GetObjectStateEntry(page);
entry.SetModifiedProperty("ChangedPropertyName");
// Do the same for all other changed properties
_db.SaveChanges();
_db.Dispose();
}

which is the best practices for exposing entity or DTO to view in mvc3?

I have created my own customized lots of architecture including n-tier layers for different different technology.
Currently working on n-tier architecture with asp.net mvc framework. The problem is I have entity framework at data access layer. As the entities will have all it's relational metadata and navigation properties, it becomes heavier one. I am feeling like it is not wise to expose this entities directly over mvc view.
I am more favor in exposing own customized model of entities over mvc view which one be lighter one.
But this also leads me overhead of converting data from my original entities to customized model.
For example I have Employee entity which is as generated from edmx file of entity framework. It contains total 20 fields with all navigation properties.
Now over view in mvc I need to show only 2 fields for edit.
So do we need to expose original entity to view or need to create DTO/customized model of that two field and than expose that view?
I would use a view model. I have learnt not to expose my domain objects to the view, I rather map my domain object to the view model and return this view model to the view.
Here is a partial view model, you might have more properties if you need more employee data to create/edit or display:
public class EmployeeViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
In my action method of my controller it would look something like this:
public ActionResult Edit(int id)
{
Employee employee = employeeRepository.GetById(id);
// Mapping can be done here by using something like Auto Mapper, but I am
// manually mapping it here for display purposes
EmployeeViewModel viewModel = new EmployeeViewModel();
viewModel.FirstName = employee.FirstName;
viewModel.LastName = employee.LastName;
return View(viewModel);
}
And then your view might look something like this:
<td>First Name:</td>
<td>#Html.TextBoxFor(x => x.FirstName, new { maxlength = "15" })
#Html.ValidationMessageFor(x => x.FirstName)
</td>
I prefer to have a view model that has only the values of employee that is needed on the view. Let say your employee has 20 properties, and you only need to update 2 fields, why then pass all 20 to the view? Use only what you need.
You can expose original entity, that is nothing bad. But as soon as you need some other information on the view e.g. instead of Name and Lastname you need FullName, then you should create an EmployeeViewModel with only needed properties. You initialize it with desired values in an action and then pass it to the view.

How do you exclude properties from binding when calling UpdateModel()?

I have a view model sent to the edit action of my controller. The ViewModel contains references to EntityObjects. (yea i'm fine with it and don't need to want to duplicate all the entities properties in the viewmodel).
I instantiate the view model and then call UpdateModel. I get an error that a property is "null" which is fine since it is a related model. I am trying to exclude the property from being bound during model binding. On debugging it I see in the entity where the model binder is trying to set the value of the property to null.
Here is my edit action:
var model = new SimplifiedCompanyViewModel(id);
var excludeProperties = new string[] {
"Entity.RetainedEarningsAccount.AccountNo"
,"Property.DiscountEarnedAccount.ExpenseCodeValue"
,"Entity.EntityAlternate.EntityID"
,"Property.BankAccount.BankAccountID"
,"Entity.PLSummaryAccount.AccountNo"
,"Property.RefundBank.BankAccountID"
,"Company.Transmitter.TCC"
};
try
{
UpdateModel<SimplifiedCompanyViewModel>(model, String.Empty, null, excludeProperties);
if (ModelState.IsValid)
{
//db.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View(model);
}
I have looked at a few other issues about specifying a "prefix" but I don't think that is the issue since I am telling it to bind to the viewmodel instance not just the entity object.
Am I excluding the properties correctly? Strange thing is is only seems to happen on this item. I suspect it may be an issue with the fact that there is actually no refund bank related to my entity. But I have other related items that don't exist and don't see the same issue.
More info... since I'm told me model isn't designed well.
The Company is related to a BankAccount. The Company view shows the currently related BankAccount.BankAccountId and there is a hidden field with the BankAccount.Key. I use jQueryUI autocomplete feature to provide a dropdown of bank account displaying the BankAccount.BankAccountId and when one is selected the jQuery code changes the hidden field to have the correct Key value. So, when this is posted I don't want the current bankaccounts BankAccountID modified, hence I want it to skip binding that field.
If I exclude BankAccountId in the model then on the BankAccount edit view the user would never be able to change the BankAccountId since it won't be bound. I'm not sure how this indicates a poor model design.
Use the Exclude property of the Bind attribute:
[Bind(Exclude="Id,SomeOtherProperty")]
public class SimplifiedCompanyViewModel
{
public int Id { get; set; }
// ...
}
This is part of the System.Web.Mvc namespace. It takes a comma-separated list of property names to exclude when binding.
Also you should consider using TryUpdateModel instead of UpdateModel. You can also just have the default model binder figure it out by passing it as an argument to the constructor:
public ActionResult Create([Bind(Exclude="Id")]SimplifiedCompanyViewModel model)
{
// ...
}
A very simple solution that I figured out.
try
{
UpdateModel<SimplifiedCompanyViewModel>(model, String.Empty, null, excludeProperties);
ModelState.Remove("Entity.RetainedEarningsAccount.AccountNo");
ModelState.Remove("Property.DiscountEarnedAccount.ExpenseCodeValue");
ModelState.Remove("Entity.EntityAlternate.EntityID");
ModelState.Remove("Property.BankAccount.BankAccountID");
ModelState.Remove("Entity.PLSummaryAccount.AccountNo");
ModelState.Remove("Property.RefundBank.BankAccountID");
ModelState.Remove("ompany.Transmitter.TCC");
if (ModelState.IsValid)
{
//db.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View(model);
}
Another option here is simply don't include this attribute in your view and it won't be bound. Yes - you are still open to model injection then if someone creates it on the page but it is another alternative. The default templates in MVC will create your EditorFor, etc as separate items so you can just remove them. This prevents you from using a single line view editor with EditorForModel, but the templates don't generate it that way for you anyways.
EDIT (adding above comment)
DRY generally applies to logic, not to view models. One view = one view model. Use automapper to easily map between them. Jimmy Bogard has a great attribute for this that makes it almost automatic - ie you create the view model, load up your Customer entity for example, and return it in the action method. The AutpMap attribute will then convert it to a ViewModel. See lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models
Try the Exclude attribute.
I admit that I haven't ever used it.
[Exclude]
public Entity Name {get; set;}

How to update tables with a many-to-many join with a bridging table that has payload

I am building a personal Movie Catalogue and have the following structure:
Movie table/entity
MovieID (PK identifier) +
Other movie related properties
Person table/entity
PersonID (PK identifier) +
Other person related properties.
PersonMovie table/entity
MovieID (FK)
PersonID (FK)
Other columns containing information about what the person did on the movie (I.e. charactor name or job).
I want to have a view that allows a user to create/update a movie, or a person, and have a checkbox to then allow them to select existing or create new cast members (persons), or movies.
I am struggling on two fronts:
1) how to present this type of multi-page data collection. A movie has many cast members & a person can be involved in many movies.
2) how to update 2 or 3 of the tables above depending on what the user whats to enter. A user may want to add a movie but doesnt know the cast members yet or vice versa. A user may want to add a movie and add people who already exist as cast members of the movie.
Also I do not want cascading deletes and have struggled switching it off for the relationships between the above entities.
I can do this easily with webforms but am learning MVC 3 & Entity Framework 4 and am still getting my head around it all. I have looked around and haven't come across solutions/tutorials on what I would like to achieve.
Any help would be much appreciated.
Tony
I had a similar issue when I switched from another MVC framework (Rails as in ROR). For the starters, check out Leniency's reply on the similar question, that is; relationship-with-payload or non-PJT (pure-join-table) which unfortunately ASP.NET MVC3 doesn't support explicitly.
You can create a ModelView (a virtual entity) to wrap the collections of other entity types and pass it to the View. The aforementioned post has the detailed example with the code for Model, ViewModel, View, Partial and the Controller. (read both the answers on that post, my answer is continuation of Leniency's answer there)
Hope it helps!
Vulcan's on the right track, and my response that she linked too will help you get the model setup where the linking table contains extra data.
For building the views, you'll mostly likely find that ViewModels are the way to go for more complicated setup like you're describing, then your controller and service layer will deal with processing the view model data and translating it into EF entities. Viewmodels are built specifically to the view that you need, rather than trying to hammer a domain model into a view that may not fit it.
Here's a very rough start for one of the workflows for creating a movie, with an optional list of people.
Domain - your Movie and Person class, plus a linking table similar to what I described here.
View Models - Create a movie and attach people to it
public class MovieCreatePage
{
public MovieInput Input { get; set; } // Form field data...
public IEnumerable<People> People { get; set; } // list of people for drop downs
// ... other view data needed ...
}
public class MovieInput
{
[Required, StringLength(100)]
public string Name { get; set; }
// Easiest to just submit a list of Ids rather than domain objects.
// During the View Model -> Domain Model mapping, there you inflate them.
public int[] PeopleIds { get; set; }
// ... other input fields ...
}
Create.cshtml - just make a form for your view model.
Controller:
// NOTE! The parameter name here matches the property name from the view model!
// Post values will come across as 'Input.Name', 'Input.Year', etc...
// Naming the parameter the same as the view model property name will allow
// model binding. Otherwise, you'll need an attribute: [Bind(Prefix=".....")]
[HttpPost]
public ActionResult Create(MovieInput input)
{
if (ModelState.IsValid)
{
//
// Now do your mapping - I'd suggest Automapper to help automate it,
// but for simplicity, lets just do it manually for now.
var movie = new Movie
{
Name = input.Name,
Actors = input.PeopleIds != null
? input.PeopleIds.Select(id => new Person { Id = id })
: null
};
//
// Now save to database. Usually in a service layer, but again,
// here for simplicity
// First, attach the actors as stubbed entities
if (movie.Actors != null)
{
foreach (var actor in movie.Actors)
_db.People.Attach(actor); // Attach as unmodified entities
}
_db.Movies.Add(movie);
_db.SaveChanges();
TempData["Message"] = "Success!"; // Save a notice for a successful action
return RedirectToAction("Index");
}
// Validation failed, display form again.
return View(new MovieCreatePage
{
Input = input,
// ... etc ...
});
}
Hopefully this helps you some and points you in a good direction. It does, of course, bring up a lot of other questions that will just take time (ie, automapper, service layers, all the various EF gotcha's, etc...).

Resources