Hibernate native query that returns an object with nested properties for GraphQL - spring

Is it possible for a native Hibernate/Spring database query to return an object structure that contains nested properties? Ultimately I want to return the data to a GraphQL query. I'm using Spring for GraphQL and want the following request satisfied:
query Query {
someField {
prop1
prop2
complexProp {
prop3
prop4
}
}
}
What does work is to return a flattened version of the graph as you see below. I'm okay with working with the flattened version, but I would prefer a graph with nested fields for complex objects. Here is what does work:
query Query {
someField {
prop1
prop2
prop3
prop4
}
}
I'm able to generate the above flattened graph by using Transformers.aliasToBean (aka, ResultTransformer), like so:
var query = """
select p.prop1 as prop1,
p.prop2 as prop2,
c.some_prop1 as prop3,
c.some_prop2 as prop4
from parent p
inner join child c on c.parent_id = p.id
""";
var results = (List<ParentWithChildFlattenedDto>) entityManager.createNativeQuery(query)
.setMaxResults(100)
.unwrap(NativeQuery.class)
.setResultTransformer(Transformers.aliasToBean(ParentWithChildFlattenedDto.class))
.getResultList();
If I were using managed entities instead of a native query, I know the nested graphql structure could be built by doing one of two things:
The "new" operator in JPQL
Interface projections
thx

Related

Creating a group by parameter for the get method in a generic repository for entity framework

I am using the repository pattern with Entity Framework as described in this article: repository pattern with Entity Framework
In the part where the GenericRepository is described (Generic Repository) there is a method which is used to get entities from the database set called Get. It has an orderBy but no groupBy. I am wondering how one might implement a groupBy in the same manner as the orderBy so that you can specify which field to group by dynamically on the entity.
What I have come up with is this:
Func<IQueryable<TEntity>, IGrouping<string, TEntity>> groupBy = null
and then in the method code it should be used something like this:
if(groupBy != null)
{
query = groupBy(query).ToList();
}
But this is not compiling since the IGrouping is not queryable. Does someone know how to point me in the right direction or has a solution to this?
Edit: The reason for doing this instead of using groupby on the returned list is for performance reasons. I want the groupby to be sent as an sql statement to the database and resolved there.
Grouping has no sense without projection. So you have to define new method which returns IEnumerable with new type.
I have added sample of such method. Also removed includeProperties because EF Core ignores Includes during grouping.
Usage sample:
_orderRepostory
.GetGrouped(e => e.UserId, g => new { UserId = g.Key, Count = g.Count()});
And implementation:
public class GenericRepository<TEntity> where TEntity : class
{
... // other code
public virtual IEnumerable<TResult> GetGrouped<TKey, TResult>(
Expression<Func<TEntity, TKey>> groupingKey,
Expression<Func<IGrouping<TKey, TEntity>, TResult>> resultSelector,
Expression<Func<TEntity, bool>>? filter = null)
{
var query = dbSet.AsQueryable();
if (filter != null)
{
query = query.Where(filter);
}
return query.GroupBy(groupingKey).Select(resultSelector);
}
}

How to get data from two tables using web api

I want to get data from two tables using web api, but I'm receiving an error.
Here is my code:
public List<tblEmpTask> GettblEmpTasks()
{
var q = (from n in db.tblEmpTasks
join c in db.tblEmployees on n.intEmpCode equals c.intEmpCode
select new
{
n.strTaskName,
n.dtStart,
c.strEmployeeName,
}).ToList();
return q;
}
Here is the error that I'm receiving:
The type of one of the expressions in the join clause is incorrect. Type inference failed in the call to 'Join'.
and please note that I am using web api. Looking forward to solve this issue.
when selecting an anonymous the function should return List<object>
or instead
use a type to return value such as-
class myType{
string TaskName, //assuming type as string
string dtStart, //assuming type as string
string EmployeeName //assuming type as string
}
and in LinQ query something like -
select new myType{ TaskName=n.strTaskName, dtStart=n.dtStart, EmployeeName=c.strEmployeeName}
and return as List<myType>

