How do I map data from a DTO to a navigational property? - asp.net-mvc

I have two models, User and Review, which have a one to many relationship. I am using a DTO to create new reviews in my controller. Reviews are added to an ICollection of type Review on a Movie model, (movies and reviews also have a one to many relationship). Here's a snippet from my controller:
var query = db.Movies.Where(i => i.id == reviewDTO.movieId).FirstOrDefault();
Review review = new Review()
{
goreRating = reviewDTO.goreRating,
shockRating = reviewDTO.shockRating,
jumpRating = reviewDTO.jumpRating,
plotRating = reviewDTO.plotRating,
supernaturalRating = reviewDTO.supernaturalRating,
description = reviewDTO.description,
isSpoiler = reviewDTO.isSpoiler
};
try
{
query.Reviews.Add(review);
}
And the models:
public class User
{
public int id { get; set; }
public string Username { get; set; }
public virtual ICollection<Review> Reviews { get; set; }
}
public class Review
{
public int id { get; set; }
public virtual Movie Movie { get; set; }
public virtual User User { get; set; }
public int goreRating { get; set; }
public int shockRating { get; set; }
public int jumpRating { get; set; }
public int plotRating { get; set; }
public int supernaturalRating { get; set; }
public string description { get; set; }
public bool isSpoiler { get; set; }
}
How can I add the relationship in the controller using entity framework and set the foreign key userId for each review?

To add a relation between User and Review you are just missing the UserId in Review
public class Review
{
....
public int UserId { get; set; } // Add this to review model
....
}
To get users with all their reviews you can write use this kind of LINQ query
var data = _context.User.Where(x => ...any condition here...).Include(x => x.Reviews )

Related

Need help trying to create a one-to-many relationship using EF7, Asp.NET and SQLite

I am new to Entity Framework and Asp.NET, and therefore, struggling with creating database relationships within the Entity Framework.
I have two SQLite tables (Ticket and User) and have setup my entity models as follows:
public class Users
{
[ForeignKey("id")]
public int id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public virtual ICollection<Tickets> Tickets { get; set; }
}
public class Tickets
{
public int id { get; set; }
public string summary { get; set; }
public string description { get; set; }
public string c_location { get; set; }
public string c_store_device { get; set; }
public string category { get; set; }
public DateTime? created_at { get; set; }
public DateTime? closed_at { get; set; }
public int priority { get; set; }
public int? assigned_to { get; set; }
public DateTime? due_at { get; set; }
public DateTime? updated_at { get; set; }
public string status { get; set; }
public virtual Users Users { get; set; }
}
I am trying to use Entity Framework 7 to export an IEnumerable<Tickets> that includes the User assigned to each Ticket.
I have tried to create my model relationship in MyDBContext as a single User can have multiple Tickets, and also has a foreign key associated in my Sqlite database (Tickets.assigned_to = User.id):
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Users - > many Tickets
modelBuilder.Entity<Users>()
.HasMany(p => p.Tickets)
.WithOne(e => e.Users)
.HasForeignKey(p => p.assigned_to);
}
My result ends up with Ticket data being exported, but against every ticket I see a null value for User:
[{"id":10002,...,"Users":null}]
When I use .Include() within my Repository to include each User like this:
public IEnumerable<Tickets> GetAll()
{
return _db.Tickets.Include(t => t.Users).ToList();
}
It results in the error
HTTP Error 502.3 - Bad Gateway
The specified CGI application encountered an error and the server terminated the process.
What I'm trying to retrieve is data that looks like:
{"Ticket";[{"id":10002,..."status":"closed"}],"Users":[{"id":"1"..."email":"johndoe#someplace.com"}]}
I know it probably has something to do with my relationship model, but I cannot work out what I am doing wrong.
First you should really derive your Users from IdentityUser. It helps when trying to wire up the relationship, but I will give you the answer based on your current models. Your ForeignKey property should be on the child entity. By naming conventions, which is what EF uses by default, your public Users Users works better if you put a public int UsersId. Then essentially what EF will do is from your public Users Users it will go to the Users table. Then it looks for the ForeignKey which is set to Id, so now we are in the Users Table looking at the id property. Then it looks for the naming convention UsersId and if it sees it, it will set that property to the value that it saw from the Users Table Id column.
Try using this
public class Users
{
public int id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public virtual ICollection<Tickets> Tickets { get; set; }
}
public class Tickets
{
public int id { get; set; }
public string summary { get; set; }
public string description { get; set; }
public string c_location { get; set; }
public string c_store_device { get; set; }
public string category { get; set; }
public DateTime? created_at { get; set; }
public DateTime? closed_at { get; set; }
public int priority { get; set; }
public DateTime? due_at { get; set; }
public DateTime? updated_at { get; set; }
public string status { get; set; }
[ForeignKey("Id")]
public int UsersId { get; set; }
public virtual Users Users { get; set; }
}
and for your Fluent API configuring
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Users - > many Tickets
modelBuilder.Entity<Users>()
.HasMany(p => p.Tickets)
.WithOne();
}
Now all that does is create the relationship. In order to view the specific items you want to view, use a ViewModel. So, pull the two lists you want from where you want. Then use logic to separate the list how you want them to display.
public class UsersViewModel()
{
public UsersViewModel(Users user, List<Tickets> tickets)
{
this.first_name = user.first_name;
this.last_name = user.last_name;
this.email = user.email;
this.Tickets = new List<Tickets>();
foreach(var ticket in tickets)
{
if(ticket.UserId == user.Id)
{
this.Tickets.Add(ticket)
}
}
}
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public List<Tickets> Tickets { get; set;}
}
then in your controller make your list
public IActionResult Index()
{
var usersList = _repository.Users.ToList();
var ticketsList = _repository.Tickets.ToList();
var model = new List<UsersViewModel>();
foreach(var user in usersList)
{
var listItem = new UsersViewModel(user, ticketsList);
model.Add(listItem);
}
return View(model);
}
or use a Linq query
public IActionResult Index()
{
var usersList = _repository.Users.ToList();
var model = new List<UsersViewModel>();
foreach(var user in usersList)
{
var ticketsList = from x in _repository.Tickets where x.UserId.Equals(user.Id) select x;
var listItem = new UsersViewModel(user, ticketsList);
model.Add(listItem);
}
return View(model);
}
then at the top of your view you should have
#model IEnumerable<UsersViewModel>

