I am new to MVC, and learning as i go, but I am struggling to get to grips with DTO's with Web api.
I have 2 tables, one Schools, one students.
The School table has a one to many relationship with the Student table.
I can't seem to get the api response the way I want it.
This is the School DTO
public class SchoolDTO
{
public string schoolCode { get; set; }
public string schoolName{ get; set; }
public string studentNames { get; set; } // the related data
}
And this is what I am trying to do to populate it -
var schoolWithStudents = from b in context.Schools
select new SchoolDTO()
{
schoolCode = b.schoolCode,
schoolName= b.schoolName,
studentNames = b.Student.studentName
};
The response i am trying to get is something like this -
School
{schoolCode, schoolName}
StudentNames
[{…},{..}]
}
If you want to display student names which belong to a school, why studentNames property of SchoolDTO class is of type string ? It should be List<string>:
public class SchoolDTO
{
public string schoolCode { get; set; }
public string schoolName { get; set; }
public List<string> studentNames { get; set; }
}
And your Database Model should be something like that:
public class School
{
[Key] //I assume it is a PK
public string schoolCode { get; set; }
public string schoolName { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class Student
{
[Key]
public Guid studentId { get; set; }
public string studentName { get; set; }
public string schoolCode { get; set; }
[ForeignKey("schoolCode")]
public virtual School School { get; set; }
}
So you can query the database like this:
var schoolWithStudents = context.Schools.Select(q => new SchoolDTO
{
schoolCode = q.schoolCode,
schoolName= q.schoolName,
studentNames = q.Students.Select(w => w.studentName).ToList()
})
.ToList();
Related
I have a db with some tables in which items contains some localized string. The plan is to have an ID to a dedicated "Localization" table.
public class User
{
public int Id {get; set; }
public string Name { get; set; }
public Localization Signature { get; set; }
}
public class Item
{
public int Id {get; set; }
...
public Localization Title { get; set; }
}
public class Localization
{
public int Id { get; set; }
public string En { get; set; }
public string Fr { get; set; }
public string De { get; set; }
}
This works. But the goal is now to have a "dynamic" list of languages, so we could easy extend the localization to other languages.
I can solve this with a JSON field in which I serialize the languages string, but it has the disadvantage to lose the readability in any DB Viewer. So if possible, I would like to have real columns.
Is there any way to solve this use case with EF Core ?
I'd approach this not by adding columns to the database (which requires a change to the DB structure) but by adding rows:
public class Item
{
public int Id {get; set; }
...
public string Title { get; set; }
}
public class Localization
{
public int Id { get; set; }
public int ItemId { get; set; }
public string LanguageCode { get; set; }
public string Text { get; set; }
}
Then load item's title along the lines of:
item.Title = context.Localizations
.Where(l => l.ItemId == item.Id && l.LanguageCode == "en")
.FirstOrDefault();
(You can also load Title in the same query where you load Item... that query is meant to be illustrative of the concept).
I have 3 tables , one to many relationship.
I need to get only specific columns with SelectMany method.
I need to get only Categories.CategoryName and Comments.CommentDate of the selected News object.
Here is my code
News news = db.News.Include(w => w.Categories)
.Include(w => w.Comments).SingleOrDefault(n => n.NewsId == Id);
Here are my Entities:
News Entity:
public partial class News
{
public News()
{
this.Categories = new HashSet<Category>();
this.Comments = new HashSet<Comment>();
}
public int NewsId { get; set; }
public string NewsTitle { get; set; }
public string NewsBody { get; set; }
public System.DateTime NewsDate { get; set; }
public string NewsImagePath { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
Category Entity:
public partial class Category
{
public Category()
{
this.News = new HashSet<News>();
}
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public virtual ICollection<News> News { get; set; }
}
Comment Entity:
public partial class Comment
{
public Comment()
{
this.News = new HashSet<News>();
}
public int CommentId { get; set; }
public string CommentBody { get; set; }
public Nullable<System.DateTime> CommentDate { get; set; }
public virtual ICollection<News> News { get; set; }
}
This LINQ query should take care of it:
var query =
from news in db.News
where news.Id == Id
let categoryNames =
from category in news.Categories
select category.Name
let commentDates =
from comment in news.Comments
select comment.CommentDate
select new {
CategoryNames = categoryNames.ToList(),
CommentDates = commentDates.ToList()
};
That query is not using SelectMany, but that wouldn't help you, since then you wouldn't be able to group your categories and comments by news items. Since categories and comments are not directly connected, you'd need two SelectManys and then you'd need to cross join the results. That would obviously not be what you want.
Maybe try using the following?
var categoryNames = news.Categories.Select(c=>c.CategoryName);
var commentDates = news.Comments.Select(c=>c.CommentDate);
Note that SelectMany is used to flatten lists.For example, lets say you have collection of news matching certain search criteria, and then you use SelectMany to collect all the Categories/Comments of these news set, in a flat list.
I have three classes: Students, Subjects and Grades.
public class Grades
{
[Key]
public int Id { get; set; }
public Student Student { get; set; }
public Subject Subject { get; set; }
public int Year { get; set; }
public string Grade { get; set; }
}
Student Class
public class Student
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string Nationality { get; set; }
}
Subject Class
public class Subject
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
}
I want to return all Grades but with properties of Student and Subject expanded, like
I can access
Grade.Name
Grade.Gender
Grade.Nationality
Grade.Year
Grade.Grade
instead of
Grade.Student.Name
Grade.Student.Gender
Grade.Student.Nationality
Use these expressions to expand your data. Note that they will not be of the Grade class but they will be anonymous class with properties you want. If you need to pass these items to other methods, you have to create explicit class that has these properties. Otherwise you may access them directly in the same method. Like, expandedGrades.First().Name.
var expandedGrades =
DBContext.Grades.Select(grade =>
new
{
Name = grade.Student.Name,
Gender = grade.Student.Gender,
Nationality = grade.Student.Nationality,
Year = grade.Year,
Grade = grade.Grade
});
or
var expandedGrades =
from grade in DBContext.Grades
select new
{
Name = grade.Student.Name,
Gender = grade.Student.Gender,
Nationality = grade.Student.Nationality,
Year = grade.Year,
Grade = grade.Grade
};
Assuming you have proper relationships set between your Students, Subjects and Grades tables. In Entity framework you can use .include to get your job done.
A basic example:
Blog blogs = context.Blogs
.Include(b => b.Posts)
.ToList();
with this now you can use blogs.Posts directly.
Reference : https://msdn.microsoft.com/en-in/data/jj574232.aspx
Title says it all, right now I have a single table that is populated from a linq query and I want to add more tables with different linq queries. I'm kinda lost on how would I do that..
I could probably do it if I create different views for each table but I want to have just one view for all. :D
Here's my code: (It's a table for "on going" projects)
Controller:
public ActionResult Index()
{
var project = from x in db.Projects
where x.Project_Status == "Ongoing"
select x;
return View(project);
}
Model:
public class Project
{
[Key]
public int Project_Id { get; set; }
public string Project_Name { get; set; }
public string Project_Detail { get; set; }
public string Project_Status { get; set; }
public int Employee_Id { get; set; }
}
View Model:
public class AdminHomeViewModel
{
public Project Ongoing { get; set; } //table for ongoing projects
public Project NYA { get; set; } //another table for Not Yet Assigned projects
public Employee Free { get; set; } //another table for free employees
public List<Project> OngoingList { get; set; }
public List<Employee> NYAList { get; set; }
public List<Employee> FreeList { get; set; }
}
You are confusing yourself with the different types of models. You should have a clear understanding between View-Model and Data-Model. You should always return View-Model to the View, and not the Data-Model. Data-Model are just the POCO classes which represents your data framework (in this case, each tables). There should be different Data Models for each of your table, which you must be having already based on your entity-framework approach (Code first, Model first or Database first). Then, prepare a single model for your view (as we can bind only one model to one view). Keep all the fields from different Data-Models that you need in that View and pass it along. See the approach below:
Data-Models
public class Project
{
[Key]
public int Project_Id { get; set; }
public string Project_Name { get; set; }
public string Project_Detail { get; set; }
public string Project_Status { get; set; }
public int Employee_Id { get; set; }
}
public class Employee
{
[Key]
public int Employee_Id { get; set; }
public string Employee_Name { get; set; }
public string Employee_Detail { get; set; }
}
View-Model
public class MyViewModel
{
public int Project_Id { get; set; }
public string Project_Name { get; set; }
public string Project_Detail { get; set; }
public string Project_Status { get; set; }
public int Employee_Id { get; set; }
public string Employee_Name { get; set; }
public string Employee_Detail { get; set; }
}
Or
public class MyViewModel
{
public Project proj { get; set; }
public Employee emp { get; set; }
}
Pass it to view as:
public ActionResult Index()
{
MyViewModel model = new MyViewModel();
// You linq query to populate model goes here
return View(model);
}
Update:
From my understanding, you need something like this:
View-Model:
public class AdminHomeViewModel
{
public AdminHomeViewModel()
{
Ongoing = new List<Project>();
NYA = new List<Project>();
Free = new List<Employee>();
}
public List<Project> Ongoing { get; set; } //table for ongoing projects
public List<Project> NYA { get; set; } //another table for Not Yet Assigned projects
public List<Employee> Free { get; set; } //another table for free employees
}
Controller:
public ActionResult Index()
{
AdminHomeViewModel model = new AdminHomeViewModel();
var result1 = (from x in db.Projects
where x.Project_Status == "Ongoing"
select new Project(){
Project_Id = x.Project_Id ,
Project_Name = x.Project_Name,
... //all other assignments goes here
}).ToList();
var result2 = (from x in db.Projects
where x.Project_Status == "blah blah"
select new Project(){
Project_Id = x.Project_Id ,
Project_Name = x.Project_Name,
... //all other assignments goes here
}).ToList();
var result3 = (from x in db.Employee
where x.AnyCondition == "blah blah"
select new Employee(){
Employee_Id = x.Employee_Id ,
Employee_Name = x.Employee_Name,
... //all other assignments goes here
}).ToList();
model.Ongoing = result1;
model.NYA = result2;
model.Free = result3;
return View(model);
}
I have made simple model for example.
public class Publisher
{
public int Id { get; set; }
public string Title { get; set; }
public Address Location { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
public class Address
{
public string Country { get; set; }
public string City { get; set; }
public string Street { get; set; }
public string HouseNumber { get; set; }
}
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public int LanguageId { get; set; }
public int? PublisherId { get; set; }
}
I need to get publishers with related books. I know how to do it using linq to entities. Is it possible to solve a problem using entity sql?
public class CatalogContext : DbContext {...}
public List<Publisher> GetByCity(string city)
{
var result = new List<Publisher>();
string queryString;
queryString = String.Format(#"SELECT VALUE row(a,b)
FROM CatalogContext.Publishers AS a
join CatalogContext.Books AS b on a.Id = b.PublisherId
WHERE a.Location.City = '{0}'", city);
var rows = ((IObjectContextAdapter)_context).ObjectContext.CreateQuery<DbDataRecord>(queryString).ToList();
return ???
}
Query returns required data but it's List<DbDataRecord> - list of pairs <publisher, book>. How to translate it to list of publishers with filled navigation property "Books"?
Is it possible to write query which directly returns List<Publisher>?
you can do the following:
var result = ObjectContext.Publishers.Include("Books").Include("Locations")
.Where(c => c.Location.City = "SOME_CITY").Select(c => c);
Include - basically joins the table.
Then you can drill down to books by doing the following:
var test = result[0].Books;
Why are you using direct sql command instead of Entity Framework code style?