LINQ query: restrict child entity - c#

I'm novice in LINQ, so I need an initial help how to simplify writing of LINQ queries. Here my scenario: I have two tables C_Systemtype with 1:M relationship to CT_Systemtype, using database first approach.
Class C_System:
{
public string SystemtypeId { get; set; }
public bool Is_productive { get; set; }
public bool Is_systemown { get; set; }
public bool Is_active { get; set; }
public byte[] Icon { get; set; }
public virtual ICollection<CT_Systemtype> CT_Systemtype { get; set; }
public virtual ICollection<C_System> C_System { get; set; }
}
Class CT_Systemtype:
{
public string SystemtypeId { get; set; }
public string LanguageId { get; set; }
public string Title { get; set; }
public string Descript { get; set; }
public virtual C_Systemtype C_Systemtype { get; set; }
public virtual S_Language S_Language { get; set; }
}
I like to select all C_Systemtype but with CT_Systemtype restricted to a given LanguageId.
I believe the following LINQ query is working (p_langId is my parameter):
using (var db = new PaltrConnect())
{ var query = from s in db.C_Systemtype
join t in db.CT_Systemtype on s.SystemtypeId equals t.SystemtypeId
where t.LanguageId == p_langId
select new { s.Is_productive,
s.Is_systemown,
s.Is_active,
s.Icon,
s.CT_Systemtype }
}
The result is of type anonymous. My intention is something like C_Systemtype.Include(t => t.CT_Systemtype) but with additional restriction on CT_Systemtype.
How can I rewrite this query in such a way that I don't have to give each property in the select part and to finally map individual properties?

using (var db = new PaltrConnect())
{
var query = from s in db.C_Systemtype
join t in db.CT_Systemtype on s.SystemtypeId equals t.SystemtypeId
where t.LanguageId == p_langId
select s ;/*s is your C_Systemtype*/
}

Because you are joining two tables together you can't just return a single type. To prevent having to map each property in the select you can use something like AutoMapper.

Related

nHibernate.IQueryOver removing sub class left join

I have a query with an inner join between two objects (BagDto and ItemDto) where ItemDto also has at least one parent with type of LocationDto. Here are the class definitions:
public class BagDto
{
public int Id { get; set; }
public string Color { get; set; }
public string Type { get; set; }
public DateTime CreatedDate { get; set; }
/* other properties for bag comming from oracle DB */
public IEnumerable<ItemDto> Items { get; set; }
}
public class ItemDto
{
public int Id { get; set; }
public int BagId { get; set; }
public int LocationId { get; set; }
public string Type { get; set; }
public DateTime AddDate { get; set; }
public BagDto Bag { get; set; }
public LocationDto Location { get; set; }
}
public class LocationDto
{
public int Id { get; set; }
public string Name { get; set; }
public double SquareMeters { get; set; }
public string CountyName { get; set; }
public virtual IEnumerable<ItemDto> Items { get; set; }
}
In my query I do not want any kind of Location data to get and only BagDto and ItemDto is really what I would like to query. The mapping of all three objects are okay and I do not want to change those. I also would not like to create inheritance to separate LocationDto out (ie.: ItemDto will not contains LocationDto but ItemWithLocationDto will).
Here is the query:
public IEnumerable<BagDto> GetBagsWithAvailableType()
{
ItemDto itemDtoAlias = null;
Session.QueryOver<BagDto>()
.Where(x.CreatedDate <= DateTime.UtcNow)
.JoinAlias(x => x.Items, () => itemDtoAlias, NHibernate.SqlCommand.JoinType.InnerJoin)
.Where(
() => itemDtoAlias.Type == "A")
.List();
}
Using nHibernate Profiler the following query is generated:
SELECT this_.ID,
this_.COLOR,
this_.TYPE,
this_.CREATEDDATE,
item1_.ID,
item1_.BAG_ID,
item1_.LOCATION_ID,
location2_.ID,
location2_.NAME,
location2_.SQUAREMETERS,
location2_.COUNTYNAME
FROM BAG this_
inner join ITEM item1_
on this_.ID = item1_.BAG_ID
left outer join LOCATION location2_
on item1_.LOCATION_ID = location2_.ID
WHERE (this_.CREATEDDATE <= TIMESTAMP '2021-04-07 16:23:54')
and (item1_.TYPE = 'A')
Anybody knows a way how to get rid of the left outer join related to the LOCATION? I would like to specify this in the query but google all the day for it still no solution. Thanks for the help!
P. S.: writting all this query in plain SQL and call it from the code is a bad practice. Our codeguides are not allowing that.
Without mappings it's not clear why Location is added to the query in a first place. Assuming it's added due to fetch="join" mapping for Location property you can skip it in a query with SelectMode.Skip (available since NHibernate 5.2):
ItemDto itemDtoAlias = null;
Session.QueryOver<BagDto>()
.Where(x.CreatedDate <= DateTime.UtcNow)
.JoinAlias(x => x.Items, () => itemDtoAlias, NHibernate.SqlCommand.JoinType.InnerJoin)
.Fetch(SelectMode.Skip, () => itemDtoAlias.Location)
...
See description of all SelectMode options here

How to name the intermediate entity lists in a LINQ query?