what is a projection in LINQ, as in .Select()

I typically do mobile app development, which doesn't always have .Select. However, I've seen this used a bit, but I don't really know what it does or how it's doing whatever it does. It is anything like
from a in list select a // a.Property // new Thing { a.Property}
I'm asking because when I've seen code using .Select(), I was a bit confused by what it was doing.
.Select() is from method syntax for LINQ, select in your code from a in list select a is for query syntax. Both are same, query syntax compiles into method syntax.
You may see: Query Syntax and Method Syntax in LINQ (C#)
Projection:
Projection Operations - MSDN
Projection refers to the operation of transforming an object into a
new form that often consists only of those properties that will be
subsequently used. By using projection, you can construct a new type
that is built from each object. You can project a property and perform
a mathematical function on it. You can also project the original
object without changing it.
You may also see:
LINQ Projection
The process of transforming the results of a query is called
projection. You can project the results of a query after any filters
have been applied to change the type of the collection that is
returned.
Example from MSDN
List<string> words = new List<string>() { "an", "apple", "a", "day" };
var query = from word in words
select word.Substring(0, 1);
In the above example only first character from each string instance is selected / projected.
You can also select some fields from your collection and create an anonymous type or an instance of existing class, that process is called projection.
from a in list select new { ID = a.Id}
In the above code field Id is projected into an anonymous type ignoring other fields. Consider that your list has an object of type MyClass defined like:
class MyClass
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
Now you can project the Id and Name to an anonymous type like:
Query Syntax:
var result = from a in list
select new
{
ID = a.Id,
Name = a.Name,
};
Method Syntax
var result = list.Select(r => new { ID = r.Id, Name = r.Name });
You can also project result to a new class. Consider you have a class like:
class TemporaryHolderClass
{
public int Id { get; set; }
public string Name { get; set; }
}
Then you can do:
Query Syntax:
var result = from a in list
select new TemporaryHolderClass
{
Id = a.Id,
Name = a.Name,
};
Method Syntax:
var result = list.Select(r => new TemporaryHolderClass
{
Id = r.Id,
Name = r.Name
});
You can also project to the same class, provided you are not trying to project to classes generated/created for LINQ to SQL or Entity Framework.
My summary is it takes results (or a subset of results) and allows you to quickly restructure it for use in the local context.
The select clause produces the results of the query and specifies the
"shape" or type of each returned element. For example, you can specify
whether your results will consist of complete Customer objects, just
one member, a subset of members, or some completely different result
type based on a computation or new object creation.
Source: http://msdn.microsoft.com/en-us/library/bb397927.aspx
There are a lot of possible uses for this but one is taking a complex object which of many other contains a property that is a string -- say Name -- and allows you to return an enumeration with just the entries of Name. I believe you can also do the opposite -- use that property ( for example) and create / return new type of object while passing in a property or properties.
It means "mapping". Map each element of a sequence to a transformed sequence. I hadn't comprehended its meaning before I looked at the image.
Where does the meaning of the word come from?
Simply, math! https://mathworld.wolfram.com/Projection.html

IQueryable to IQueryable<T>

is it possibile convert an IQueryable object to IQueryable where T is a mapped entity? (T will be a POCO class).
Thanks in advance.
Just Cast<T>() it. Assuming it is a queryable of the same type. Otherwise you could use the OfType<T>() filtering method to filter out items of a certain type.
IQueryable query = ...;
IQueryable<MyType> x = query.Cast<MyType>(); // assuming the queryable is of `MyType` objects
IQueryable<MyDerivedType> y = query.OfType<MyDerivedType>(); // filter out objects derived from `MyType` (`MyDerivedType`)
However in your case, you say that you are using Dynamic LINQ and doing a dynamic projection. Consider this completely made up query:
var query = dc.SomeTable
.Where("SomeProperty = \"foo\"")
.Select("new (SomeProperty, AnotherProperty)");
It results in a query of type IQueryable. You cannot cast this to a query of a specific type IQueryable<T> after all, what is T? What the Dynamic LINQ library does is creates a type that derives from DynamicCass. You could cast to IQueryable<DynamicClass> (query.Cast<DynamicClass>()) but you will not have access to the properties so it's moot.
Really the only nice option you have is to use dynamic to access these properties in this case.
foreach (dynamic x in query)
{
string someProperty = x.SomeProperty;
int anotherProperty = x.AnotherProperty;
// etc...
}
If you want to convert this to a query of your POCO objects, you'll have to do the conversion as a separate step but using LINQ to Objects.
IEnumerable<SomePoco> query =
dc.SomeTable
.Where("SomeProperty = \"foo\"")
.Select("new (SomeProperty, AnotherProperty)")
.Cast<DynamicObject>().AsEnumerable().Cast<dynamic>()
.Select(x => new SomePoco
{
SomeProperty = x.SomeProperty,
AnotherProperty = x.AnotherProperty,
});
If you must have an IQueryable<T>, then you should not use dynamic projections in the first place.
IQueryable<SomePoco> query =
dc.SomeTable
.Where("SomeProperty = \"foo\"")
.Select(x => new SomePoco
{
SomeProperty = x.SomeProperty,
AnotherProperty = x.AnotherProperty,
});
Seeing as how the cast is not working for LINQ to Entities, then I suppose the only option you have to get a strongly type collection of your POCO objects is to break this out into a loop.
var query = dc.SomeTable
.Where("SomeProperty = \"foo\"")
.Select("new (SomeProperty, AnotherProperty)");
var result = new List<SomePoco>();
foreach (dynamic x in query)
{
result.Add(new SomePoco
{
SomeProperty = x.SomeProperty,
AnotherProperty = x.AnotherProperty,
});
}

Nhibernate 3.0 LINQ: Problem returning to IQueryable (non generic version) - doesn't allow ToList()

I am using the latest Nhibernate and i have a linq query to return just 1 column. so I can't use for example IQueryable as there is no entity class - i am returning only 1 column. But return to IQueryable Non Generic version doesn't provide the ToList method
Here is the method
public IQueryable GetCode()
{
using (ITransaction transaction = _session.BeginTransaction())
{
var results = (from c in _session.Query<Client>()
select new
{
Group = c.Code
}).Distinct();
}
}
Of course if i do this (see below) i get the ToList method on my IQueryable
public IQueryable<Client> GetCode()
{
using (ITransaction transaction = _session.BeginTransaction())
{
var results = (from c in _session.Query<Client>()
select c;
}
}
The problem being is that i need to do DISTINCT and use only 1 column.
Any ideas, i am at a loss
Thanks in advance
EDIT
When i look at the type that is returned via IQueryable it is
{NHibernate.Linq.NhQueryable<<>f__AnonymousType6>}
and looking under the base class of what is returned i see an exception
Expression type 10005 is not supported by this SelectClauseVisitor.
Wouldn't the following work?
public IQueryable<X> GetCode() // X = the type of Client.Code
{
using (ITransaction transaction = _session.BeginTransaction())
{
var results = (from c in _session.Query<Client>()
select c.Code).Distinct();
}
}
The problem here is not just that you can't call ToList on a non-generic IQueryable, but that the entire result is untyped, so you cannot read the Code property of each element either. (This can be worked around with C# 4's dynamic type, but that's not really what you want here.)
In your case, I don't see why you really need to construct an anonymous type just to return a distinct sequence of Code values renamed as Group. Returning the field's value should be sufficient.
If you'd need to return more than just one column, you should create an explicit type, rather than using an anonymous type, so you can say
public IQueryable<ClientGroupAndSomething> GetCode()
{
using (ITransaction transaction = _session.BeginTransaction())
{
var results = (from c in _session.Query<Client>()
select new ClientGroupAndSomething
{
Group = c.Code,
...
}).Distinct();
}
}

Resources