Repository Pattern and MVC help - c#

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.

Related

Correctly Mapping viewmodel to entity

I have my entity as:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
I have my UserViewModel as
public class UserViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
I am using these as below in my controller:
//This is called from my view via ajax
public void Save(UserViewModel uv)
{
// this throws error: cannot convert from UserViewModel to Entity.User
MyRepository.UpdateUser(uv);
}
My UpdateUser in repository class is as below:
public void UpdateUser(User u)
{
var user = GetUserDetails(u.Id);
user.Name = u.Name;
user.Address = u.Address;
//using entity framework to save
_context.SaveChanges();
}
How can I correctly map UserViewModel in my controller to my entity
By using AutoMapper you can do something like:
public void Save(UserViewModel uv)
{
// this throws error: cannot convert from UserViewModel to Entity.User
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<UserViewModel , User>();
});
User u = config.CreateMapper().Map<User>(uv);
MyRepository.UpdateUser(u);
}
Or manually :
public void Save(UserViewModel uv)
{
User u = new User()
{
Id = uv.Id
Name = uv.Name;
Address = uv.Address;
};
MyRepository.UpdateUser(u);
}
Which is not good to do it manually if you change your view-model and your model then you should change your code also, but with Automapper you don't need to change the code.
EDIT1:
This is not good idea to use model-view in repository (DataAccess Core) so it would be better to keep your public void UpdateUser(User u) and don't change it, in outside it is better to pass user to UpdateUser not UserViewModel like what you have done before.
EDIT2:
In my opinion non of answered posts doesn't related to SOC (Separation on concerns) even mine...
1- When I passed UserViewModel I've violated the SOC ....
2- In the other side if I got User in Peresentation layer directly I also violated the SOC.
I think the best way is a middle layer as proxy....
Presentation <----> Proxy <----> Repository.
Your repository deals with objects of type User, so you need to map the values back to an instance of that type and then make the call.
Assuming you have a method to get the user called GetUser:
public void Save(UserViewModel uv)
{
var user = MyRepository.GetUser(uv.Id);
user.Name = uv.Name;
user.Address = uv.Address;
MyRepository.UpdateUser(user);
}
You can then save the changes in your repository class. You can attach the object to make sure there are no issues if the object was created in a different context:
public void UpdateUser(User u)
{
_context.Users.Attach(u);
_context.Entry(u).State = EntityState.Modified;
_context.SaveChanges();
}
You are doing the mapping of property values(view model->enity model) inside your repositories UpdateUser method. So use the view model class (UserViewModel) as the parameter type of that.
public void UpdateUser(UserViewModel u)
{
// Get the entity first
var user = GetUserDetails(u.Id);
// Read the property values of view model object and assign to entity object
user.Name = u.Name;
user.Address = u.Address;
//using entity framework to save
_context.SaveChanges();
}
Now from your Save method ,you can pass the view model object to this method.
This will fix your compile time error (which is your current problem in the question), but be careful about what classes you are using in what layers. If you are too much worried about using a view model class in your data access layer, you can do that in a middle service layer. But then you are getting the entity model in that layer and doing the update there.
Remember, there is no definite answer for that question. Use the approach you think is readable and consistent with the project/ team. Often times, i tend to use the term "Common DTO classes" than "View models" so i can peacefully pass those around to another layer. I keep them in a separate project (called Common DTO) and this will be cross cutting across other projects. That means i will add a reference to this Common DTO project in my Web/UI layer and my data access/service layer and use those as needed.

MVC Models, Entity Framework and binding dropdowns best practice

