Should data access operations be encapsulated in the ViewModel or Controller? - entity-framework

One of the main reasons I want to use a ViewModel instead of the model direct in the controller is that I notice the controller containing data access that, to me, seems to be the wrong place for this work. Shouldn't data access / read write be done in the ViewModel?
things like:
Data Access
Read / Write
Mapping
Select Lists
i.e.
EF created Model:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestIODSManagement.Models
{
using System;
using System.Collections.Generic;
public partial class ClientJob
{
public int Id { get; set; }
public int ClientId { get; set; }
public int JobTypeId { get; set; }
public string OlapAppName { get; set; }
public string EdgeAppName { get; set; }
public Nullable<int> DatabaseServer { get; set; }
public Nullable<int> ProcessingServer { get; set; }
public Nullable<int> QueryServer { get; set; }
public string DatabaseName { get; set; }
public int DomainId { get; set; }
public int CurrencyTypeId { get; set; }
public virtual Client Client { get; set; }
public virtual CurrencyType CurrencyType { get; set; }
public virtual Domain Domain { get; set; }
public virtual JobType JobType { get; set; }
public virtual Server DbServer { get; set; }
public virtual Server OpServer { get; set; }
public virtual Server OqServer { get; set; }
}
}
Possible ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using TestIODSManagement.Models;
namespace TestIODSManagement.ViewModels
{
public class ClientJobsViewModel
{
private DeploymentsEntities db = new DeploymentsEntities();
public int Id { get; set; }
public int ClientId { get; set; }
public int JobTypeId { get; set; }
public string OlapAppName { get; set; }
public string EdgeAppName { get; set; }
public Nullable<int> DatabaseServer { get; set; }
public Nullable<int> ProcessingServer { get; set; }
public Nullable<int> QueryServer { get; set; }
public string DatabaseName { get; set; }
public int DomainId { get; set; }
public int CurrencyTypeId { get; set; }
public virtual Client Client { get; set; }
public virtual CurrencyType CurrencyType { get; set; }
public virtual Domain Domain { get; set; }
public virtual JobType JobType { get; set; }
public virtual Server DbServer { get; set; }
public virtual Server OpServer { get; set; }
public virtual Server OqServer { get; set; }
private List<Client> _clients;
public IList<Client> Clients { get { return _clients.AsReadOnly(); } }
private List<Domain> _domains;
public IList<Domain> Domains { get { return _domains.AsReadOnly(); } }
private List<CurrencyType> _currencyTypes;
public IList<CurrencyType> CurrencyTypes { get { return _currencyTypes.AsReadOnly(); } }
private List<JobType> _jobTypes;
public IList<JobType> JobTypes { get { return _jobTypes.AsReadOnly(); } }
private List<Server> _databaseServers;
public IList<Server> DatabaseServers { get { return _databaseServers.AsReadOnly(); } }
private List<Server> _processingServers;
public IList<Server> ProcessingServers { get { return _processingServers.AsReadOnly(); } }
private List<Server> _queryServers;
public IList<Server> QueryServers { get { return _queryServers.AsReadOnly(); } }
public ClientJobsViewModel(Client client)
{
ForceClientList(client);
SetSelectLists();
}
public ClientJobsViewModel(int jobId)
{
ClientJob job = db.ClientJobs.Find(jobId);
Client thisClient = db.Clients.Find(job.ClientId);
ForceClientList(thisClient);
SetSelectLists();
}
private void ForceClientList(Client client)
{
_clients = db.Clients
.Where(c => c.Id == client.Id)
.ToList();
}
private void SetSelectLists()
{
_databaseServers = db.Servers
.Where(s => s.ServerPurpos.PurposeName == "DataWarehouse").ToList();
_processingServers = db.Servers
.Where(s => s.ServerPurpos.PurposeName == "Processing").ToList();
_queryServers = db.Servers
.Where(s => s.ServerPurpos.PurposeName == "Querying").ToList();
_domains = db.Domains.ToList();
_currencyTypes = db.CurrencyTypes.ToList();
_jobTypes = db.JobTypes.ToList();
}
}
}

