HQL restriction on child collection - c#

I have a class which has a collection
public class Parent
{
...
ISet<Child> Children;
...
}
Given a list of child names, I'd like to return parents whose Children property contains all items of this list.
I managed to write an HQL query, but it works for a single name, not a whole list :
SELECT p FROM Parent AS p JOIN p.Children AS c WHERE c.Name = 'MyName'

Thanks Mauricio, I managed to solve this problem with the following criteria query
var criteria = session.CreateCriteria<Parent>("p")
.Add(Restrictions.IsNotEmpty("p.Children"));
foreach (var name in namesToMatch)
{
criteria.Add(Subqueries.Exists(DetachedCriteria.For<Parent>("p2")
.SetProjection(Projections.Id())
.CreateAlias("p2.Children", "c")
.Add(Restrictions.Eq("c.Name", name))
.Add(Restrictions.EqProperty("p2.Id", "p.Id"))));
}

Related

Query in LINQ with self join

I have a table which contains columns among others like Id as Primary Key and LastMeterReadingId (Foreign Key which references to same table) - something like Parent Meter Reading.
I would like to get all rows which are not already used like Parent. I would like to avoid situation when meter reading is parent for more than one meter reading.
I know how to join to same table, but I have no idea how to choose only those records which aren't parent already. That's how query looks like without condition statement.
return (from m in uow.MeterReadingReadWriteRepository.Query()
join parent in uow.MeterReadingReadWriteRepository.Query() on m.Id equals parent.LastMeterReadingId
select new MeterReadingDto()
{
(...)
}).ToList();
Do you have any idea how to achieve it in efficient way?
Regards.
I would like to get all rows which are not already used like Parent
In other words, you want all rows that have no children. Note that the variable name parent in your query is misleading - when you do a join b on a.Id equals b.ParentId, a is the parent and b is the child.
Anyway, there are at least 3 ways to achieve your goal, IMO being equivalent from nowadays database query optimizers point of view (i.e. should be equally efficient):
(1) Using !Any(...) which is equivalent to SQL NOT EXISTS(...):
from m in uow.MeterReadingReadWriteRepository.Query()
where !uow.MeterReadingReadWriteRepository.Query().Any(child => m.Id == child.LastMeterReadingId)
select ...
(2) Using group join:
from m in uow.MeterReadingReadWriteRepository.Query()
join child in uow.MeterReadingReadWriteRepository.Query()
on m.Id equals child.LastMeterReadingId into children
where !children.Any()
select ...
(3) Using left outer antijoin:
from m in uow.MeterReadingReadWriteRepository.Query()
join child in uow.MeterReadingReadWriteRepository.Query()
on m.Id equals child.LastMeterReadingId into children
from child in children.DefaultIfEmpty()
where child == null
select ...
If this is EF (LINQ to Entities), the first two are translated to one and the same SQL NOT EXISTS based query. While the last is translated to the "traditional" SQL LEFT JOIN ... WHERE right.PK IS NULL based query.
You could just add
where !(from child in uow.MeterReadingReadWriteRepository.Query() where child.Id == m.LastMeterReadingId select child).Any()
Not sure how intelligently this would be optimised though. It would also be better to factor out uow.MeterReadingReadWriteRepository.Query().
Do you not have a Child relationship/collection in your Meter Reading entity from the foreign key constraint? - this would make the query much more straightforward.
var readings = uow.MeterReadingReadWriteRepository.Query();
var parents = readings
.Join(readings, child => child.Id, parent => parent.LastMeterReadingId,
(child, parent) => new {parent.Id})
.Distinct()
.ToDictionary(a => a.Id);
var result = (from m in readings
where !parents.Contains(m.Id)
select new
{
Id = m.Id
}).ToList();
Thanks #Ben Jackson
public class MeterReading : EntityBase
{
public long PropertyId { get; set; }
public long? LastMeterReadingId { get; set; }
public long? PaymentId { get; set; }
public Property Property { get; set; }
public MeterReading LastReading { get; set; }
public Payment Payment { get; set; }
}
That's how most value properties looks like. Maybe should I use T-SQL query with JOIN to CTE which mentioned before condition statement? I'll try your solution ASAP.

Runtime joins to query within Entity Framework

