How to select 2 objects from 2 tables in one query? - linq

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();

Related

EF Core - Relationship between 2 entities for non-PK columns

Here are my simplified entities for this questions:
public class Page
{
public Guid Id { get; set; }
public string PageType { get; set; }
public string PageName { get; set; }
public virtual ICollection<Section> Sections { get; set; }
}
public class Section
{
public Guid Id { get; set; }
public string SectionName { get; set; }
public string CmsContentId { get; set; }
[NotMapped]
public ICollection<CmsContentLanguage> Languages { get; set; }
}
public class CmsContentLanguage
{
public Guid Id { get; set; }
public string LangugeCode { get; set; }
public string CmsContentId { get; set; }
}
What I want to do is query my Page table and include the Sections navigation property, and for each Section the Languages property (which is not a db column) will be a collection of CmsContentLanguages. The response from my query would look like this:
{
"id":"6b3c680a-a5aa-4782-80ce-591f1d16abe2",
"pageName":"Description",
"pageType":"content",
"sections":[
{
"id":"e688b09e-9b1c-4094-aa04-cd044c820630",
"sectionName":"Introduction",
"cmsContentId ":"e1ad5dca-c74b-497e-856b-bf26a699e635",
"languages":[
{
"id":"11e19169-797c-4b6a-b5e8-2bdb9c1f28cc",
"languageCode":"en",
"cmsContentId ":"e1ad5dca-c74b-497e-856b-bf26a699e635"
},
{
"id":"19a0f31c-4b96-4afe-920f-40cea544eeab",
"languageId":"es",
"cmsContentId ":"e1ad5dca-c74b-497e-856b-bf26a699e635"
}
]
},
{
"id":"a53b9ace-b9a7-407d-b641-7a3c46077428",
"sectionName":"FAQs",
"cmsContentId ":"e1ad5dca-c74b-497e-856b-bf26a699e635",
"languages":[
{
"id":"11e19169-797c-4b6a-b5e8-2bdb9c1f28cc",
"languageCode":"en",
"cmsContentId ":"e1ad5dca-c74b-497e-856b-bf26a699e635"
},
{
"id":"19a0f31c-4b96-4afe-920f-40cea544eeab",
"languageId":"es",
"cmsContentId ":"e1ad5dca-c74b-497e-856b-bf26a699e635"
}
]
}
]
}
Multiple Section records can have the same CmsContentId value. Section.Languages is not a navigation property (nor do I think it should be).
Then I want to do a Linq query like this:
var guidId = Guid.Parse("6b3c680a-a5aa-4782-80ce-591f1d16abe2");
var query = dbContext.Pages
.Include(x => x.Sections)
.FirstOrDefault(p => p.Id == guidId);
At this point I have the response data I want, but the Languages property of each Section entity is null. This is where I'm lost as to how to setup relationships or do a query to get this data.
You are looking for the ThenInclude method. Here is how you use it.
var query = dbContext.Pages
.Include(x => x.Sections)
.ThenInclude(x => x.Languages)
.FirstOrDefault(p => p.Id == guidId);

Entity Framework Core 2 querying multi level collections with theniclude

I created two classes:
public class A {
public int Id { get; set; }
public ICollection<B> Bs { get; set; }
}
public class B {
public ICollection<C> C1s { get; set; }
public ICollection<C> C2s { get; set; }
}
then I tried to fetch them with ThenInclude method:
var result = context.As //public DbSet<A> As { get; set; }
.Include(a => a.Bs)
.ThenInclude(b => b.C1s)
.Include(a => a.Bs)
.ThenInclude(b => b.C2s)
.SingleOrDefaultAsync(a => a.Id.Equals(id)); //id is given
return await result;
But unfortunately both C1s and C2s collections are empty.
How to retrieve C entities which are related to B one?
I replaced .ThenInclude() methods with
.Include("Points.MasterPoints")
.Include("Points.SlavePoints")
That solved my issue.

Linq ORM map Object to 3 level Object

I have object like this. This include Group Question (QG), 1 group question has many Question(Q), 1 question has many answer.
public class CrmQuestionAnswer
{
public long QgId { get; set; }
public string QgName { get; set; }
public int QgMIndex { get; set; }
public int QgMdf { get; set; }
public string QgDescription { get; set; }
public long QId { get; set; }
public long QParentId { get; set; }
public string QName { get; set; }
public string QDescription { get; set; }
public int QMindex { get; set; }
public int QMdf { get; set; }
public bool IsMainQuestion { get; set; }
public bool IsTitle { get; set; }
public int QTypeId { get; set; }
public long AnswerId { get; set; }
public string AnswerName { get; set; }
public string AnswerValue { get; set; }
public int AnswerMdf { get; set; }
public int AnswerMIndex { get; set; }
public string AnswerDescription { get; set; }
public long? LinkQuestionId { get; set; }
}
I want to use Linq to map List CrmQuestionAnswer to List QuestionGroupView
public class QuestionGroupView:Title
{
public List<CrmQuestionView> Questions;
}
public class CrmQuestionView: Title
{
public long? ParentId;
public bool? IsMainQuestion;
public bool? IsTitle;
public long? LinkQuestionId;
public List<CrmAnswerView> Answers;
}
public class CrmAnswerView : Title
{
public long? LinkQuestionId;
}
Title is base class:
public class Title
{
public long Id { get; set; }
public string Name { get; set; }
public int MIndex { get; set; }
public int Mdf { get; set; }
public int Type { get; set; }
public string Description { get; set; }
}
I use this code:
public List<QuestionGroupView> GetListQuestionsAnswers(long themaId)
{
var questionAnswerDao = new CrmQuestionAnswerDao();
var questionAnswerlist = questionAnswerDao.GetByThemasId(themaId);
//map List CrmQuestionAnswer -> List QuestionGroupView: 3 level
var listquestiongroup = questionAnswerlist
.OrderBy(t => t.QgMIndex)
.ThenBy(t => t.QMindex)
.GroupBy(t => t.QgId)
.Select(GetQuestionGroup)
.ToList();
return listquestiongroup;
}
private static QuestionGroupView GetQuestionGroup(IGrouping<long, CrmQuestionAnswer> grouping)
{
var group = grouping.First();
var question = new QuestionGroupView
{
Id = group.QgId,
Name = group.QgName,
Description = group.QgDescription,
Mdf = group.QgMdf,
MIndex = group.QgMIndex,
Questions = grouping
.Select(p => new CrmQuestionView
{
Id = p.QId,
Name = p.QName,
Description = p.QDescription,
Mdf = p.QMdf,
MIndex = p.QMindex,
Type = p.QTypeId,
ParentId = p.QParentId,
IsMainQuestion = p.IsMainQuestion,
IsTitle = p.IsTitle,
Answers = grouping//**This line is wrong**
.GroupBy(g => g.QId)
.Select(GetTitle)
.ToList()
})
.ToList()
};
return question;
}
private static CrmAnswerView GetTitle(IGrouping<long, CrmQuestionAnswer> grouping)
{
var group = grouping.First();
var answer = new CrmAnswerView
{
Id = group.AnswerId,
Name = group.AnswerName,
Description = group.AnswerDescription,
MIndex = group.AnswerMIndex,
Mdf = group.AnswerMdf,
Type = group.QTypeId,
LinkQuestionId = group.LinkQuestionId,
};
return answer;
}
This is data get from server Data
My code gets right Group question (2 group) with right List question, but it gets wrong list answer from data.
Can some help me ?
Best regards

Get data Self reference

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
}
}

How to build a complex View Model

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)
{
...
}
}

Resources