I was wondering if anyone could help me with the building of my View Model...
I have three parent models, Users, Profiles, and Projects
On a view, I would like to pass a model that has the user's information, their profile information, and their projects information...
So far my View Model looks like this...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace ProDevPortMVC3.ViewModels
{
public class PortfolioViewModel
{
public int ProfileID { get; set; }
public int UserID { get; set; }
public string ProfileFirstName { get; set; }
public string ProfileLastName { get; set; }
public string ProfileEmail { get; set; }
public Nullable<long> ProfileContactNo { get; set; }
public string ProfileCity { get; set; }
public string ProfileState { get; set; }
public string ProfileCountry { get; set; }
public string ProfilePhotoPath { get; set; }
public string ProfilePhotoName { get; set; }
public string ProfileBio { get; set; }
public string ProfileMissionStatement { get; set; }
public string ProfilePrivacySetting { get; set; }
public IEnumerable<ProfileBlog> ProfileBlogs { get; set; }
public IEnumerable<ProfileForum> ProfileForums { get; set; }
public IEnumerable<Project> Projects { get; set; }
}
}
The problem is that the Projects model/table has one-to-many child tables... and I need all of their information as well in the View Model... Here are the child tables...
ProjectCodeSamples
ProjectDownloads
ProjectScreenShots
ProjectTechnologiesUseds
Here is my Controller Action Method thus far...
public ActionResult Index(int id)
{
var profile = db.Profiles.SingleOrDefault(p => p.UserID == id);
var profileBlogs = db.ProfileBlogs.Where(p => p.ProfileID == profile.ProfileID);
var profileForums = db.ProfileForums.Where(p => p.ProfileID == profile.ProfileID);
var projects = db.Projects.Where(p => p.ProfileID == profile.ProfileID);
var viewModel = new PortfolioViewModel
{
ProfileFirstName = profile.ProfileFirstName,
ProfileLastName = profile.ProfileLastName,
ProfileEmail = profile.ProfileEmail,
ProfileContactNo = profile.ProfileContactNo,
ProfileCity = profile.ProfileCity,
ProfileState = profile.ProfileState,
ProfileCountry = profile.ProfileState,
ProfilePhotoPath = profile.ProfilePhotoPath,
ProfilePhotoName = profile.ProfilePhotoName,
ProfileBio = profile.ProfileBio,
ProfileMissionStatement = profile.ProfileMissionStatement,
ProfilePrivacySetting = profile.ProfilePrivacySetting,
ProfileBlogs = profileBlogs.Where(p => p.ProfileID == profile.ProfileID),
ProfileForums = profileForums.Where(p => p.ProfileID == profile.ProfileID),
Projects = projects.Where(p => p.ProfileID == profile.ProfileID)
};
return View(viewModel);
}
So, how do I continue or what do I do from here?
EDIT: I forgot to add that the Project Child Tables have a foreign key ProjectID that connect them to the Projects table...
Here is the final View code for it to work...
#foreach (var item in Model.Projects)
{
<p>
#Html.DisplayFor(modelItem => item.ProjectName)
</p>
foreach (var subItem in item.ProjectDownloads)
{
<pre>
#Html.DisplayFor(modelItem => subItem.ProjectDownloadPath)
</pre>
}
}
Since you use the Project model in your ViewModel you can simply access the Project's child tables in the view.
For example, you should be able to do the following:
foreach(var item in model.Projects)
{
foreach(var download in item.ProjectDownloads)
{
...
}
}
Related
I have the classes below:
public class User
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public class ParentEntity
{
public Guid Id { get; set; }
public string SomeProperty { get; set; }
public ICollection<ChildEntity> ChildEntities { get; set; }
}
public class ChildEntity
{
public Guid Id { get; set; }
public int Vote { get; set; }
public Guid UserId { get; set; }
}
public class ReturnedParentDto
{
public Guid Id { get; set; }
public string SomeProperty { get; set; }
public int Vote { get; set; }
}
I want to be able to return a full list of ParenEntities, but take an Id of the User class (UserClassId), then filter the ParentEntity's ICollection where UserUid = UserClassId, so only 1 ChildEntity is always returned. Then I would want to extract a specific field from that returned ChildEntity and merge it with the ParentEntity fields. The end result should be like the ReturnedParentDto.
I want to do it in the style like
ParentEntities.Include(v => v.ChildEntities).ToList()
That seems to be possible in EF Core 5, but my project is in 3.1.
You can do this as below
Approach 1:
var result = result = parentEntities.Include(x => x.ChildEntities.Where(y => y.UserId == userId))
.Select(x => new ReturnedParentDto {
Id = x.Id,
SomeProperty = x.SomeProperty,
Vote = x.ChildEntities.FirstOrDefault()?.Vote // userId is the variable here
});
Approach 2:
var result = parentEntities.Select(x =>
new ReturnedParentDto {
Id = x.Id,
SomeProperty = x.SomeProperty,
Vote = x.ChildEntities.FirstOrDefault(y => y.UserId == userId)?.Vote // userId is the variable here
});
I want to get the below result in one query by linq methods such as .Where, .Select etc., is it possible?
Inner join is the better.
new {
Blog = MyDbContext.Blogs.SingleOrDefault(b => b.Url == "xxx.com"),
Post = MyDbContext.Posts.SingleOrDefault(p => p.Blog.Url == "xxx.com" &&
p.Author == "Jack")
}
Models:
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Author { get; set; }
public Blog Blog { get; set; }
}
public class MyDbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
var ans = MyDbContext.Blogs.Where(b => b.Url == "xxx.com")
.Select(b => new {
Blog = b,
Post = b.Posts.Where(p => p.Author == "Jack").FirstOrDefault()
})
.SingleOrDefault();
This is my Entity model class which was auto generated by Ado.net model
public partial class SubModule
{
public int SubModuleId { get; set; }
public Nullable<int> ModuleId { get; set; }
public string SubModuleName { get; set; }
public Nullable<bool> Active { get; set; }
public Nullable<bool> IsModules { get; set; }
public string url { get; set; }
public string path { get; set; }
public string subform { get; set; }
}
this is my another class
public class ChildModules
{
public int ? SubModuleId { get; set; }
public Nullable<int> ModuleId { get; set; }
public string SubModuleName { get; set; }
public Nullable<bool> Active { get; set; }
public Nullable<bool> IsModules { get; set; }
public string url { get; set; }
public string path { get; set; }
public string subform { get; set; }
}
I want to copy Sub modules data to my Child modules class properties
My code is
List<SubModule> ChildModule = entity.SubModules.Where(x => x.IsModules == false).ToList();
List<ChildModules> listchildmodules = new List<ChildModules>();
ChildModules chmodule = new ChildModules();
foreach (SubModule mod in ChildModule)
{
chmodule.SubModuleId = mod.SubModuleId;
chmodule.ModuleId = mod.ModuleId;
chmodule.SubModuleName = mod.SubModuleName;
chmodule.Active = mod.Active;
chmodule.IsModules = mod.IsModules;
chmodule.url = mod.url;
chmodule.path = mod.path;
chmodule.subform = mod.subform;
listchildmodules.Add(chmodule);
}
but in listchildmodules last row insert in every index.
Why?
Your code always add the same object always. Because you always updating the values of same object and insert that into list.
Keep the below line of code inside foreach.
ChildModules chmodule = new ChildModules();
Your foreach should look like below
foreach (SubModule mod in ChildModule)
{
ChildModules chmodule = new ChildModules();
chmodule.SubModuleId = mod.SubModuleId;
chmodule.ModuleId = mod.ModuleId;
chmodule.SubModuleName = mod.SubModuleName;
chmodule.Active = mod.Active;
chmodule.IsModules = mod.IsModules;
chmodule.url = mod.url;
chmodule.path = mod.path;
chmodule.subform = mod.subform;
listchildmodules.Add(chmodule);
}
Or you could declare ChildModules chmodule; outside foreach and initialize chmodule = new ChildModules(); inside foreach loop.
I have a self reference model.
I want get data with linq.i want when status is ok return data.but if parent status is ok all of child return ok or pending or deleted.
how can i do this.
var model = _efComment.List(p => p.PostId == postId);
var list = model.ToList()
.Where(p => p.ComentStatus == ComentStatus.Ok)
.Where(x => x.Reply == null)
.ToList();using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using DomainModel.Classes;
namespace DomainModel
{
public class Comment : BaseFieldsTables
{
public string Content { get; set; }
public string WriterName { get; set; }
public string WriterEmail { get; set; }
public string WriterWebsite { get; set; }
public int PostId { get; set; }
[ForeignKey("PostId")]
public Post Post { get; set; }
public Comment Reply { set; get; }
public int? ReplyId { get; set; }
public ICollection<Comment> Children { get; set; }
public ComentStatus ComentStatus { get; set; }
}
}
namespace DomainModel
{
public enum ComentStatus
{
Ok = 1,
Pending = 2,
Deleted = 3
}
}
public class Project
{
public virtual int ID { get; set; }
[Required]
public virtual String Title { get; set; }
public String Definition { get; set; }
public DateTime StartDate { get; set; }
[Required]
public int CreaterID { get; set; }
public virtual ICollection<Status> Status { get; set; }
public virtual ICollection<Task> Tasks { get; set; }
public virtual ICollection<User> Users { get; set; }
public Project()
{
Users = new HashSet<User>();
}
}
public class User
{
public int ID { get; set; }
[DisplayName("Kullanıcı Adı")]
[Required]
[MinLength(5, ErrorMessage = "Kullanıcı Adı En Az 5 Karakter Olmalıdır")]
public string username { get; set; }
[DataType(DataType.Password)]
[DisplayName("Şifre")]
[Required]
[MinLength(3,ErrorMessage="Şifre En Az 3 Karakter Olmalıdır")]
public string password { get; set; }
[Required]
public String Name { get; set; }
[Required]
public String Surname { get; set; }
public int? CreaterID { get; set; }
public int level { get; set; }
public ICollection<Task> Tasks { get; set; }
public ICollection<Project> Projects { get; set; }
public User()
{
Projects = new HashSet<Project>();
}
}
public class TaskDB : DbContext
{
public DbSet<Comment> Comments { get; set; }
public DbSet<Project> Projects { get; set; }
public DbSet<Situation> Situaitons { get; set; }
public DbSet<Task> Tasks { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Project>().
HasMany(c => c.Users).
WithMany(p => p.Projects).
Map(
m =>
{
m.MapLeftKey("ProjectId");
m.MapRightKey("UserId");
m.ToTable("ProjectUser");
});
}
}
If I add project , current user added to project users list but project not added current user's projects list
This is my project add code
[HttpPost]
public ActionResult Create(Project proje,Status status)
{
proje.StartDate = DateTime.Now;
proje.Status = new HashSet<Status>();
var user = _db.Users.Single(r=> r.ID == UserRole.ID);
proje.Users.Add(user);
proje.Status.Add(status);
user.Projects.Add(proje);
if (ModelState.IsValid)
{
var projeler = _db.Projects;
projeler.Add(proje);
_db.SaveChanges();
return RedirectToAction("Index");
}
return View(proje);
}
I Search this problem's cause I did not find , I want to learn why entity framework add user to project's list but not add project to user's list
Your code to add the new project to the database looks correct and the relationship is most likely stored.
But possibly you don't load the Projects list with a User. If you call...
var project = _db.Projects.Single(p => p.ID == 1);
var users = project.Users; // lazy loading because Users is virtual
...you will see the project's users because they get lazily loaded since the Project.Users property is marked as virtual. If you do the same with a User...
var user = _db.Users.Single(u => u.ID == 1);
var projects = user.Projects; // no lazy loading because Projects is not virtual
...the projects don't get loaded because the User.Projects property is not marked as virtual.
Either mark the property as virtual as well to enable lazy loading for the User.Projects collection:
public virtual ICollection<Project> Projects { get; set; }
Or use eager loading:
var user = _db.Users.Include(u => u.Projects).Single(u => u.ID == 1);