projection property in subquery nhibernate criteria - sql

Here's the deal, I got 2 tables:
table (A) with columns ( colA_1 | colA_2 | colA_ID ) <br>
table (B) with columns ( colB )
and I'm using DetachedCriteria.For<AnyEntity>() to query SQL.
The purpose is get an sql senerated like this:
Select A.colA_ID from A
where (CAST(colA_1 AS VARCHAR(10)) + CAST(colA_2 AS VARCHAR(10)))
in (select colB from B)
Thanks in advance for any help

I would strongly recommend to create a special property on your A entity:
public class EntityA
{
...
public virtual string ProjectedKey { get; set; }
}
And map it as readonly with formula
<property name="ProjectedKey"
formula="(CAST(colA_1 AS VARCHAR(10)) + CAST(colA_2 AS VARCHAR(10)))"
insert="false" update="false" />
And now is easy to use subquery
// subquery to get colB (its id?) from table B
var detachedQuery = DetachedCriteria.For<EntityB>()
.SetProjection(Projections.Id()) // or property representing col B
// use subquery with property represented by formula
var rootQuery = session.CreateCriteria<EntityA>()
.Add(Subqueries.PropertyIn("ProjectedKey", detachedQuery));

Related

Breeze Query: compare two columns on Related entity

Using Breeze, how can I compare two columns on a related property of an entity?
public class TableA{
public ICollection<TableB> TableBEntity {get; set;}
}
public class TableB{
public TableC TableCEntity {get; set;}
}
public class TableC {
public string columnA { get; set;}
public string columnB { get; set;}
}
var subpredicate = Predicate.create('TableCEntity.columnA', FilterQueryOp.Equals, 'TableCEntity.columnB');
var predicate = Predicate.create('TableBEntity', FilterQueryOp.Any, subpredicate);
var query1 = EntityQuery.from('TableB')
.where(subpredicate);
var query2 = EntityQuery.from('TableA')
.where(predicate );
query1 above executes without error. However query2 gives me the error:
The query specified in the URI is not valid. Could not find a property named 'TableCEntity' on type 'TableA'.
It seems as the subpredicate is not properly evaluated and it searches for the property TableCEntity on TableA instead of on TableB. If I change the subpredicate to
var subpredicate = Predicate.create('TableCEntity.columnA', FilterQueryOp.Equals, 'asamplevalue');
then, query2 works find. It just does not work the right side of the predicate is a record's column.
Am i doing something wrong or is this a bug?
The breeze 'any' and 'all' operators require that the property returned by the first expression ( "orders" in the example below) be a nonscalar navigation property. i.e. a navigation property that returns a collection. The subpredicate is then is just a simple predicate against the type returned by the first expression.
var query = EntityQuery.from("Employees")
.where("orders", "any", "freight", ">", 950);
with predicates this would be expressed as follows
var p2 = Predicate.create("freight", ">", 950);
var p1 = Predicate.create("orders", "any", p2);
var query = EntityQuery.from("Employees").where(p1);
In your case, i'm not sure what you are trying to do with your 'query2'. 'query2' appears to be a query over a collection of 'TableB' entities returned from 'TableA', but the 'subpredicate' deals with 'TableC' entities.
If this doesn't help, it might be easier to assist if you could restate your TableA, B and C names with table names that are a bit more intuitive and pluralize the collection property names.
Hope this helps.

Laravel Eloquent to join table and count related

How do I use join with Eloquent taking in consideration the following table structure:
I have a properies table
---------------------
ID | Name
---------------------
1 | Property Name
than I have rooms
----------------------
RoomID | Property
----------------------
A-212 | 1
----------------------
F-1231 | 1
here Property is the foreign key
than I want to get all Properties and count how many rooms do they have each
The query which retrives all looks like
class PropertiesRepository extends EloquentBaseRepository implements PropertiesInterface
{
use TaggableRepository;
/**
* Construct
* #param Properties $properties
*/
public function __construct( Properties $properties )
{
$this->model = $properties;
}
/**
* Get all properties joining rooms
* #return Properties
*/
public function getAll()
{
return $this->model->get();
}
}
How do I extend this query to get the desired result?
This is more of a MySQL join+group+select trick which includes following steps.
Join your relation table(use join if you want to exclude rows with RoomsCount=0, else use leftJoin)
Use groupBy by primaryKey to avoid duplicates of the join.
Select count of joined table
$this->model->leftJoin('Rooms', 'Properties.ID', '=', 'Rooms.Property')
->selectRaw('Properties.*, count(Rooms.RoomID) as RoomsCount')
->groupBy('Properties.ID')
->get();
Define the relationship on your Property model class:
<?php
namespace App\Models;
class Property extends Model {
public function rooms() {
return $this->hasMany(Room::class);
}
}
$properties = Property::withCount(['rooms'])->get();
This will add a rooms_count to the result.

