Query on an entity, where joined with another that has a specific value? - ejb-3.0

I have a database with 3 tables.
LANGUAGE
id
ARTICLE
-id
ARTICLE_DETAIL
-id
-articleId
-languageId
I need to get an article from the database, but only if it has article details in a specific language. Today, I have the query in native MySQL using a coalesce, and that works fine. But now I want to make the same thing in EJB3. I've tried a lot of different things, but so far unsuccessful. I'm not very familiar working with entities in EJB3, so if anyone could please help me getting on the right track here, I would appreciate it.
Here's more or less what I've been trying so far:
Integer id = 543; // id of an article
Integer languageId = 2; // id of a language
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Article> cq = cb.createQuery(Article.class);
Root<Article> article = cq.from(Article.class);
Join<Article, ArticleDetail> details = article.join(Article_.articleDetailList);
// I think this is where I go wrong
cq.where(article.get(Article_.id).in(id)).where(details.get(ArticleDetail_.languageId).in(languageId));
TypedQuery<Article> q = em.createQuery(cq);
Article result = (Article) q.getSingleResult();
return result;

This did the job:
...
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Article> cq = cb.createQuery(Article.class);
Root<Article> article = cq.from(Article.class);
Join<Article, ArticleDetail> details = article.join(Article_.articleDetailList);
Join<ArticleDetail, Language> language = details.join(ArticleDetail_.languageId);
cq.where(cb.and(
cb.equal(article.get(Article_.id), id),
cb.equal(language.get(Language_.id), languageId)));
...

Related

LINQ query JOIN two tables for Web API controller method

I am really poor at LINQ and can't figure out a simple problem. I have a MVC Web API that has a controller. I have a method inside the controller to return back data for comments entered by user for an item.
The data structure is simple - Comments and User tables with UserID column acting as the foreign key
To solve the problem, I have the following method, which has a LINQ query to do a join between Comments and User tables and return back an object in a new extended object that combines the Comments and User details. I cant seem to grab data from the User table. Can someone please help?
public IQueryable<CommentsWithUserDetails> GetReviewsWithUserByItem(int ID)
{
var query = from x in db.Comments
join y in db.Users on x.CommentsUserID equals y.UserID into z
where x.CommentsItemID.Equals(ID)
select new CommentsWithUserDetails
{
CommentsUserID = x.CommentsUserID,
CommentsText = x.CommentsText,
CommentsRating = x.CommentsRating,
CommentsDate = x.CommentsDate,
UserFirstName = y.FirstName,
UserLastName = y.LastName,
UserPictureURL = y.PictureURL
};
return query;
}
The solution is just to remove the 'into z' part from the query, yes as simple as that!
As pointed by #Nilesh and #Gert Arnold

What is the performance optimum (or even better coding practise) for writing this Linq query