Extremely basic question about best practice in MVC when binding drop down lists.
This inst a real world example but a basic example that explains my question:
Take the following model
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public virtual Car Car { get; set; }
}
public class Car
{
public int ID {get;set;}
public string Make {get; set;{}
public string Model {get; set;}
}
Then assume that these get flattened into a view model:
public class IndexViewModel
{
public int PersonID;
public string Name;
public int SelectedCarID;
public SelectList<Cars> Cars;
}
In my constructor I have an index method:
[HttpGet]
public ActionResult Index()
{
var person = _ctx.People.FirstOrDefault(x=>x.ID == 1);
var vm = new IndexViewModel(){
Name = person.Name,
SelectedCarID = person.Car.ID,
};
return View(vm);
}
Now, Assume that the person that is returned from the context has NO car record when the page first loads.
The view has a line :
#Html.DropDownListFor(m=>m.SelectedCarID, Model.Cars)
When the form is submitted it is picked up by the action :
[HttpPost]
public ActionResult Index(IndexViewModel model)
{
var person = _ctx.People.FirstOrDefault(x=>x.ID == model.PersonID);
var car = _ctx.Cars.FirstOrDefault(x=>x.ID == model.SelectedCarID);
person.Name = model.name;
person.Car = car;
_ctx.SaveChanges();
}
Now that is the way I have done it for ages, I started using EF back when LINQ to SQL was taking off and I have always created my models like that as I was under the imperssion that it was the recommended way.
After a discussion with another developer today I am not sure if this is stil the best way? It has always irked me that I need to do a lookup against the database to get the Car record out just so that I can update the record.
My questions are:
What is the best way to achive what I have described above?
Is the above correct?
Is there a better way to update the car entity against the person without doing a lookup (Preferably without including the foreign keys in the model)?
Is it better to just include the FKs in the model (Its not the way Ive been doing it bit it seems more sensible)?
Is there a way to bind the drop down to the car object (The guy I spoke to seemed to suggest you could but my knowlege of MVC/asp.net and furious googling seems to indicate that you cant)?
This really ins't the place for Best Practices sort of questions (that would probably be Code Review).
However some notes initially.
Keep your domain objects in the domain
The first thing that stood out to me was the SelectList<Car> property. Where it appears as your Car entity is actually a domain entity. A domain entity should not be exposed to the UI for multiple reasons.
Entity framework proxy classes monitor changes to properties that can be inadvertently saved.
Re-factoring of domain entities requires re-factoring of UI Code.
Domain entities typically contact properties you would not like exposed or otherwise.
Serialization of the Domain Entities will also serialize navigation properties and (mostly likely) cause circular reference errors.
Your question
Given the above you know have your answer, you will have to do a lookup for an entity based on your criteria from your View Model. Your view model should not have any understanding of the data context. It is in fact a View Model not a Domain Entity. By telling your View Model to interact with your data contexts you have no separation between your Data Access layers and your Presentation layers.
Don't make your controller manage data access as well
Your controller has a lot of work to-do, managing data access shouldn't be one of them. Doing so you have infarct coupled your Presentation Layer with your Data Access layer. Now as this is an example its easy to forgive however re factoring your data access layer will have direct consequences to your Presentation layer. I would suggest places a Services layer in between your data access layer and the presentation layer.
Ok All this in practice how does it look.
This is my personal approach here but will look at decoupling the data layer from the Presentation layer, no domain objects passed to the Presentation layer and using services to broker the transactions to the data layer.
Sample Service
This service is responsible for handling the interaction between the data layer and presentation (note mock repositories).
public class SampleService
{
public SampleService()
{
_dbContext = new SampleContext();
}
readonly SampleContext _dbContext;
public virtual Person GetPersonById(int id)
{
return _dbContext.Persons.FirstOrDefault(x => x.ID == id);
}
public virtual Car GetCarById(int id)
{
return _dbContext.Cars.FirstOrDefault(x => x.ID == id);
}
public virtual IList<Car> GetAllCars()
{
return _dbContext.Cars.ToList();
}
public virtual void UpdatePerson(Person person)
{
if (person == null)
throw new ArgumentNullException(nameof(person));
_dbContext.SaveChanges();
}
public virtual void UpdateCar(Car car)
{
if (car == null)
throw new ArgumentNullException(nameof(car));
_dbContext.SaveChanges();
}
}
Does this appear to be more work, absolutely does but better to implement your service now than have to do it later. What we also achieve is one location to update if we wish to change any queries or interaction methods.
IndexViewModel
As we have agreed we are no longer passing the car object to the SelectList. Infact we only need to construct a basic IList<SelectListItem> and populate this from our controller.
public class IndexViewModel
{
public IndexViewModel()
{
AvailableCars = new List<SelectListItem>();
}
public int PersonID { get; set; }
public string Name { get; set; }
public int SelectedCarId { get; set; }
public IList<SelectListItem> AvailableCars { get; set; }
}
Controller
Now our controller is pretty simple to wire up.
[HttpGet]
public ActionResult Index()
{
var person = sampleService.GetPersonById(1);
var model = new IndexViewModel
{
Name = person.Name,
PersonID = person.ID,
SelectedCarId = person.Car.ID
};
model.AvailableCars = sampleService.GetAllCars()
.Select(car => new SelectListItem
{
Text = $"{car.Make} - {car.Model}",
Value = car.ID.ToString()
})
.OrderBy(sli => sli.Text)
.ToList();
return View(model);
}
[HttpPost]
public ActionResult Index(IndexViewModel model)
{
var person = sampleService.GetPersonById(model.PersonID);
if(person != null)
{
person.Name = model.Name;
//only update the person car if required.
if(person.Car == null || person.Car.ID != model.SelectedCarId)
{
var car = sampleService.GetCarById(model.SelectedCarId);
if (car != null)
person.Car = car;
}
sampleService.UpdatePerson(person);
}
return View();
}
View Drop Down list
#Html.DropDownListFor(m => m.SelectedCarId, Model.AvailableCars)
If you compare your code to my code I have actually added more code to the solution, however removes a lot of coupling and dependencies that could become hard to manage in larger applications.
Now back to your original questions.
Is there a better way to update the car entity against the person without doing a lookup (Preferably without including the foreign keys
in the model)?
No, you should be doing a lookup for that entity (car) outside of the Model. The model should not be aware of the data context.
Is it better to just include the FKs in the model (Its not the way Ive been doing it bit it seems more sensible)?
NO, your model should not be aware of the data context, therefore you do not need to define foreign keys (in a data context sense) leave that to your controller and services.
Is there a way to bind the drop down to the car object (The guy I spoke to seemed to suggest you could but my knowlege of MVC/asp.net
and furious googling seems to indicate that you cant)?
You could, but you don't want to. Our Car entity is a domain entity and we dont want to expose the entity to the UI (Presentation). Instead we will use other classes to expose what properties are bound. In this example a simple IList<SelectListItem> was more than sufficient.

asp.net mvc better way of getting relational data

I am building an asp.net mvc site that allows users (with the role of manager) to add/manage other users
To do this I've added a relational table called ManagerUsers to the database that contains a manager id and a user id. When a manager invites a user, the data is stored in the ManagerUsers table.
When a manger views the users I am doing the following:
using (var context = new ApplicationDbContext())
{
Guid myId = Guid.Parse(User.Identity.GetUserId());
var userIds = context.ManagersUsers.Where(u => u.ManagerId == myId).Select(u => u.UserId.ToString()).ToList();
var userProfiles = context.Users.Where(t => userIds.Contains(t.Id)).ToList();
return View(userProfiles);
}
This works ok but seems kind of slow and long-winded. Does anyone know a better way of doing it?
EDIT: based on some replies I think I need to clarify what I'm asking. What I want to know is whether there is a better way to get a list of users that are under my management than getting a list of users Ids from the ManagerUsers table and then finding them from all of the users in the Users table? Maybe there is a better way of storing this data to make it faster for retrieval?
This tutorial shows examples of defining relationships with Entity Framework and the virtual property:
https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application
It would look something like this:
public virtual <ApplicationUser> User { get; set; }
This will actually create a table relating the two models. From here you should be able to get the Users using ManagerUser.Users or something to this effect. I would also follow mason's example and implement a Repository pattern.
You shouldn't tightly couple your data access code to your MVC layer. That makes it difficult to change data layers, and it makes it difficult to test MVC without hitting a real database. You're far better off creating a separate layer that allows them to be loosely coupled.
interface IMembershipService
{
List<UserProfile> GetUsersForManager(Guid managerId);
}
class SqlServerMembershipService : IMembershipService
{
private readonly string ConnectionString;
public SqlServerMembershipService(string connectionString)
{
//Any initialization of the repository goes here
ConnectionString = connectionString;
}
public List<UserProfile> GetUsersForManager(Guid managerId)
{
using (var context = new ApplicationDbContext(connectionString))
{
var userIds = context.ManagersUsers.Where(u => u.ManagerId == myId).Select(u => u.UserId.ToString()).ToList();
var userProfiles = context.Users.Where(t => userIds.Contains(t.Id)).ToList();
return View(userProfiles);
}
}
}
Your MVC controller looks like this:
class UsersController
{
private readonly IMembershipService MembershipService;
public UsersController(IMembershipService membershipService)
{
MembershipService = membershipService;
}
public ActionResult Index()
{
Guid myId = Guid.Parse(User.Identity.GetUserId());
var profiles = MembershipService.GetUsersForManager(myId);
return View(profiles);
}
}
See how UsersController now has no idea about SqlServerMembershipService? All it knows is that it's going to receive some class via its constructor that will handle retrieving data for it. How it gets that class it up to you. You could tightly couple it by saying IMembershipService MembershipService = new SqlServerMembershipService but it's better to use Dependency Injection to do that for you.
Just in case anyone cares, here is what I did in the end:
public class ApplicationManager : ApplicationUser
{
public virtual List<ApplicationUser> Users { get; set; }
public ApplicationManager()
{
Users = new List<ApplicationUser>();
}
}
public class ApplicationUser : IdentityUser
{
public virtual ApplicationManager Manager { get; set; }
...
}
This adds two fields to the AspNetUsers table - Manager_Id and Discriminator (which states whether the user is an ApplcationManager or ApplicationUser).

Entity Framework and adding POCOs without adding child objects

So perhaps I'm addressing this problem the wrong way, but I wanted to get the opinion from you fine people on StackOverflow about how to more correctly do this.
I've got a program that has to retrieve information from a repository around an Entity Framework 6.0 code-first context, do some work on the information contained and then it adds a new record to the database.
Anyway, here's the simplified look at the class I'm retrieving from EF through the repository:
public class Product
{
public int Id { get;set; }
public virtual ProductCategory Category { get;set; }
public string Name { get;set; }
}
I then build a ProcessedProduct with the following definition and pass in the previously retrieved Product as the BaseProduct:
public class ProcessedProduct
{
public int Id { get;set; }
public virtual Product BaseProduct { get;set; }
}
I use a repository layer that I saw on an EF lesson on Pluralsight and have purposed here. I've added all the relevant bits below:
public class MyContext : BaseContext<MyContext>, IMyContext
{
//Lots of IDbSets for each context
public void SetModified(object entity)
{
Entry(entity).State = EntityState.Modified;
}
public void SetAdd(object entity)
{
Entry(entity).State = EntityState.Added;
}
}
public class MyRepository : IMyRepository
{
private readonly IMyContext _context;
public MyRepository(IUnitOfWork uow)
{
_context = uow.Context as IMyContext;
}
public ProcessedProduct FindProcessedProduct(int id)
{
return _context.ProcessedProducts.Find(id);
}
public ProductCategory FindCategory(int id)
{
return _context.Categories.Find(id);
}
public int AddProcessedProductWithoutProduct(ProcessedProduct newRecord)
{
newRecord.Product = null;
Save();
return newRecord.Id;
}
public int UpdateProcessedProductWithProductButWithoutChildProperties(int processedProductId, int productId)
{
var processedProduct = FindProcessedProduct(processedProductId);
processedProduct.BaseProduct = FindProduct(productId);
processedProduct.BaseProduct.Category = null;
_context.SetModified(product);
Save();
return processedProduct.Id;
}
public int UpdateProductChildren(int processedProductId, int categoryId)
{
var processedProduct = FindProcessedProduct(processedProductId);
var category = FindCategory(categoryId);
processedProduct.BaseProduct.Category = category;
_context.SetModified(product);
Save();
return processedProduct.Id;
}
}
And finally, here's the portion that pulls it all together:
try
{
//Create the processed product without the product instance
var processedProductId = repo.AddProcessedProductWithoutProduct(finishedProduct);
//Now, update this processed product record with the product. This way, we don't create a
//duplicate product.
processedProductId = repo.UpdateProcessedProductWithProductButWithoutChildProperties(processedProductId, product.Id);
//Finally, update the category
processedProductId = repo.UpdateProductChildren(processedProductId, product.Category.Id);
//Done!
}
When I attempt to insert this ProcessedProduct into EF, it correctly creates the ProcessedProduct record, but it also creates a new Product and new Category row. I've tried manually changing the change tracking for each object so ProcessedProduct would be 'added' and the others would be either 'modified' or 'unchanged', but I would get foreign key reference exceptions thrown by Entity Framework.
My "fix" was to simply break this up into a number of different calls:
I create the new ProcessedProduct record, but I assign the Product value to null.
I query for that ProcessedProduct record with the Id, query for the appropriate Product with its Id and assign that Product to the newly retrieved ProcessedProduct record. However, I have to null out the Category property or else this will add a new duplicate Category record. I save and the ProcessedProduct record is modified.
Finally, I query the ProcessedProduct once more as well as the ProductCategory and then assign that ProductCategory to the Category property of the ProcessedProduct.BaseProduct. I can save once more and now I've created all the records I need without making any of the duplicates.
However, this approach seems quite convoluted since all I originally wanted to do is save the new parent record and simply not create duplicate child records. Is there a better way to go about doing this that I'm missing? Thanks!
Edit: And I guess the larger question is say I have a complex object with a whole bunch of these child complex objects. What's the easiest way to create a new parent without having to go through the entire graph of child objects to update the parent with them one layer at a time?
I highly recommend not setting Product & Category as navigation properties when editing. As you saw when you add the graph of processed product (with a product & category attached) to the EF context, it's marking everything in the graph as added and does inserts on everything.
The pattern I always recommend (and Nikolai also suggested in his comment, so up-vote his comment like I did :)) is to include the FK IDs in your entity and set those values, not the navigations. e.g.
newRecord.ProductId=theProductIdValue.
I've had many people cry "but foreign keys? ewwww! They will make my classes so dirty and impure!" but after they see how much easier it is to code things without tangling with the navigations in these scenarios, they have come back to say "okay, it was worth it!"
BTW if you are talking about my EF in the Enterprise course, I have a whole module about dealing with this problem...it's called something bout graphs in disconnected scenarios. :)