I need help with a specific LINQ query. I couldn't find a way to group intermediate entities and use them in my select statement.
The domain: We have a list of criteria Questions to assess Projects. There are Assessors that assess the projects and give them QuestionScores which include notes. When an assessor is assessing a project, they should be able to see other assessor's notes. Assessors also are able to reassess, then they also see their previous note.
I wrote the following query for this that will return a list of QuestionModels, however, I don't know how to fill some of the parts.
string assessorId = "assessor_id_0";
string projectId = "project_id_0";
var query =
from question in _context.Questions
join questionScore in _context.QuestionScores on question.Id equals questionScore.QuestionId
join assessment in _context.Assessments on questionScore.AssessmentId equals assessment.Id
where assessment.ProjectId == projectId
select new QuestionModel
{
Id = question.Id,
QuestionOrder = question.QuestionOrder,
QuestionText = question.QuestionText,
SelfNote = null, // Assessor's old note
OtherNotes = null // Other assessors' notes
};
How do I fill the null parts?
Here are my domain classes:
public class Question
{
public string Id { get; set; }
public int QuestionOrder { get; set; }
public string QuestionText { get; set; }
}
public class QuestionScore
{
public string Id { get; set; }
public string AssessmentId { get; set; }
public string QuestionId { get; set; }
public string AssessmentNote { get; set; }
}
public class Assessment
{
public string Id { get; set; }
public string ProjectId { get; set; }
public string AssessorId { get; set; }
}

LINQ to Entities does not recognize the method ..., and this method cannot be translated into a store expression

My function is as on lambda expression
public IList<ent_Message> messageDetailsArray(decimal from,decimal to)
{
owncibai_ExamEntities db = new owncibai_ExamEntities();
var details = db.Messages.OrderBy(or=>or.mDate).Where(wh => (wh.userNumber==from && wh.messageTo==to) || (wh.messageTo==from && wh.userNumber==to)).Select(a => new ent_Message
{
isRead = a.isRead,
mDate = a.mDate,
Message1 = a.Message1,
messID = a.messID,
userNumber = a.userNumber,
messageTo=a.messageTo,
Name=a.User.First_Name+" "+a.User.Last_Name,
photo = (db.MessagePhotoes.Where(ph => ph.messID == a.messID).Select(b => new ent_MessagePhoto
{
msgPhoto=b.msgPhoto,
srl=b.srl
})).ToList()
}).ToList();
var update = db.Messages.Where(wh => wh.messageTo == from).ToList();
update.ForEach(a => a.isRead = true);
db.SaveChanges();
return details;
}
It works fine when I remove Photo parameter from list. While I add photo it is giving following error.
LINQ to Entities does not recognize the method 'System.Collections.Generic.List1[Entities.ent_MessagePhoto] ToList[ent_MessagePhoto](System.Collections.Generic.IEnumerable1[Entities.ent_MessagePhoto])' method, and this method cannot be translated into a store expression.
Entity class is as follows
public class ent_Message{
public decimal messID { get; set; }
public Nullable<decimal> userNumber { get; set; }
public Nullable<decimal> messageTo { get; set; }
public Nullable<System.DateTime> mDate { get; set; }
public string ip { get; set; }
public string Message1 { get; set; }
public Nullable<bool> isRead { get; set; }
public Nullable<decimal> parentID { get; set; }
public string Name { get; set; }
public IList<ent_MessagePhoto> photo { get; set; }
}
I am totally confused where I am wrong in photo...
Thanks in advance
This bit:
photo = (db.MessagePhotoes.Where(ph => ph.messID == a.messID).Select(b => new ent_MessagePhoto
{
msgPhoto=b.msgPhoto,
srl=b.srl
})).ToList() //<-right here
appears inside your outer Select clause. When the IQueryProvider tries to convert your outer Select statement to valid SQL, it will see an inner Select, which of course can be converted to SQL, but then it will hit the ToList() call and fail, because there is no equivalent in SQL.
If you want to perform some operations in your Select projection that can't be done in SQL, they need to be done against the query result set in-memory on the .NET application side. One common way to do this is to put a ToList() before your select statement - this will be interpreted as "send the Where and OrderBy parts to SQL, bring the full result set back into a List, then perform the Select projection".
ent_MessagePhoto must be in the class definition
public class ent_Message<ent_MessagePhoto>
{
public decimal messID { get; set; }
public Nullable<decimal> userNumber { get; set; }
public Nullable<decimal> messageTo { get; set; }
public Nullable<System.DateTime> mDate { get; set; }
public string ip { get; set; }
public string Message1 { get; set; }
public Nullable<bool> isRead { get; set; }
public Nullable<decimal> parentID { get; set; }
public string Name { get; set; }
public IList<ent_MessagePhoto> photo { get; set; }
}​
Thanks for your suggestion I resolved this issue. Issue was version only. I was using 5.x and updated to 6.x and working fine.

How to query with a join with linq to sql

I'm trying to query for gifts given a term from my categories table. Entity Framework created a bridge table to connect my "Gift" with my "GiftCategroies". But the query I have yielded no results.
From DbContext:
public DbSet<Gift> Gifts { get; set; }
public DbSet<GiftCategory> Categories { get; set; }
The two entities I created:
public class Gift
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<GiftCategory> Categories { get; set; }
public int Rating { get; set; }
}
public class GiftCategory
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<Gift> Gifts { get; set; }
}
Here is my query to try and fetch the gifts given a giftcategory term. No results returned. I'm not sure if I even need a join for this type of query.
var model =
from gifts in db.Gifts
join giftCategory in db.Categories on gifts.Id equals giftCategory.Id
where giftCategory.Name.Contains(searchTerm)
select gifts;
You should use navigation properties instead of joins:
var gifts = (from c in db.Categories
from g in c.Gifts
where c.Name.Contains(searchTerm)
select g).Distinct().ToList();

c#. EF entity sql. How to get entity with related objects?

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?

Categories

Resources