How to query a child object - c#

public class Employee
{
public int Id { get; set; }
public string Title { get; set;}
//....other fields....
//......
//public Topics Interest { get; set; }
public IList<Topics> Interests { get; set; }
}
public class Topics
{
public int Id { get; set; } ;
public string Name { get; set; } ;
//other fields
}
public static IQueryable<EmployeeObject> QueryableSQL()
{
IQueryable<EmployeeObject> queryable = EmployeeRepository.GetAllEmployee();
}
My above data structure has Employee and within it has multiple interests and each interest has multiple topics
My Question is:
How would i search Employee.Interests.Name ?
//i need help construct the linq....
//the below will not work and look for something in the `EmployeeObject` rather in `Interests`
IList<EmployeeObject> _emps = QueryableSQL().Where(x => x.Name== "Chess").ToList();

It depends on what you want. Do you want items where any of their interests match a given value?
var query = QueryableSQL().Where(employee =>
employee.Interests.Any(interest => interest.Name == "Chess"));
When you've been able to explain in English the query that you want the translation to LINQ will be a lot easier.

You can use Any on the child collection to find matching EmployeeObjects
IList<EmployeeObject> _emps =
QueryableSQL().Where(x => x.Interests
.Any(i => i.Name== "Chess"))
.ToList();

Related

Using .Select to get single item from sub list, then assigning individual properties of that item to view model

I have pretty much solved this problem but I am wondering whether there is a more efficient way of doing this using Entity framework / SQL.
Essentially, what i am doing is performing a subquery to get a SINGLE item on a list of objects that are connected to a parent entity. I then want to extract only a few columns from that single entity.
The first way, which doesn't work but shows my possible thought process was to put each object into a temporary variable and then create the view:
_context.IcoInfos.Select((i) =>
{
var reward = i.SocialRewards.OrderByDescending(s => s.EndDate).FirstOrDefault();
return new IcoInfoRewardCountViewModel()
{
CampaignName = i.Name,
CurParticipants = reward.CurParticipants,
Title = reward.CustomTitle,
IsLive = reward.IsLive
};
});
The second way, which works, I am creating a temporary model which stores the single database row of the sublist result...
_context.IcoInfos.Select((i) => new
{
Reward = i.SocialRewards.OrderByDescending(s => s.EndDate).FirstOrDefault(),
IcoName = i.Name
}).Select(t => new IcoInfoRewardCountViewModel()
{
CampaignName = t.IcoName,
CurParticipants = t.Reward.CurParticipants,
Title = t.Reward.CustomTitle,
IsLive = t.Reward.IsLive
}).ToList();
My question is, is this second way the only/best way to achieve this?
Your second approach is ok but for bigger application will cause you trouble if application growth larger and you have a lot information to store in the model.
So I think you can use automapper to make your code more clean.
Example
To use autoampper I need to define a model class and DTO class that share some same properties.
public class Comment
{
public string Content { get; set; }
public virtual Comment ParentComment { get; set; }
public virtual Post Post { get; set; }
public virtual User? User { get; set; }
public CommentStatus CommentStatus { get; set; }
}
public class CommentDto
{
public int Id { get; set; }
public Guid UniqeId { get; set; }
public string Content { get; set; }
public Comment ParentComment { get; set; }
public CommentStatus CommentStatus { get; set; }
public DateTime DateCreated { get; set; }
}
I also need to define the profile class to register mapping
public class CommentProfile : Profile
{
public CommentProfile()
{
CreateMap<Comment, CommentDto>(MemberList.None).ReverseMap();
}
}
Then I will need to register into DI container in startup.cs
services.AddAutoMapper();
Then I can use like this
var comments = await _unitOfWork.Repository<Comment>().Query()
.Include(x => x.User)
.Include(c => c.Post)
.Select(x => new CommentViewModel
{
Comment = _mapper.Map<Comment, CommentDto>(x),
})
.ToListAsync();
It will make the code more clear and I dont have to do manual mapping

How to get last Id that contain HardwarId

I got an issue to reclaim Hardware that has exact ID (e.g. ID=5). There is my code:
class HardwareTransfer{
public int Id { set; get; }
public ICollection<Hardware> Hardwares { get; set; }
}
class Hardware{
public int Id { set; get; }
public string Title { set; get; }
}
How to get last HardwareTransfer.Id of HardwareTransfer, that contains Hardwares.Id = 5?
you can use this code
//_listHardwareTransfer is a List Of HardwareTransfer
var maxId=_listHardwareTransfer.Where(x => x.Hardwars.Contains(5)).Max(x => x.Id);
There are several ways how you can obtain this. By using LINQ (preferred way):
myHardwareTransfer.Hardwares.Last(a => a.Id == 5);
In C#:
Hardware lastFound;
foreach(var nHardware in myHardwareTransfer.Hardwares)
if(nHardware.Id == 5)
lastFound = nHardware;

Filtering object containing objects from another table using linq c#