I am new to linq so please excuse me if I am asking a very basic question:
paymentReceiptViewModel.EntityName = payment.CommitmentPayments.First().Commitment.Entity.GetEntityName();
paymentReceiptViewModel.HofItsId = payment.CommitmentPayments.First().Commitment.Entity.ResponsiblePerson.ItsId;
paymentReceiptViewModel.LocalId = payment.CommitmentPayments.First().Commitment.Entity.LocalEntityId;
paymentReceiptViewModel.EntityAddress = payment.CommitmentPayments.First().Commitment.Entity.Address.ToString();
This code is too repetitive and I am sure there is a better way of writing this.
Thanks in advance for looking this up.
Instead of executing query at each line, get commitment entity once:
var commitment = payment.CommitmentPayments.First().Commitment.Entity;
paymentReceiptViewModel.EntityName = commitment.GetEntityName();
paymentReceiptViewModel.HofItsId = commitment.ResponsiblePerson.ItsId;
paymentReceiptViewModel.LocalId = commitment.LocalEntityId;
paymentReceiptViewModel.EntityAddress = commitment.Address.ToString();
It depends a bit on what you are selecting to, you cannot select from one entity into another in Linq to Entities. If you are using LINQ to SQL and creating the paymentReceiptModel, you can do this.
var paymentReceiptModel = payment.CommitmentPayments.select(x=>new{
EntityName = x.Commitment.Entity.GetEntityName(),
HofItsId = x.Commitment.Entity.ResponsiblePerson.ItsId,
LocalId = x.Commitments.Entity.LocalEntityId,
EntityAddress = x.Commitment.Entity.Address
}).FirstOrDefault();
If you are using an already instantiated paymentReceiptModel and just need to assign properties then you are better looking to the solution by lazyberezovsky.
To get around the limitation in Linq to Entities, if that is what you are using, you could do this
var result = payment.CommitmentPayments.select(x=>x);
var paymentReceiptModel= result.select(x=>new
{
EntityName = x.Commitment.Entity.GetEntityName(),
HofItsId = x.Commitment.Entity.ResponsiblePerson.ItsId,
LocalId = x.Commitments.Entity.LocalEntityId,
EntityAddress = x.Commitment.Entity.Address
}).FirstOrDefault();
This essentially, makes the majority of your query Linq to Objects, only the first line is Linq to Entities

Can't combine "LINQ Join" with other tables

The main problem is that I recieve the following message:
"base {System.SystemException} = {"Unable to create a constant value of type 'BokButik1.Models.Book-Author'. Only primitive types ('such as Int32, String, and Guid') are supported in this context."}"
based on this LinQ code:
IBookRepository myIBookRepository = new BookRepository();
var allBooks = myIBookRepository.HamtaAllaBocker();
IBok_ForfattareRepository myIBok_ForfattareRepository = new Bok_ForfattareRepository();
var Book-Authors =
myIBok_ForfattareRepository.HamtaAllaBok_ForfattareNummer();
var q =
from booknn in allBooks
join Book-Authornn in Book-Authors on booknn.BookID equals
Book-Authornn.BookID
select new { booknn.title, Book-AuthorID };
How shall I solve this problem to get a class instance that contain with property title and Book-AuthorID?
// Fullmetalboy
I also have tried making some dummy by using "allbooks" relation with Code Samples from the address http://www.hookedonlinq.com/JoinOperator.ashx. Unfortunately, still same problem.
I also have taken account to Int32 due to entity framework http://msdn.microsoft.com/en-us/library/bb896317.aspx. Unfortunatley, still same problem.
Using database with 3 tables and one of them is a many to many relationship. This database is used in relation with entity framework
Book-Author
Book-Author (int)
BookID (int)
Forfattare (int)
Book
BookID (int)
title (string)
etc etc etc
It appears that you are using two separate linq-to-sql repositories to join against. This won't work. Joins can only work between tables defined in a single repository.
However, if you are happy to bring all of the data into memory then it is very easy to make your code work. Try this:
var myIBookRepository = new BookRepository();
var myIBok_ForfattareRepository = new Bok_ForfattareRepository();
var allBooks =
myIBookRepository.HamtaAllaBocker().ToArray();
var Book_Authors =
myIBok_ForfattareRepository.HamtaAllaBok_ForfattareNummer().ToArray();
var q =
from booknn in allBooks
join Book_Authornn in Book_Authors
on booknn.BookID equals Book_Authornn.BookID
select new { booknn.title, Book_AuthorID = Book_Authornn.Book_Author };
Note the inclusion of the two .ToArray() calls.
I had to fix some of you variable names and I made a bit of a guess on getting the Author ID.
Does this work for you?
I would suggest only having a single repository and allowing normal joining to occur - loading all objects into memory can be expensive.
If you are making custom repositories you make also consider making a custom method that returns the title and author IDs as a defined class rather than as anonymous classes. Makes for better testability.

Subsonic 3 LINQ Projection issue, fixed or no?