EntityFramework and relationtionships

Imagine the person Ted. Ted use bulletin board. He can post ads and subscribe to ads (imagine ad is some event.. teaching lessons for example). So as you guessed we have two objects: Advert and User (Ted). One user posts different adverts and in the other hand one user subscribes for different adverts. So we have two types of relationships: One-to-Many (Ted to his adverts) and Many-to-Many (Advert to subscribers - subscriber to adverts).
So the Models looks like:
[Table("Users")]
public class User
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Display(Name="Login")]
[Required(ErrorMessage = "Enter the login.")]
public string Name { get; set; }
[Required(ErrorMessage = "Select the city.")]
public int CityId { get; set; }
public City City { get; set; }
public int? SpecialityId { get; set; }
public Speciality Speciality { get; set; }
public virtual ICollection<Advert> Adverts { get; set; }
public virtual ICollection<Advert> SubscribedOnAdverts { get; set; }
public User()
{
Adverts = new List<Advert>();
SubscribedOnAdverts = new List<Advert>();
}
}
And Advert:
public class Advert
{
public int Id { get; set; }
[Required(ErrorMessage = "Enter your ad title")]
public string Title { get; set; }
[Required(ErrorMessage = "Enter your ad text")]
[Display(Name="Advert text")]
public string Description { get; set; }
public int? Price { get; set; }
[DisplayName("Owner")]
[Required(ErrorMessage = "Select ad owner")]
public int UserId { get; set; }
public User User { get; set; }
[DisplayName("Speciality")]
[Required(ErrorMessage = "Enter the speciality")]
public int SpecialityId { get; set; }
public Speciality Speciality { get; set; }
[Column(TypeName = "DateTime2")]
public DateTime publishTime { get; set; }
public virtual ICollection<User> SubscribedUsers { get; set; }
public Advert() {
publishTime = DateTime.Now;
SubscribedUsers = new List<User>();
}
}
Let's look at the User model: you can see the same type of props: Adverts, SubscripedOnAdverts. If we delete SubscribedOnAdverts property from the User model and SubscribedUsers from the Advert model, following code will perfom correct:
IEnumerable<Advert> userAdverts = db.Users.Where(usr => usr.Id == id).FirstOrDefault().Adverts;
It will return adverts this user posted.
But with the above properies (SubscribedOnAdverts in User model, SubscribedUsers in Advert model) it will return empty Collection.
Normal:
With problem:
I can guess why it happens. But i don't know how to fix this issue and save the relationships.

how to query against a many to many relation with entity framework 6