How to use ExecuteStoreQuery for fetching data from Multiple tables

My application is in Asp.Net MVC3 coded in C#.Net. My issue is i want to get data from database using SQL query, for that i'm aware that i can use the below technique
Code to get data using ExecuteStoreQuery
var Complete_Data = db.ExecuteStoreQuery<Mytable>("select * from Mytable").ToList();
I have two issues
How to get the data in var Complete_Data when the data is coming from Multiple table (i.e the query has multiple joins).
I will be generating the selecting columns dynamically. The select query columns will generating dynamically.
Below is the sample example
string Field_Formation=string.Empty;
foreach (var item in My_Parameter_Collection_Logic_Variable)
{
Field_Formation+= item.Field_Name + ",";
}
Here My_Parameter_Collection_Logic_Variable is a variable declared in my code that will have a certain collection.
var Complete_Data = db.ExecuteStoreQuery<What_Class_To_Be_Taken_Here>("select" + Field_Formation + " from My_Tables_With_Multiple_Joins").ToList();
Need suggestion, whether it is possible to do such a stuff.
var Complete_Data = db.ExecuteStoreQuery<**What_Class_To_Be_Taken_Here**>
<What_Class_To_Be_Taken_Here> - this class must have properties like your Field_Formation.
For example if your select is:
"SELECT e.idExpense AS ExpenseID, e.idVehicle as VehicleID, d.Date AS Date1 .... join ... where ..."
create class like this:
public class ItemExample
{
private int VehicleID{ get; set; }
private int ExpenseID{ get; set; }
private DateTime? Date1 { get; set; }
}
You can write query using join and get your data from multiple tables.
for eg:-
var Complete_Data = db.ExecuteStoreQuery("select * from Table1 as T1 inner join Table2 as T2 on T1.id=T2.Id").ToList();
You will get all column of all table and then you can access using A.ColumnName or B.ColumnName.

add Nhibernate Projections

