I was wondering what is the best approach to having a select list on a form which contains values from a database without duplicating any code.
What I thought would make sense would be to load this data in the controller and pass it to a view model, so I can use SelectListFor<> or whatever in order to generate the list. However this means that I have to duplicate all the list loading in both the GET and the POST methods. The other way I can see would be to pass the database context into the view model constructor and have it load the list , but this then presents two more issues:
1) Should the view model know about the database context?
2) I then cannot use model binding by accepting the view model type as a method argument because it does not have a no-argument constructor (if I create a no-argument constructor then it won't have the lists if I want to redisplay the view containing the form).
Is there a better way to do this? This seems like it must be a fairly common scenario and any advice would be appreciated.
We typically implement our lookups through a ReferenceDataRepository that gets used within the controllers in the same way as any other repository interaction. This repository will usually recieve a high number of calls for predominantly static readonly data so we may implement a derived CachedReferenceDataRepository over this using an abstraction of your caching scheme of choice (Session, AppFabric etc).
Why not get you db or repository or business rule - whatever you call it send back an IDictionary???
This example assumes you have a list of users, you will send back an Key with their ID and the Value with lets say first name + last name:
Then use this inside the view....
<%= Html.DropDownListFor(model => model.UserID, new SelectList(Model.AvailableUsers, "Key", "Value",Model.UserID))%>
model.UserID = Key
Model.AvailableUsers = IDictionary<int,string>
I create my lists in some helper code sometimes then I lookup those values using this helper... so there is one centralized class (usually static) that will generate these "Users"...
Pass these users onto the view directly or alternatively a ViewModel as in your case- which is what I recommend
NOTE: You would not hookup your data context with the List/ Model Binding, that makes things too complex. Just take in the UserID as the selected user from the list then in your post handle apporpriately...
ViewModel:
public class UsersViewModel
{
public int UserID { get; set; }
public IDictionary<int,string> AvailableUsers{ get; set; }
}
In your post...
[HttpPost]
[ValidateAntiForgeryToken]
[DemandAuthorization(RoleNames.AdminUser, AlwaysAllowLocalRequests = true)]
public ActionResult AllUsers(int UserID)
{
try
{
//save to db or whatever...
return RedirectToAction("Index", "Users");
}
catch (RulesException ex)
{
ex.CopyTo(ModelState); //custom validation copied to model state
}
var _users= _service.GetUsers();
return View("AllUsers", new UsersViewModel
{
UserID = UserID,
AvailableUsers = _users
});
}
Well, in my opinion, you have to have context or repository object in your viewmodel to keep dry in this scenario. Furthermore, it is also correct that your viewmodel should not know about your database. To handle this issue you can have viewmodel's constructor accept an interface like
public Interface IUserRepository
{
public IEnumerable<User> GetAll();
}
and you can have your view model like
public class CreateVM
{
private IUserRepository _repo;
public CreateVM(IUserRepository repo)
{
_repo = repo;
}
public IEnumerable<SelectListItem> AvailableUsers
{
get{
return _repo.GetAll().Where(x=>x.isAvailable).Select(x=>new SelectListinItem{Text = x.UserName, Value = x.UserID});
}
}
}
Last piece of the puzzle is your DI setup. tell ur IOC container to inject IUserRepository in constructor of your viewmodel whenever it is instantiated. I don't know if DI can work when modelbinder creates an instance of your view model but it it does you are there at least in theory. your viewmodel does not know your repository but only an interface and your list is created at single point so you are dry too.
The biggest problem I see with passing IRepository to ViewModel is that this can easily cause performance issues - select n+1's are so natural in this case, that it is hard to avoid them. You want to have as little rountrips to DB as possible for the request, and having IRepository passed around all those multi-level ViewModels just doesn't help that.
Instead, you can introduce ViewModel factory which is responsible for creating ViewModels of desired type. MyViewModelFactory would depend on IRepository, and would create MyViewModel which is just plain DTO.
Related
Hi guys I have various Database Models like this one
public class Trips
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public .... // and finally
public string Group_Of_user { get; set; }
}
And my Identity profile is like this
public class ApplicationUser : IdentityUser
{
public string Group_Of_user { get; set; }
}
I had originally designed my models without and Group_of_user.My main aim is to restrict one Group_of_user from another Group_of_user records. So now everytime I have to check the record everytime the User is accessing, editing etc etc with a if statement like the one below.
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var user = manager.FindById(User.Identity.GetUserId());
if (entry.Group_Of_user != user.Group_Of_user)
{
return HttpNotfound();
}
Is there any way either with a action filter or some code magic in Identity by which I can do this auto magically without inserting too many Ifs in my controller.
Sure. You just create a custom action filter, and then apply it to either your controller, action, or even globally via App_Start\FilterConfig.cs. However, this is best left as an excercise for you, as if you don't understand the mechanics, you won't understand how to fix problems, should they arise. Besides, the MSDN documentation is actually pretty good on this.
However, before you go too far, this is actually a pretty poor way of restricting access, at least in the sense of maintainability. Instead of using some arbitrary string value, actually create a foreign key to an instance of your user entity or IndentityRole. Or, if you don't want to do either or those, at least create a full-fledged Group object and create an association with that.
I'm a junior web developer trying to learn more every day.
What it the best practice for you guys to performe MVC repository pattern with Linq?
The one I use:
Create extra clases with the exact name of my .tt files with CRUD method like getAll(), getOne(), Update(), Delete() filling my own class with the entity framework and returning this, or using the entity framework crude
this is an example of what I'm actually doing.
this is my getAll method of my class for example User
public class CEmployee : CResult
{
public string name{get;set;}
public string lastname{get;set;}
public string address{get;set;}
//Extracode
public string Fullname // this code is not in the .tt or database
{
get
{
return name + lastname;
}
}
public <List>CEmployee getAll()
{
try
{
var result = (from n in db.Employee
select new CEmployee // this is my own class I fill it using the entity
{
name = n.name,
lastname = n.lastname,
address = n.address
}).ToList();
if (result.Count > 0)
{
return result;
}
else
{
return new List<CResult>
{
new CResult
{
has_Error = true,
msg_Error = "Element not found!!!!"
}
}
}
}
catch
{
return Exception();
}
}
}
that the way I do all thing I return a filled of my type, but on the web I see that people return the entity type normaly, But I do this to manipulate my response, And if I want to return extra information I just have to neste a list for example, whats the best way guys, return mytype or return the entity type ?
PD, I also use this class like my ViewModel.And I do this for all my classes.
One of the projects I am currently one uses Dependency Injection to setup the DAL (Data Access Layer.) We also are using an n-Tier approach; this separates the concern of the repository from the Business Logic and Front End.
So we would start with 4 or so base projects in the application that link to each other. One of that handles the Data Access, this would be your repository; read up on Ninject for more info on this. Our next tier is our Domain which houses the Entities built by the t4 template(.tt files) and also our DTO's (data transfer objects which are flat objects for moving data between layers.) Then we have a service layer, the service layer or business logic layer holds service objects that handle CRUD operations and any data manipulation needed. Lastly we have our front end which is the Model-View-ViewModel layer and handles the controllers and page building.
The MVVM calls the services, the service objects call the data access layer and Entity Framework works with Ninject to access the data and its stored in the DTO's as it is moved across layers.
Now this may seem overly complex depending on the application you are writing, this is built for a highly scalable and expandable web application.
I would highly recommend going with a generic repository implementation. The layers between your repository and the controller vary depending on a number of factors (which is kind of a broader/bigger topic) but the generic repository gets you going on a good implementation that is lightweight. Check out this article for a good description of the approach:
http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
Ideally in a MVC application, you will want to repositories in a different layer like in a separate project, let's call it Data layer.
You will have an IRepository interface that contain generic method signatures like GetAll, GetById, Create or UpdateById. You will also have abstract RepositoryBase class that contain shared implementation such as Add, Update, Delete, GetById, etc.
The reason that you use an IRepository Interface is, there are contracts for which your inherited repository class, such as EmployeeRepository in your case, need to provide concrete implementations. The abstract class serves as a common place for your shared implementation (and override them as you need to).
So in your case, what you are doing using LINQ with your DbContext is basically correct, but implementation like your GetAll method should be part of the generic/shared implementation in your abstract class RepositoryBase:
public abstract class RepositoryBase<T> where T : class
{
private YourEntities dataContext;
private readonly IDbSet<T> dbset;
protected RepositoryBase(IDatabaseFactory databaseFactory)
{
DatabaseFactory = databaseFactory;
dbset = DataContext.Set<T>();
}
protected IDatabaseFactory DatabaseFactory
{
get;
private set;
}
protected YourEntities DataContext
{
get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
}
public virtual T GetById(long id)
{
return dbset.Find(id);
}
public virtual T GetById(string id)
{
return dbset.Find(id);
}
public virtual IEnumerable<T> GetAll()
{
return dbset.ToList();
}
}
I would suggest you need to think about whether or not to return an error result object like CResult, and think about if your CEmployee and CResult should exist in this parent-child relationship. Also think about what you want to do with your CResult Class. It seems to me your CEmployee handles too many tasks in this case.
I want to understand (and finally appreciate because now it's only pain...) more ViewModels and strongly-typed Views in MVC.
My ViewModel
public class Combined
{
public IEnumerable<Domain> Domains { get; set; }
public IEnumerable<RegInfo> RegInfos { get; set; }
public Combined(IEnumerable<Domain> domains, IEnumerable<RegInfo> reginfos)
{
this.Domains = domains;
this.RegInfos = reginfos;
}
In Controller I pass data from repositories to an object of type Combined.
public ActionResult RegDetails(int id = 0)
{
var domain = from x in unitofwork.DomainRepository.Get(n => n.ID == id)
select x;
var reginfo = from y in unitofwork.ReginfoRepository.Get(n => n.ID == id)
select y;
var regdetails = new Combined(domain, reginfo);
return View(regdetails);
}
In a View (using Razor) I have #model project.namespace.Combined so I'm passing an object that holds two lists.
1/ Why can't I access each list item like this #Model.Domain.Name (noobish question but please help me to understand logic behind it)? I can do it form View "level" by using join but it's totally against MVC pattern. I think that only place to join those two tables is in Controller but it will create totally new object so do I need to create a Model for it?
2/ What's the best approach to get an IEnumerable object that will hold data from 2 or more tables that can be used to populate View (join, automapper)?
3/ Is there an approach that will allow me to create a Model that I will be able to use to POST to multiple tables from one FORM?
Thanks in advance.
The logic of fetching the entities in your controller action is fine; that's the job of the controller. You don't, however, need a custom constructor on your view model: just use object initialization.
var regdetails = new Combined { Domains = domain, RegInfos = reginfo }
Now, as far as your view model goes, Domains and RegInfos are IEnumerables, but you're only fetching a single object for each. If your intention is to have a list type, then you should modify your LINQ to select multiple items, but if your intention is to in fact have just one object for each, then you should not use IEnumerables in your view model.
public class Combined
{
public Domain Domain { get; set; }
public RegInfo RegInfo { get; set; }
}
If you do that, then you will be able to access the Name property on the Domain instance with just #Model.Domain.Name. However, if you keep them list-types, then you must loop through them in your view (even if there's only one item in the list):
#foreach (var domain in Model.Domains)
{
// Do something with domain.Name
}
You get indeed a Model property in your view, and you can use Domains and RegInfos properties like you would do in c#. For example :
#{
var firstDomain = Model.Domains.FirstOrDefault();
// do some process with this variable
}
Or :
#foreach(var regInfo in Model.RegInfos)
{
// do some other process
}
If displayed data come from various data sources, it is best to make a specific view model. You need to avoid making calculations or applying business rules in your view, data should be preformatted before that. Another benefit is to pass only required data to your view : you don't want to fetch a huge object (or collection) from your database just for 2 displayed properties.
That view model can also be used when you submit a form. You can get it back if your post action has a parameter of the view model type, and if you correctly generate inputs in your view (by using some HtmlHelper like Html.Editor(For), etc).
Anyway, there's a lot to say about strongly typed views, and many resources / tutorials can be found across the web.
Any help is greatly appreciated!,
Everything was going great until I stumbled across this :(
When I click edit on my display table, It goes to the edit vue putting a 0 in my id text field but the rest of the form is blank?
What I have:
public ActionResult EditProduct(int? id)
{
Product prod = new Product();
return View(prod);
}
Thanks Guys!
In your code you are creating a new product and then sending that to the view, so it will be blank and have a zero as the id.
You need to retrieve your product and then pass it to the view. Maybe like this:
public ActionResult EditProduct(int? id)
{
Product prod = _productRepository.Get(id);// code to retrieve product from database
if (prod != null)
{
return View(prod);
}
else
{
return RedirectToAction("Error"); // or whatever...
}
}
You'll need to load your product from your data store by id instead of creating a new instance. Something like:
return View(db.Products.Find(id))
A great place to start with MVC is http://www.asp.net/mvc. There are plenty of tutorials for data driven mvc web sites.
To do your repository, create an interface named IProduct with a method Get, GetAll, Save, etc. Your repository class implementation ie ProductRepository.cs that implements IProductRepository has a reference to your ObjectContext (or DbContext is using ef 4.1)
Some prefer to have a generic IRepository interface - but as it was said to me 'a generic repository is a fairy tale'
Once you have that, create
YourRepository repository = new Repository(); //Some choose to pass in a context or inject one via unity, ninject, etc. this is a basic example.
Your repository has a method
private YourContextName _context = new YourContextName();
public Product Get(int productId)
{
return _context.Products.Where(o=>o.ProductId=productId).Single();
}
Thats all there is to it. Of course there are more advanced implementations but it is fairly basic.
http://blogs.microsoft.co.il/blogs/gilf/archive/2010/01/20/using-repository-pattern-with-entity-framework.aspx
http://www.codeproject.com/KB/database/ImplRepositoryPatternEF.aspx
http://blogs.msdn.com/b/adonet/archive/2009/06/16/using-repository-and-unit-of-work-patterns-with-entity-framework-4-0.aspx
I'm new to C# and ASP.NET MVC and i'm trying to understand the repository pattern. I've read a whole lot of articles, but I just don't understand how to use it. I'm currently using LINQ to SQL to access my SQL Server 2005 database and for testing purposes I created two tables. I have an Employees table and an EmployeeContacts table. The pk of both tables is UserName.
Employees
UserName
LastName
FirstName
Position
Email
Status
HireDate
EmployeeContacts
UserName
Contact1
Contact1Phone
Contact1Relationship
There is a one to one relationship between the two tables. An employee can be added, updated, and deleted and so can the data in the EmployeeContacts table.
So would I create a base repository to be used by both entities or should I create a repository for each entity separately? If anybody would be willing to show me some code that would be great.
So far, I have this Employee repository. I also have one for EmployeeContacts.
namespace MvcDirectoryLINQ.Models
{
public class EmployeeRepository
{
private TestDB_DataDataContext db = new TestDB_DataDataContext();
private UserName u = new UserName();
//
// Query Methods
public IQueryable<Employee> FindAllEmployees()
{
return db.Employees;
}
public IQueryable<Employee> FindRecentEmployees()
{
DateTime myDate = DateTime.Today.AddMonths(-6);
return from empl in db.Employees
where empl.HireDate >= myDate
orderby empl.HireDate
select empl;
}
public Employee GetEmployee(string UserName)
{
return db.Employees.SingleOrDefault(d => d.UserName == UserName);
}
//
// Insert/Delete Methods
public void Add(Employee employee)
{
// get the UserName which is created from the email
employee.UserName = u.ReturnUserName(employee.Email);
//Insert the new employee into the database
db.Employees.InsertOnSubmit(employee);
db.EmployeeContacts.InsertOnSubmit(employee.EmployeeContact);
}
public void Delete(Employee employee)
{
db.EmployeeContacts.DeleteOnSubmit(employee.EmployeeContact);
db.Employees.DeleteOnSubmit(employee);
}
//
// Persistence
public void Save()
{
db.SubmitChanges();
}
}
}
I have a class for an EmployeeFormViewModel:
namespace MvcDirectoryLINQ.Models
{
public class EmployeeFormViewModel
{
//Properties
public Employee Employee { get; private set; }
public EmployeeContact EmployeeContact { get; private set; }
//Constructor
public EmployeeFormViewModel(Employee employee, EmployeeContact employeeContact)
{
Employee = employee;
EmployeeContact = employeeContact;
}
}
}
Code for EmployeeController:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(string UserName, FormCollection formValues)
{
Employee employee = employeeRepository.GetEmployee(UserName);
EmployeeContact employeecontact = employeecontactRepository.GetContact(UserName);
try
{
UpdateModel(employee);
UpdateModel(employeecontact);
employeecontactRepository.Save();
employeeRepository.Save();
return RedirectToAction("Details", new { UserName = employee.UserName });
}
catch
{
foreach (var issue in employee.GetRuleViolations())
{
ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
return View(new EmployeeFormViewModel(employee, attendingID));
}
}
In my View, i inherit from #model MvcDirectoryLINQ.Models.EmployeeFormViewModel. My Employee data saves correctly but the EmployeeContacts don't and I have no idea why.
Am I implementing the repository pattern correctly?
The main goal when using the Repository Pattern (as far as I understand it) is to decouple your application from using a specific Data Access Layer. You haven't done that here because you create I can see that your EmployeeRepository class does not implement an interface. You really want to have something like EmployeeRepository : IEmployeeRepository
Then, in your Controller code, you can pass around an IEmployeeRepository instead of working concretely with your EmployeeRepository. This will give you two benefits:
Should you ever need to switch the backend code, you only need to make another class that implements the interface.
When you go to test your Controllers, you can pass around a so called mock object that implements the interface instead of hitting the actual database, which slows your tests down and also breaks Unit Testing.
Another thing I noticed is that you spin up a DataContext inside your repository. If you wanted to make changes to multiple different types of objects you would therefore have multiple DataContexts open, which I don't think is what you want, since your changes won't be transactional. You may want to look into the Unit of Work Pattern for a solution.
When learning about a pattern, try to figure out the main benefit first before trying to implement it. In some cases it may not make sense. Please let me know if you would like me to elaborate on anything. Good luck.
So would I create a base repository to be used by both entities or should I create a repository for each entity separately?
The general rule when using the repository pattern is that there should be one repository class per each primary entity type. Can the EmployeeContacts live independently of any Employee? If so, they should have their own repository. Are them always related to an Employee? If so, manage them by using the Employee repository itself.