I have those 2 Models
public class BranchEmployees
{
public int ID { get; set; }
[Required, Column(Order = 0), Key]
public string ApplicationUserID { get; set; }
[Required, Column(Order = 1), Key]
public int BranchID { get; set; }
public virtual ICollection<ApplicationUser> ApplicationUser { get; set; }
public virtual ICollection<Branch> Branch { get; set; }
}
public class Branch
{
public int ID { get; set; }
public string BranchName { get; set; }
[Required]
public string ApplicationUserID { get; set; }
public ApplicationUser User { get; set; }
public virtual ICollection<BranchEmployees> BranchEmployees { get; set; }
}
public class ApplicationUser
{
//rest of the code
}
UPDATE
I have everything set up but what I want is the query that gets me the Employees whose IDs are in the branch employees table
, I'm using entity framework code first with MVC 5 , how do I do it ?
Assuming that your ApplicationUser class will have a navigational property called BranchEmployees, here is the query that gets me the Employees whose IDs are in the branch employees table
List<ApplicationUsers> employeeNames =
dbContext
.ApplicationUsers
.Where(au => au.BranchEmployees
.Count() > 0).ToList();
Also, can you provide whole model including ApplicationUser? I also wonder why you do not prefer BranchEmployees to inherit from ApplicationUser.
You don't need a class that indicates a many-to-many relation between two tables when you do code-first. The key here is to create virtual properties of those classes. Lets say you have a class Student and class Course. Students can be in many Courses and Courses can have many Students. To generate a database using these models the classes should look like this:
public class Student
{
private ICollection<Course> _courses;
public Student()
{
this._courses = new HashSet<Course>();
}
[Key]
public int Id { get; set; }
public string FullName { get; set; }
public virtual ICollection<Course> Courses
{
get { return this._courses; }
set { this._courses = value; }
}
}
And for Course:
public class Course
{
private ICollection<Student> _students;
public Course()
{
this._students = new HashSet<Student>();
}
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students
{
get { return this._students; }
set { this._students = value; }
}
}
I hope that this can help you solve your issue.

Join two Models to display in webpage

I'm building an application using ASP.NET MVC4 with code first data migrations. I have an estimates model, a clients model, a DbContext, and a view model I created. I am wanting to display the company name in a drop down, with the company name tied to an estimate. I have a ClientId in both models. I also created a DbSet<> and that didn't work either when querying against it.
I tried to create a viewmodel that I thought I could simply query against and display through my controller. I'm not having any luck in getting this to work. After a day plus of looking on here and other places, I'm out of ideas.
How can I query/join the two models, or query the viewmodel to get the company name associated with the clientId? Thanks for the help.
Models:
public class Estimates
{
[Key]
public int EstimateId { get; set; }
public int ClientId { get; set; }
public decimal EstimateAmount { get; set; }
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime EstimateDate { get; set; }
public string EstimateNotes { get; set; }
}
public class Clients
{
[Key]
public int ClientId { get; set; }
public string CompanyName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public ICollection<Estimates> Estimates { get; set; }
public ICollection<Contracts> Contracts { get; set; }
}
public class ClientEstimateViewModel
{
public Clients Clients { get; set; }
public Estimates Estimates { get; set; }
}
public class NovaDb : DbContext
{
public NovaDb(): base("DefaultConnection")
{
}
public DbSet<Clients> Clients { get; set; }
public DbSet<Estimates> Estimates { get; set; }
public DbSet<Contracts> Contracts { get; set; }
public DbSet<Invoices> Invoices { get; set; }
public DbSet<ClientEstimateViewModel> ClientViewModels { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Controller:
NovaDb _db = new NovaDb();
ClientEstimateViewModel ce = new ClientEstimateViewModel();
public ActionResult Index()
{
var model =
(from r in ce.Clients
join x in ce.Estimates
where
//var model =
// from r in _db.Clients
// orderby r.CompanyName ascending
// select r;
return View(model);
}
Because you've created the relationship between client & estimate in your models, you should be able to create a query like this:
var query = from c in _db.clients
select new ClientEstimateViewModel
{
Clients = c,
Estimates = c.Estimates
}
Although you'd have to change your model so Estimates was public List<Estimates> Estimates { get; set; }
This would give you a collection of ClientEstimateViewModel which you could then pass to your view

Entity Framework, relation between two tables

My model classes are:
public class User
{
public User()
{
Polls = new List<Poll>();
}
public int Id { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
ICollection<Poll> Polls { get; set; }
}
public class Poll
{
public int Id { get; set; }
public int PositiveCount { get; set; }
public int NegativeCount { get; set; }
public String Description { get; set; }
public User User { get; set; }
}
public class PollsContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Poll> Polls { get; set; }
}
EF created a table User_Id column for Polls table.
In the Create view of the Poll, I want to specify the UserId for new poll belongs too, but intellisense shows there is no access to model.UserId, there is a model.User.Id, which is not allowing me create a Poll for existing user and rather creates new User with new Id and no association is created.
<div class="editor-label">
#Html.LabelFor(model => model.User.Id)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.User.Id)
#Html.ValidationMessageFor(model => model.User.Id)
</div>
What is the right way of creating a new Poll for an existing User then ?
public class Poll
{
public int Id { get; set; }
public int PositiveCount { get; set; }
public int NegativeCount { get; set; }
public String Description { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
I think your Poll class should look like:
public class Poll
{
public int Id { get; set; }
public int PositiveCount { get; set; }
public int NegativeCount { get; set; }
public String Description { get; set; }
public int User_Id { get; set; }
public User User { get; set; }
}
If you have a column in your Poll table User_Id, then your model should also have this column. You can then just assign a User_Id to a Poll and Entity Framework will take care of the correct linking to the right User object.
Further, consider making your association properties (Poll.User and User.Polls) virtual in order to use the lazy loading mechanisms of Entity Framework.
See this

Resources