Have Employee: BaseEntity class with
public virtual BaseEntity Department {get;set;}
public virtual BaseEntity Position {get;set;}
and BaseEntity class:
public virtual long Id {get;set;}
public virtual long Name {get;set;}
How can I map my entities and /create select like this
SELECT DepartmentTable.nvarchar1 as Department, PositionTable.nvarchar1 as Position, COUNT(*) as N
FROM AllUserData EmployeeTable
left outer join AllUserData PositionTable on EmployeeTable.int2=PositionTable.tp_ID
left outer join AllUserData DepartmentTable on EmployeeTable.int3=DepartmentTable.tp_ID
WHERE EmployeeTable.tp_ListId = #p0 and PositionTable.tp_ListId = #p2 and DepartmentTable.tp_ListId = #p1
GROUP BY DepartmentTable.nvarchar1, PositionTable.nvarchar1;
I tried like this:
var criteria = session.CreateCriteria<Entities.Employee>();
criteria.CreateAlias("Position", "PositionTable", JoinType.LeftOuterJoin);
criteria.Add(Restrictions.Or(Restrictions.Eq("PositionTable.ListId", Program.PositionListGuid), Restrictions.IsNull("PositionTable.Id")));
criteria.CreateAlias("Department", "DepartmentTable", JoinType.LeftOuterJoin);
criteria.Add(Restrictions.Or(Restrictions.Eq("DepartmentTable.ListId", Program.DepartmentListGuid), Restrictions.IsNull("DepartmentTable.Id")));
criteria.Add(Restrictions.Eq("ListId", Program.EmployeeListGuid));
var projectionList = Projections.ProjectionList();
projectionList.Add(Projections.RowCount());
projectionList.Add(Projections.GroupProperty("Department"), "AliasedId");
criteria.SetProjection(projectionList);
criteria.SetResultTransformer(Transformers.AliasToBean(typeof(BaseEntity)));
var list = criteria.List<BaseEntity>();
// "More than one row with the given identifier was found" exception raised here
I'am confused, should I somehow use joined table alias for Projections.GroupProperty, rework my mapping/Entity to use only primitive types (string, int) or any other approach?
Figured out:
Add int Number to BaseEntity and string DepartmentName, string PositionName to Employee. Now I can use Projections to map Sql grouped by result to this properties:
var pl = Projections.ProjectionList()
.Add(Projections.RowCount(), GetEntityProperty(typeof (BaseEntity), "Number"))
.Add(Projections.GroupProperty("DepartmentTable.Title"), "PositionName")
.Add(Projections.GroupProperty("PositionTable.Title"), "DepartmentName");
ICriteria criteria = session.CreateCriteria<Employee>()
.CreateAlias("Position", "PositionTable", JoinType.LeftOuterJoin)
.Add(Restrictions.Eq("PositionTable.ListId", Program.PositionListGuid))
.CreateAlias("Department", "DepartmentTable", JoinType.LeftOuterJoin)
.Add(Restrictions.Eq("DepartmentTable.ListId",Program.DepartmentListGuid))
.Add(Restrictions.Eq("ListId", Program.EmployeeListGuid))
.SetProjection(pl)
.SetResultTransformer(Transformers.AliasToBean<BaseEntity>());
var list = criteria.List<BaseListEntity>().ToList();

NHibernate: Return a referenced property without lazy loading using SetProjection

I have the following two classes mapped:
public class Foo
{
public virtual Guid Id { get; set; }
public virtual Bar Bar { get; set; }
}
public class Bar
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
}
I have the following Criteria:
return Session.CreateCriteria<Foo>("f")
.CreateAlias("f.Bar", "b")
.SetProjection(Projections.Property("f.Bar"))
.List<Bar>();
This generates the following SQL:
select b.Id from Foo f
inner join Bar on f.BarId = b.Id
Notice how only the Id of Bar is returned, rather than the entire class. How do I get all the columns of Bar instead?
The solution depends on your needs.
First of all if you need to return entity Bar, then your initial Criteria must be of type Bar so you just:
session.CreateCriteria<Bar>().
.List<Bar();
If you need to add some restrictions based on Foo then there are two ways.
Use HQL
session.CreateQuery(
"select b " +
"from Foo f " +
"inner join f.Bar b " +
"where f.Id = 9 ")
.List();
Use query only property. Do this by adding access="noop" in your Bar mapping file.
<many-to-one name="foo" access="noop" class="Foo" column="FooFk"/>
Note that your domain model doesn't have to change! You don't need to add that "foo" property/field in the Bar class.
Now you can use that property in your queries like:
session.CreateCriteria<Bar>()
.CreateAlias("foo", "f")
.Add(Restrictions.Eq("f.Id", 9))
.List<Bar>();
If it doesn't fit into a single criteria, use DetachedCriteria:
var subquery = DetachedCriteria.For<Foo>("f")
.SetProjection(Projections.Property("f.Bar"))
// more filter criteria ...
return session.CreateCriteria<Bar>
.SetProjection(Subqueries.PropertyIn("id", subquery));
which creates sql like this:
select Bar.*
from Bar
where Bar.id in (Select b.id from Foo f inner join Bar b on ...)
Is obviously only make sense if you have some filter criteria base on Foo in the subquery.
If the above detached criteria query doesnt work out here is a simple HQL query that should do the trick.
var hqlQuery="select b from Foo as f inner join f.Bar as b";
Now run this query as follows:
Session.CreateQuery(hqlQuery).List<Boo>();
you can now add where condition to your query too if you want.
Hope this helps.. I can tell you how to do it with Criteria but I think this is a little easier for you to ustand as u seem to be comfortable with SQL.