How to implement 3 tier approach using Entity Framework?

I know this question is asked many times, but I couldnt get a clear picture of what I need.
I have a WPF application which I need to redo using 3- Tier approach.
I have used Entity Framework for creating datamodel and using Linq queries for querying the data.
objCustomer = dbContext.Customers.Where(c => c.CustCode == oLoadDtl.CustNo).First();
I use Linq queries where ever I need in the program to get records from the database.
So, I just would like to know which all stuff comes under DAL, Business logic and UI layers.
Also, how do I separate them?
Can the entity datamodel considered as a DAL?
Is it a better idea to put the entity model in a separate class library?
It's better to create special class called DataAccess to encapsulate EntityFramework-invokes. For business logic you can create model classes, they will use DAL if needed. Other details depend on what your application should do.
For example:
//DAL
public class DataAccess
{
public static void GetCustomerByNumber(int number)
{
var objCustomer = dbContext.Customers.Where(c => c.CustCode == number).First();
return objCustomer;
}
}
//Models
public class Customer
{
public string Name { get; set; }
public int Number { get; set; }
public Customer GetCustomerByNumber(int number)
{
return DataAccess.GetCustomerByNumber(number);
}
public void ChangeProfile(ProfileInfo profile)
{
//...
}
}
Main things are extensibility, re-usability and efficiency of your solutions.

Categories