I have a database that is mapped using the Entity Framework. Entity Framework is generating the C# code of the database objects in the similar manner as shown below. For simplicity I have created Parent, Child, GrandChild hierarchy but the actual db contains much longer hierarchies and many other fields.
class Parent
{
string name;
int id;
datetime DateOfBirth;
}
class Child
{
string name;
int id;
int ParentId; ( FK reference to Parent Child )
}
class GrandChild
{
string name;
int id;
int ChildId; (FK reference to Child )
}
Now, I am building an api where the filters will be provided at runtime. I mean, some of the queries could be
Give all GrandChild rows for ParentId =1
Give All Grandchild rows for ChildName = "x"
Give all GrandChild rows for Parent with DateOfbirth = "x/y/z"
So, how can I build in C# code, using LINQ or Expression Trees to create predicates and join filters dynamically/runtime.
Following URL:
https://msdn.microsoft.com/library/bb882637.aspx
shows how to create dynamic query, but not how to INNER JOIN multiple such queries. Does anyone know how to do that?
This Stackoverflow answer:
The parameter '***' was not bound in the specified LINQ to Entities query expression
also highlights how to create filters dynamically but not how to join them.
Does anyone know how to create dynamic queries to filter rows and join the queries? Let me know if you need more information. Thanks
Well, I'm going to suppose that is not your real model because you should have properties instead fields and your entities must be public.
If you have represented your db relationships using navigation properties, you could create a extension method like this:
static IQueryable<TEntity> Select<TEntity>(this IQueryable<TEntity> query, List<Expression<Func<TEntity, bool>>> filters = null,
List<Expression<Func<TEntity, object>>> includes = null)
{
if (includes != null)
{
query = includes.Aggregate(query, (current, include) => current.Include(include));
}
if (filters != null)
{
query = filters.Aggregate(query, (current, filter) => current.Where(filter)); //at the end this is going to be translated to condition1 && condition2 ...
}
return query;
}
In the first list you pass all the conditions you want to apply to your query and the second helps you to load the related entities that you need in your query:
var conditions = new List<Expression<Func<GrandChild, bool>>>() { (t) => t.Child.Parent.ParentId==1 };
var includes = new List<Expression<Func<GrandChild, object>>>() { (t) => t.Child.Parent };
var query= yourContext.GrandChilds.Select(filters,includes);
1 . Give all GrandChild rows for ParentId =1
var grandChildData=from grand in GrandChild
join ch in Child on grand.ChildId equals ch.Id
where ch.ParentId==1
select grand;
Give All Grandchild rows for ChildName = "x"
var grandChildData=from grand in GrandChild
join ch in Child on grand.ChildId equals ch.Id
where ch.name = "x"
select grand;
Give all GrandChild rows for Parent with DateOfbirth = "x/y/z"
var grandChildData=from grand in GrandChild
join ch in Child on grand.ChildId equals ch.Id
join p in Parent on ch.ParentId equals p.id
where p.DateOfbirth==Convert.ToDateTime("2016/01/01")
select grand;

Using LINQ to group together a list of nodes and a list of their attributes

I have a table with a list of Nodes (with properties ID and Name), and a second table with a list of Node Attributes (with a reference Parent to the corresponding Node ID). I usually query for the node, and then get its attributes, to populate an object
public class NodeWithAttributes
{
public Node Node = new Node();
public List<NodeAttribute> NodeAttributes = new List<NodeAttribute>();
}
However, when I want to query for a list of 'NodeWithAttributes' things get complicated. I'm trying to group the attributes together by Parent, and then assigning them to the object - something like :
var results = (from n in dbNodes.Nodes
join na in dbNodes.NodeAttributes on n.ID equals na.Parent
group na by na.Parent
into g
select new NodeWithAttributes
{
Node = n,
NodeAttributes = g
}
).ToList();
But I can only seem to return the group, and not an object based on it. What can I do to return a List of NodeWithAttributes?
I think in your case no need to group by data. If you want Parent Children try to use query similar to following.
var query = from c in north.Customers
orderby c.CustomerID
select new
{
customer = c,
orders = c.Orders
};
foreach (var item in query)
{
Console.WriteLine(item.customer.CompanyName);
foreach (var ord in item.orders)
{
Console.WriteLine(ord.OrderDate + " " + ord.OrderID);
}
Console.WriteLine("");
}

Hierarchy Problem -> Replace Recursion with Linq Join?

I have a self referential table, which has ID, ParentID (nullable).
So, the table contains many nodes, each node could be the root in the hierarchy (parent is null), or any level of the hierarchy (parent exists elsewhere in the table).
Given an arbitrary starting node, is there an elegant linq query that will return all children of the hierarchy from that node?
Thanks.
If you want to select all direct children of a node, a simple query like the following should do the job:
from item in table
where item.ID == parentID;
select item
If you want to select all descendants of a node, this is not possible with LINQ, because it requires recursion or a stack which LINQ (and SQL) doesn't provide.
See also:
StackOverflow: LINQ to SQL for self-referencing tables?
CodeProject: T-SQL - How to get all descendants of a given element in a hierarchical table
StackOverflow: Expressing recursion in LINQ
Here is a quick one I just wrote:
class MyTable
{
public int Id { get; set; }
public int? ParentId { get; set; }
public MyTable(int id, int? parentId) { this.Id = id; this.ParentId = parentId; }
}
List<MyTable> allTables = new List<MyTable> {
new MyTable(0, null),
new MyTable(1, 0),
new MyTable(2, 1)
};
Func<int, IEnumerable<MyTable>> f = null;
f = (id) =>
{
IEnumerable<MyTable> table = allTables.Where(t => t.Id == id);
if (allTables
.Where(t => t.ParentId.HasValue && t.ParentId.Value == table
.First().Id).Count() != 0)
return table
.Union(f(
allTables.Where(t => t.ParentId.HasValue && t.ParentId.Value == table
.First().Id).First().Id));
else return table;
};
But I believe it is possible to do using SQL with a Union ALL.
I know this is an old post but you should check out this extension:
http://www.scip.be/index.php?Page=ArticlesNET23
I've been using it and it is working great.
Basically I'm going with something like this as discussed in the SO link you proivded.
public IQueryable GetCategories(Category parent)
{
var cats = (parent.Categories);
foreach (Category c in cats )
{
cats = cats .Concat(GetCategories(c));
}
return a;
}
CTEs are probably the best solution but I'd like to keep things all in the same tier for now.

LINQ - Joining Lists in a linq Query

Question is How do a return a List of B with all the entities in children of all Parents without resorting to the type of code below, I was thinking u must be able to acheive the same within a single linq query?
Class Parent {
public Title,
public children List<B>,
}
data = List<A>
var childLists = from x in x.Parents select x.children;
List<B> output = new List<B>();
foreach (List<B> b in childLists)
output.AddRange(b);
Thanks.
List<B> allChildren = x.Parents.SelctMany(p => p.children).ToList()
var output = x.Parents.SelectMany(p => p.children).ToList();
using nesting
from parent in x.Parents
from child in parent.Children
select child;

Categories

Resources