You're right that the controller is not the right place, but neither is the view model. Ideally, your view model should only contain properties to encapsulate the data, and rarely any functionality. I would place all that logic in a dedicated data layer, or failing that if it's small, simple project, a class dedicated to data access.
Then, the controller should be the one to call into that layer, class or service and request that the view model be populated.

There is difference between ViewModel and Model. ViewModel is only custom class - crate which pass data between view and controller in strongly typed fashion. Model is "something" your controller calls to get data, business logic, etc. It can be service layer, business logic class, repository or whatever else. Data access is part of Model.

Related

Returning Entity with its children

Hi I am trying to return all vehicles with their recorded mileage through an api using ASP.Net Core with the following code:
// GET: api/values
[HttpGet]
public IEnumerable<Vehicle> Get()
{
return _context.Vehicles.Include(m=>m.Mileages).ToList();
}
However this only returns the first vehicle with its mileages and not the others (there are five dummy vehicles in the db all with an initial mileage).
If I change the code to:
// GET: api/values
[HttpGet]
public IEnumerable<Vehicle> Get()
{
return _context.Vehicles.ToList();
}
it returns the full list of vehicles but no mileage.
My class files are:
public class Vehicle
{
public Vehicle()
{
Mileages = new List<Mileage>();
}
public int Id { get; set; }
public string Registration { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public Marked Marked { get; set; }
public ICollection<Mileage> Mileages { get; set; }
}
and
public class Mileage
{
public int Id { get; set; }
public DateTime MileageDate { get; set; }
public string RecordedMileage { get; set; }
//Navigation Properties
public int VehicleId { get; set; }
public Vehicle Vehicle { get; set; }
}
thanks for looking!
Tuppers
you can have them auto-load (lazy loading) using proxies... but for that, your foreign entities and collections must be marked virtual in your POCOs:
public class Mileage
{
public int Id { get; set; }
public DateTime MileageDate { get; set; }
public string RecordedMileage { get; set; }
//Navigation Properties
public int VehicleId { get; set; }
public virtual Vehicle Vehicle { get; set; }
}
public class Vehicle
{
public Vehicle()
{
Mileages = new List<Mileage>();
}
public int Id { get; set; }
public string Registration { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public Marked Marked { get; set; }
public virtual ICollection<Mileage> Mileages { get; set; }
}
The proxy creation and lazy loading turned on, but that's the default in EF6.
https://msdn.microsoft.com/en-us/data/jj574232.aspx
Let me know if this works.
Well after a lot of searching I managed to find a solution. I used the following:
[HttpGet]
public IEnumerable<VehicleDto> Get()
{
var query = _context.Vehicles.Select(v => new VehicleDto
{
Registration = v.Registration,
Make = v.Make,
Model = v.Model,
Marked = v.Marked,
Mileages = v.Mileages.Select(m => new MileageDto
{
MileageDate = m.MileageDate,
RecordedMileage = m.RecordedMileage
})
.ToList(),
})
.ToList();
return (IEnumerable<VehicleDto>) query.AsEnumerable();
this doesn't seem to be the most elegant way of doing this, if anyone could offer any advice but it does return what is required.
The DTO's look like:
public class VehicleDto
{
public string Registration { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public Marked Marked { get; set; }
public ICollection<MileageDto> Mileages { get; set; }
}
and
public class MileageDto
{
public DateTime MileageDate { get; set; }
public string RecordedMileage { get; set; }
}
Thanks for taking the time to look at this
Tuppers

how to update .edmx file without effecting all the other model classes?

how to update .edmx file without effecting all the other model classes?
when I update the edmx file it recreates all the other classes and this is a problem for me because I made some changes on the other classes so how can I modify it without affecting the other classes.
For example this is one of my classes
public partial class company
{
public company()
{
this.Departments = new HashSet<department>();
this.CustomersOfTheCompany = new HashSet<company_customers>();
this.CompaniesTheCompanyCustomerFor = new HashSet<company_customers>();
this.CustomerProjectDetails = new HashSet<cus_pro_connector>();
this.CompanyAsSupplier = new HashSet<company_suppliers>();
this.CompanyAsCustomer = new HashSet<company_suppliers>();
this.Tickets = new HashSet<oneTimeAuthenticationTicket>();
}
[Required(ErrorMessage = "Company name is required")]
[StringLength(200, MinimumLength = 3, ErrorMessage = "Length Of The Company Name Should Be More Than Three Letters")]
public string CompanyName { get; set; }
[Required]
[EmailAddress(ErrorMessage = "Invalid Email Address")]
public string Email { get; set; }
[Required]
public int Country { get; set; }
public int company_id { get; set; }
public string Logo { get; set; }
public string Description { get; set; }
private CompanyDTO _CDTO = new CompanyDTO();
public CompanyDTO CDTO { get { return this._CDTO; } set { this._CDTO = value; } }
public virtual ICollection<department> Departments { get; set; }
public virtual country CountryOfTheCompany { get; set; }
public virtual ICollection<company_customers> CustomersOfTheCompany { get; set; }
public virtual ICollection<company_customers> CompaniesTheCompanyCustomerFor { get; set; }
public virtual ICollection<cus_pro_connector> CustomerProjectDetails { get; set; }
public virtual ICollection<company_suppliers> CompanyAsSupplier { get; set; }
public virtual ICollection<company_suppliers> CompanyAsCustomer { get; set; }
public virtual ICollection<oneTimeAuthenticationTicket> Tickets { get; set; }
}
so when I modify the .edmx the class attributes will no longer be available.
It is not possible to retain edits to generated files when you re-generate them. If you need to apply attributes to generated code, there is a MetadataType mechanism that allows you to specify validation attributes in another partial class.
See this other answer or MSDN for further information on this.
I don't understand your example - But I will explain here:
Let's say you have the following Entity Models:
And the User.cs looks like this:
public partial class User
{
public User()
{
this.UserWindows = new HashSet<UserWindow>();
}
public int UserId { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public virtual ICollection<UserWindow> UserWindows { get; set; }
}
Add a new file and call it Extensions.cs, then create a New Partial Class in this File:
Then you can Add Properties to this Class:
public partial class User
{
public int NewUserId { get; set; }
}
And whenever you create a New User Object you will see your new Properties:
Similarly you can do this for UserWindow.cs
Extensions.cs:
public partial class User
{
public int NewUserId { get; set; }
}
// Similarly you can do
public partial class UserWindow
{
public string MyNewProperty { get; set; }
}
Then

EF6 generates all the entity classes (tt .cs) in single file (eg. model.cs) and not as separate .cs file

I am using EF6. I have 2 tables Events and Users for which I used database first approach to generate the EDMX models and entity classes. Everything works fine but the entity classes are coming under a single file in this case EventSample.cs(shown below). I am not getting separate files for each entity as Event.cs and User.cs. Please let me know if this is correct and if not how to rectify it?
public partial class Event
{
public Event()
{
this.Users = new HashSet<User>();
}
public int Id { get; set; }
public string Title { get; set; }
public System.DateTime Time { get; set; }
public string Location { get; set; }
public string Description { get; set; }
public int Creator_Id { get; set; }
public virtual User User { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public partial class User
{
public User()
{
this.Events = new HashSet<Event>();
this.Events1 = new HashSet<Event>();
}
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public virtual ICollection<Event> Events { get; set; }
public virtual ICollection<Event> Events1 { get; set; }
}

I get UpdateException when i try to Update a collection property

I am in an MVC4 application and i am using EF CodeFirst.
When I try to run the following code:
public void Autorizare(int cerereId, Persoana persoana)
{
var cerere = _db.Cereri.Find(cerereId);
cerere.Autorizare.Add(persoana);
_db.SaveChanges();
}
I get an error like this:
Entities in 'CerereDbContext.Persoane' participate in the 'Actiune_Executanti' relationship. 0 related 'Actiune_Executanti_Source' were found. 1 'Actiune_Executanti_Source' is expected.
i have tried Entity(Actiune).State = EntityState.Modified, but no results.
I have a main POCO:
public class Cerere
{
public int Id { get; set; }
...
public virtual ICollection<Actiune> Actiuni { get; set; }
...
}
the Actiune class looks like this
public class Actiune
{
public int Id { get; set; }
public DateTime Data { get; set; }
public String Nume { get; set; }
public virtual ICollection<Persoana> Executanti { get; set; }
public String Stadiu { get; set; }
public String Obs { get; set; }
}
And Persoana:
public class Persoana
{
public int Id { get; set; }
public DateTime Data { get; set; }
public String Nume { get; set; }
}
From your model the Cerere does not have a property named Autorizare; however it does have one named Actiuni. Which is of type Actiune not Persoana which is what you are trying to add to it. Please post the rest of the Class Definition.

Entity Framework : get related entities

I created a WCF service with Entity Framework.
I have 2 tables : Theaters and Locality. Locality as a foreign key in Theaters.
My method :
public theater[] GetTheaters()
{
using (Entities context = new Entities())
{
return context.theater.ToArray();
}
}
I have to remove the "virtual" keyword from "public virtual locality locality { get; set; }" in my theater class. Otherwise, I get a CommunicationException.
But when I do that, I get my list of theaters but the locality is null...
How can I get the locality ?
Thanks
My model class ( I also have other entities) :
public partial class locality
{
public locality()
{
this.theater = new HashSet<theater>();
}
public int idLocality { get; set; }
public int npa { get; set; }
public string locality1 { get; set; }
public ICollection<theater> theater { get; set; }
}
public partial class theater
{
public theater()
{
this.session = new HashSet<session>();
}
public int idTheater { get; set; }
public string name { get; set; }
public string address { get; set; }
public int idLocality { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
public int seats { get; set; }
public string phone { get; set; }
public string email { get; set; }
public bool threeD { get; set; }
public locality locality { get; set; }
public ICollection<session> session { get; set; }
}
Here is the error that I get :
"Object graph for type 'locality' contains cycles and cannot be serialized if reference tracking is disabled.
EDIT :
The solution that I found :
In my locality class, I had a Collection of theaters.
I had to add "private to the setter like this :
" public ICollection theater { get; private set; }"
So it works, but I still have a problem, I can't access to the theaters from the locality entity anymore. (no more bi-directional)
If you want to force related entities to load, you can use the Include method to do so. By default, related entities are loaded Lazily.
Your example would be:
public theater[] GetTheaters()
{
using (Entities context = new Entities())
{
return context.theater.Include(t=>t.Locality).ToArray();
}
}
You can use eager loading or explicit loading. With eager loading you use the Include extension method:
return context.Theater.Include(t => t.Locality).ToArray();
You're missing the correct annotations to create the relationships. See the code below. (or create the relationships yourself if using the FluentAPI)
Look for the [Key] and [ForeignKey] annotations, as well as the virtual keyword.
public partial class locality
{
public locality()
{
//this.theater = new HashSet<theater>();
}
[Key]
public int idLocality { get; set; }
public int npa { get; set; }
public string locality1 { get; set; }
public virtual ICollection<theater> theaters { get; set; }
}
public partial class theater
{
public theater()
{
//this.session = new HashSet<session>();
}
[Key]
public int idTheater { get; set; }
public string name { get; set; }
public string address { get; set; }
public int idLocality { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
public int seats { get; set; }
public string phone { get; set; }
public string email { get; set; }
public bool threeD { get; set; }
[ForeignKey("idLocality")]
public virtual locality locality { get; set; }
//public ICollection<session> session { get; set; }
}