I have what seems like a simple problem, but can't wrap my head around it.
I have two tables, one contains questions, one responses. These are mapped together such that one question has many allowedResponses. EntityFramework handles this mapping very nicely, so when I call the controller to GetQuestions, I get back a lovely set of questions wach containing their pertinent responses.
We recently expanded the system to include two user groups - A and B in this example. Some questions and some responses are only valid for certain groups. So each question has a showToA showToB property - this works fine using a simple linq.where query. However I cannot figure out how to call getQuestions with the parameter showToGroupA and have it return the questions AND responses ONLY pertinent to the specified group.
I essentially want to be able to get all the relevant questions, and strip out any irrelevant responses.
Any help greatly appreciated, thank you.
public class Question
{
[Key]
public int ID { get; set; }
public int QID { get; set; }
public string question { get; set; }
public string type { get; set; }
public virtual List<AllowedResponses> AllowedResponse { get; set; }
public int PrimaryOrderNo{ get; set; }
public int SecondaryOrderNo{ get; set; }
public bool ShowToGroupA{ get; set; }
public bool ShowToGroupB{ get; set; }
}
//Model of allowed responses to questions
public class AllowedResponses
{
[Key]
public int ID { get; set; }
public virtual int QID { get; set; }
public string Response { get; set; }
public int ResponseID { get; set; }
public bool ShowToGroupA { get; set; }
public bool ShowToGroupB { get; set; }
}
At the moment I simply return a list of questions, sorted by the appropriate order, and filtered by whether or not the question should be displayed to the group - NOT filtering the AllowedResponses.
List<Questions> Questions = _repo.GetQuestions();
Questions = Questions.OrderBy(x => x.GroupAOrderNo).ToList();
List<Questions> QuestionsFiltered;
if (GroupAorB == "A")
{
QuestionsFiltered = Questions.Where(a => a.ShowToA == true).ToList();
} else
{
QuestionsFiltered = Questions.Where(a => a.ShowToB == true).ToList();
}
return Request.CreateResponse(HttpStatusCode.OK, Questions);
Please note i have simplified the code here and changed some names, excuse any resulting breakdown in logic.
You could filter out your response in a new object something like:-
List<Questions> Questions = _repo.GetQuestions();
Questions = Questions.OrderBy(x => x.GroupAOrderNo).ToList();
var FilteredQuestions =
Questions.Where(a => GroupAorB == "A" ? a.ShowToGroupA : a.ShowToGroupB).Select(q => new Question
{
ID = q.ID,
AllowedResponse =
q.AllowedResponse.Where(r => GroupAorB == "A" ? r.ShowToGroupA : r.ShowToGroupB).ToList()
}).ToList();
return Request.CreateResponse(HttpStatusCode.OK, Questions);

Assign aggregate result to the entity property not pulling all subquery rows

I have a Comment and Votes related to the comment.
[Table("QAComment")]
public class QaComment : IEntity
{
[Key, Column("QACommentID")]
public int Id { get; set; }
// ...
public virtual ICollection<QaCommentVote> Votes { get; set; }
[NotMapped]
public int OverallVote { get; set; }
}
[Table("QACommentVote")]
public class QaCommentVote : IEntity
{
[Key, Column("QACommentVoteID")]
public int Id { get; set; }
[ForeignKey("QAComment")]
public int QaCommentId { get; set; }
public int Value { get; set; }
public virtual QaComment QaComment { get; set; }
}
I need to get comments with the sum of their votes, not pulling all votes to the application.
The ways I can see to achive this:
1. Make a database view for Commment and calc votes sum in there.
Cons: dont wanna make extra-views
2. Via LINQ:
var comments =
Set<QaComment>()
.Select(c => new QaComment() {/* assign every property once again and calc OverallVote */});
Cons: don't like to assign allproperties once again.
Is there a better way devoid of that cons?
UPDATE
This is what I want as a result of LINQ:
SELECT
qac.*,
(SELECT SUM(v.Value)
FROM QACommentVote v
WHERE v.QACommentID = qac.QACommentID) as OverallVote
FROM QAComment qac
You can fetch QaComment and the sum you're looking for separately as anonymous type and merge them into one object using LINQ to Objects:
var comments
= Set<QaComment>()
.Select(c => new { c, sum = c.Votes.Sum(v => v.Value))
.AsEnumerable() // to make next query execute as LINQ to Objects query
.Select(x => { x.c.OverallVote = x.sum; return x.c; })
.ToList();
But to make point clear: I haven't tested that :)

Joining two tables with one to many relatipnship in entity framework code first

i have
public class Menu
{
public int ID { get; set;}
public List<Task> Tasks { get; set; }
}
public class Task
{
public int ID { get; set; }
public byte[] Image { get; set; }
public string Name { get; set; }
}
i would like to know all tasks which has a certain List ID using LINQ queries
Try
var result = Menus.Where(menu => menu.ID == id)
.Select(menu => menu.Tasks)
.FirstOrDefault();
Also you may want to peruse http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b as this would answer most of your queries like the above.
You can use Enumerable.Where
var list = Tasks.Where(l=>l.ID ==x);
or
var list = from t in Tasks
where t.ID == x
select t;
x will be the id you need to compare

Categories

Resources