I'm currently experiencing the issue mentioned here (and several other places): Subsonic 3 Linq Projection Issue
This is occurring using the 3.0.0.4 release package, and it also occurs when I grab the latest from GitHub and build it.
I am using the LINQ Templates.
I have this code:
var newModel = new ViewModels.HomeIndexViewModel() {
PulseListViewModel =
new ViewModels.PulseListViewModel
{
Pulses = from p in _pulseQuery
join a in _accountQuery on p.AccountId equals a.AccountId
orderby p.CreateDate descending
select new PulseListViewModel.Pulse()
{
AccountName = a.Name
, Category = p.Category
, CreateDate = p.CreateDate
, Link = p.Link
, Message = p.Message
, Source = p.Source
, Title = p.Title
}
}
};
But AccountName is always null.
If I change the AccountName to Name:
var newModel = new ViewModels.HomeIndexViewModel() {
PulseListViewModel =
new ViewModels.PulseListViewModel
{
Pulses = from p in _pulseQuery
join a in _accountQuery on p.AccountId equals a.AccountId
orderby p.CreateDate descending
select new PulseListViewModel.Pulse()
{
Name = a.Name
, Category = p.Category
, CreateDate = p.CreateDate
, Link = p.Link
, Message = p.Message
, Source = p.Source
, Title = p.Title
}
}
};
It works fine. But that's not acceptable in our project; I can't always make the names line up (besides the fact that it would make things less clear if I could).
But I'm quite confused because it would seem this issue's been fixed:
"Fixed issue where Projections were returning null or empty settings"
-- http://blog.wekeroad.com/2010/03/21/subsonic-3-0-0-4-released
So, can anyone tell me: Is this issue not fixed, and do I have to apply the changes found here at http://github.com/funky81/SubSonic-3.0/commit/aa7a9c1b564b2667db7fbd41e09ab72f5d58dcdb to make this work? Or am I missing something. Because looking through the current SubSonic source it appears this fix has been included. I feel like this should be simple and work, but instead I've spent an inordinate amount of time on it.
If you (me) modify SubSonic.Core according to the answer here: Subsonic 3.0 and linq
Then the projection works correctly.
However, I consider this a very bad solution as it requires forking a project and introducing an order of magnitude performance decrease.
Could you send me a little bit more code (especially what's behind _pulseQuery and _accountQuery) so I can fix this issue. Are you using SimpleRepository or the ActiveRecord approach or Query objects directly?
Reviving an old topic here, but in case someone searches for this later...
I also "fixed" this same issue, and put some explanation in the comments, in my fork on GitHub in this commit: https://github.com/rally25rs/SubSonic-3.0/commit/61af6aeb2ebb95f486d8df533bf13c8754d443e2
There is actually a slightly deeper issue here too. If you choose to use the "standard .NET built-in" projections, then some of the SubSonic unit tests start to fail, because SS does some extra stuff in its projection generation that the .NET projection doesn't do, so some of the expected functionality of SS doesn't work.
Personally, I think that, and the slower performance (though I haven't noticed a speed decrease) is a small price to pay for correct data.

NHIbernate Linq group by count

I have the version 3.0.0.1001 nhibernate.
My objects are basically modeiling a lineup at an event. So I have a StageSet object which represents one slot in the schedule for a stage.
Each StageSet object has a Stage and an Act property.
It also has many Users - people who have favorited the set.
I'm trying to ascertain the most popular sets that have been favorited using the following linq:
var topStars = from s in Db.StageSets
group s by s.Act.Id into g
select new { SetKey = g.Key, Count = g.Count() };
However this just fails with a Could not execute query[SQL: SQL not available] error
Should I be able to do this?
w://
in case someone comes here. The following should work with NH 3.1
var topStars = from s in Db.StageSets
group s by s.Act.Id into g
select new { SetKey = g.First().Act.Id, Count = g.Count() }
You've specified the query correctly in linq. NHibernate is refusing to translate it.
I just copied your query with a slightly different domain and it worked. But that will count StageSets by Act, NOT favorites.

Resources