Criteria API and left join on a dictionary/map - nhibernate

I have the following classes:
public class Item
{
public int Id { get; set; }
public IDictionary<int, ItemLocal> { get; protected set; }
public ICollection<string> Tags { get; set; }
public int DefaultLanguageId { get; set; }
public DateTime Start { get; set; }
}
public class ItemLocal
{
public virtual Item Parent { get; set; }
public virtual int LanguageId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
These map to the tables Item, ItemTag and ItemLocal. I want to make the following query via the criteria api:
select
i.Id,
i.Start,
l.Title
from
Item i
left join ItemLocal l on i.Id = l.ParentId and i.DefaultLangaugeId = l.LanguageId
order by
l.Title,
i.Id
But I dont know how to perform the left join with the nhibernate criteria api. Especially with the usage of the default language selection.
Any help is very appreciated.

I have found a solution:
Session
.CreateCriteria<Item>("i")
.CreateCriteria("Localization", "l", NHibernate.SqlCommand.JoinType.LeftOuterJoin)
.Add(Restrictions.Disjunction()
.Add(Restrictions.EqProperty("i.DefaultLanguageId", "l.LanguageId"))
.Add(Restrictions.IsNull("l.LanguageId"))
)
.AddOrder(Order.Asc("l.Title"))
.AddOrder(Order.Asc("w.Id"));
This seems to work but results in a query with a workaround WHERE clause. Would rather see that it could render a SQL query where the restrictions defined in the disjunction could be part of the OUTER LEFT JOIN ... ON ... statement.

Related

entity framework join 2 tables without modifying domain models

hey new to entity framework and i have these 2 models
SynchronizationProfile
public class SynchronizationProfileDBEntity
{
public string SyncProfileId { get; set; }
public string Code { get; set; }
public SynchronizationType SyncType { get; set; }
public string Schedule { get; set; }
public string UserName { get; set; }
}
SynchronizationLog
public class SynchronizationLogDBEntity
{
public string SyncLogId { get; set; }
public string SyncProfileId { get; set; }
public DateTime Ts { get; set; }
public SyncLogStatus LogStatus { get; set; }
}
there are no foreign keys on these because my team doesnt do it and get the results directly with LINQ
i want to get everything from SynchronizationLog(table) + Code(which is the name for everySyncProfileId) property from SynchronizationProfile
So i tried left join but for some reason dont get me the results.
var profiles = (from item in context.SynchronizationLogs
join item2 in context.SynchronizationProfiles
on item.SyncProfileId equals item2.SyncProfileId into gj
from subitem in gj.DefaultIfEmpty()
select new
{
SyncLogId = item.SyncLogId,
SyncProfileId = item.SyncProfileId,
Ts = item.Ts,
LogStatus = item.LogStatus
Code = item2.Code
}
Is my approach wrong?

Converting SQL query result to Linq result with an new field that is not in the Model

I have an SQL query,
SELECT
c.AssignedTo ,c.CampaignID, c.Name, c.Venue,c.StartedOn,
c.CompletedOn, c.IsOpen, COUNT(C.Name) AS Leads
FROM
Campaign AS c
RIGHT JOIN
Leads AS l ON l.CampaignID = c.CampaignID
GROUP BY
c.AssignedTo, c.CampaignID, c.Name,c.Venue,c.StartedOn, c.CompletedOn, c.IsOpen
ORDER BY
c.AssignedTo
These are my two tables in that query, CAMPAIGNS:
[Table("Campaigns")]
public class Campaigns
{
[Key]
public int CampaignID { get; set; }
[MaxLength(30)]
public string Name { get; set; }
[MaxLength(200)]
public string Venue { get; set; }
[ForeignKey("UsersReference")]
public int AssignedTo { get; set; }
public DateTime StartedOn { get; set; }
public DateTime? CompletedOn { get; set; }
public bool IsOpen { get; set; }
// To Reference Users table using FK
public Users UsersReference { get; set; }
}
and Leads:
[Table("Leads")]
public class Leads
{
[Key]
public int LeadID { get; set; }
[ForeignKey("CampaignsReference")]
public int CampaignID { get; set; }
[MaxLength(30)]
public string ConsumerName { get; set; }
[MaxLength(30)]
public string EmailAddress { get; set; }
[MaxLength(10)]
public string PhoneNo { get; set; }
public string PreferredMoC { get; set; }
public DateTime DateApproached { get; set; }
[ForeignKey("ProductsReference")]
public int ProductID { get; set; }
public string Status { get; set; }
// To access Campaign and Product table through FK
public Campaigns CampaignsReference { get; set; }
public Products ProductsReference { get; set; }
}
My query returns a result likes this in SQL:
The Leads column is just the COUNT() of the columns matching with my CampaignID. I've used context.Campaigns.FromSqlRaw() but since my Campaigns doesn't have another column specifically for the count.
Is there a way to display my new field Count() using EF Core and Linq?
Use LINQ Query for such task.
var query =
from l in ctx.Leads
let c = l.CampaignsReference
group c by new { c.AssignedTo, c.CampaignID, c.Name, c.Venue, c.StartedOn, c.CompletedOn, c.IsOpen } into g
select new
{
g.Key.AssignedTo,
g.Key.CampaignID,
g.Key.Name,
g.Key.Venue,
g.Key.StartedOn,
g.Key.CompletedOn,
g.Key.IsOpen,
Leads = g.Sum(x => x.Name != null ? 1 : 0)
};
var query = query.OrderBy(x => x.AssignedTo);

How do I do a multi-table SQL join with grouping

I have three tables that are represented here by objects and that convert to SQLite tables. The CategoryGroup table has multiple Categories and each Category has multiple Phrases.
public class CategoryGroup
{
[PrimaryKey, NotNull]
public int Id { get; set; }
public string Name { get; set; }
public bool Selected { get; set; }
}
public class Category : ICategory
{
[PrimaryKey, NotNull]
public int Id { get; set; }
public int CategoryGroupId { get; set; }
public string Name { get; set; }
public bool Selected { get; set; }
}
public class Phrase : IPhrase
{
public int CategoryId { get; set; }
[PrimaryKey, NotNull]
public string PhraseId { get; set; }
public string English { get; set; }
public string Romaji { get; set; }
public string Kana { get; set; }
public string Kanji { get; set; }
public int Modified { get; set; }
}
What I would like to do is to join these three tables and group them by CategoryGroup and then report on the Selected count.
I created this SQL but I am not sure about the three table join.
SELECT CG.Id, CG.Name, COUNT(*) AS PhraseCount
FROM CategoryGroup AS CG
FROM Category AS C
JOIN CG.Id = P.CategoryId
JOIN Phrase AS P ON C.Id = P.CategoryId
GROUP BY CG.Id
ORDER BY CG.Name
Can someone give me advice on how I can do the join?
You've got the syntax wrong. You'd select from one table, join another on some criteria so that records match, then join the third on some other criteria linking this table.
SELECT CG.Id, CG.Name, COUNT(*) AS PhraseCount
FROM CategoryGroup AS CG
JOIN Category AS C ON C.CategoryGroupId = CG.Id
JOIN Phrase AS P ON P.CategoryId = C.Id
GROUP BY CG.Id
ORDER BY CG.Name;
You may have to GROUP BY CG.Id, CG.Name instead. This is not necessary by the SQL Standard, because the category group name is functionally dependent on the category group ID, but some DBMS demand this though (because they find it too hard to determine functional dependence). I don't know about SQLite in this respect.

Fetch multiple in NPoco when children has its own mapping to do

I have been successful with fetching a parent and its children with NPoco FetchManyToOne with this code:
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
public IList<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Name { get; set; }
}
db.FetchOneToMany<Parent, Child>(parent => parent.Id, child => child.Id,
#"SELECT
P.Id, P.Name,
C.Id, C.ParentId, C.Name
FROM Parent AS P
LEFT JOIN Child AS C ON P.Id = C.ParentId",
id);
Now there is this scenario when a child can belong to a period. A children does not have to belong to a period as this is optional.
In the database the Period table consists of an id column and two datetime columns, Start and End. The Child table has a new column, PeriodId which can contain a null value if it does not belong to a period.
The class Child now gets a new property of type Period. Which can be null or an instance of class Period.
Look at the changes to the class structures:
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
public IList<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Name { get; set; }
public Period ChildPeriod { get; set; }
}
public class Period
{
public int Id { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
How can I map this sql to my classes?
#"SELECT
P.Id, P.Name,
C.Id, C.ParentId, C.Name,
PE.Id, PE.Start, PE.End
FROM Parent AS P
LEFT JOIN Child AS C ON P.Id = C.ParentId
LEFT JOIN Period AS PE ON C.PeriodId = PE.Id"
So that when a child is a part of a period that period is the value of property ChildPeriod on class Child.
Is it possible or do I have to write two calls to the database and do some manual mapping myself?
Since that's really an outer join on Period where Period will sometimes be null, do your Child class as:
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Name { get; set; }
[ResultColumn] public DateTime? Start { get; set; }
[ResultColumn] public DateTime? End { get; set; }
}

NHibernate left join select count in one-to-many relationship

I've been looking for a week after a correct synthax whithout success.
I have 2 classes :
public class ArtworkData
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<CommentData> Comments { get; set; }
}
public class CommentData
{
public virtual Guid Id { get; set; }
public virtual string Text { get; set; }
public virtual ProfileData Profile { get; set; }
public virtual ArtworkData Artwork { get; set; }
public virtual DateTime Created { get; set; }
}
I want to do this query :
SELECT this_.ArtworkId as ArtworkId3_3_,
this_.Name as Name3_3_,
this_.Description as Descript3_3_3_,
FROM Artwork this_
LEFT outer JOIN
(SELECT c.ArtworkIdFk, count(1) Cnt
FROM Comment c
GROUP BY c.ArtworkIdFk) as com
on com.ArtworkIdFk = this_.ArtworkId
ORDER BY 1 desc
But I don't find the way to.
At this moment I just have something like this :
ICriteria c = this.Session.CreateCriteria(typeof(ArtworkData));
if(filter.Category !=null)
{
c.CreateAlias("Categories", "cat")
.Add(Restrictions.Eq("cat.Id", filter.Category.Id));
}
DetachedCriteria crit = DetachedCriteria.For(typeof(CommentData), "comment")
.SetProjection(Projections.ProjectionList()
.Add(Projections.Count("comment.Id").As("cnt"))
.Add(Projections.GroupProperty("comment.Artwork.Id")));
c.Add(Expression.Gt(Projections.SubQuery(crit), 0));
c.AddOrder(Order.Desc(Projections.SubQuery(crit)));
But it's not what I want.
I want to get all Artworks order by the number of comments (but I don't need to get this number).
Please help me! I'm going crazy!
I don't understand what are you trying to do with this weird SQL but if you need to get all Artworks with number of comments you can try this query:
<query name="ArtworkWithCommentsCount">
SELECT artwork.Name, artwork.Comments.size
FROM Artwork artwork
</query>
If you use NHibernate 3 you could use this code:
var artworks = Session.Query<Artwork>().OrderBy(a => Comments.Count);
Or you could use HQL:
Session.CreateQuery("from Artwork a order by size(a.Comments)")
Try Detached Criteria. Take a look at this blogpost.