Reproduce GroupBy statement using Linq - c#

I'm developing a C# library with .NET Framework 4.0 and Entity Framework 6.1.3.
I want to get the same result that this sql statement:
select c.CODE_LEVEL
from CODES c
where c.CODE in
(Select CODE
from AGGREGATION_CHILDS
where PARENT_CODE = N'1')
group by c.CODE_LEVEL
with entity framework.
I'm using repository pattern, and I have tried this:
List<AGGREGATION_CHILDS> childrenCodeLevel =
m_AggChildRepo
.SearchFor(a => a.PARENT_CODE == aggregation.PARENT_CODE).GroupBy(a => a.Code.CODE_LEVEL).SelectMany(a => a).ToList();
With this code I get a list of AGGREGATION_CHILDS and I only need CODE_LEVEL value.
SearchFor implementation:
public IQueryable<TEntity> SearchFor(Expression<Func<TEntity, bool>> predicate)
{
return _dbSet.Where(predicate);
}
This is the sql tables creation statements:
CREATE TABLE [dbo].[CODES]
(
[CODE] [nvarchar](20) NOT NULL,
[CODE_LEVEL] [tinyint] NOT NULL,
CONSTRAINT [PK_CODES] PRIMARY KEY CLUSTERED
(
[CODE] ASC
)
)
CREATE TABLE [dbo].[AGGREGATION_CHILDS]
(
[CODE] [nvarchar](20) NOT NULL,
[PARENT_CODE] [nvarchar] (20) NOT NULL,
[POSITION] [int] NOT NULL,
CONSTRAINT [PK_AGGREGATION_CHILDS] PRIMARY KEY CLUSTERED
(
[CODE] ASC
),
CONSTRAINT [FK_AGGREGATION_CHILDS_AGGREGATIONS] FOREIGN KEY ([PARENT_CODE]) REFERENCES [AGGREGATIONS]([CODE]) ON DELETE CASCADE,
CONSTRAINT [FK_AGGREGATION_CHILDS_CODES] FOREIGN KEY ([CODE]) REFERENCES [CODES]([CODE])
)
All records in AGGREGATION_CHILDS for the same PARENT_CODE will have the same CODE_LEVEL.
How can I reproduce that sql statement?

Since you are not using any aggregate the group by will just removed the duplicates, same as using Distinct.
var res = db.CODES.Where(x =>
db.AGGREGATION_CHILDS.Any(y => y.PARENT_CODE == 1 && x.Code == y.Code))
.Select(x => x.CODE_LEVEL)
.Distinct();

Related

How do I link 3 tables using foreign keys?

I have made a table named "reservations" which contains a customer id and a house id. I made tables for houses and customers as well. I have made a datagrid, which contains the reservations data, but I also want it to contain the customers surname and the house code.
My tables are (in SQL Server Express):
CREATE TABLE [dbo].[houses]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[Code] VARCHAR(50) NULL,
[Status] VARCHAR(50) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
CREATE TABLE [dbo].[customers]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[Forename] VARCHAR(50) NULL,
[Surname] VARCHAR(50) NULL,
[Email] VARCHAR(50) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
CREATE TABLE [dbo].[reservations]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[HouseId] INT NULL,
[CustomerId] INT NULL,
[StartDate] DATE NULL,
[EindDate] DATE NULL,
PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_HouseId]
FOREIGN KEY ([HouseId]) REFERENCES [houses]([Id]),
CONSTRAINT [FK_CustomerId]
FOREIGN KEY ([CustomerId]) REFERENCES [customers]([Id])
);
I already created all the tables, but I don't know how to link them properly. I want to get the data and put it in a datagrid.
To select all data from Reservations, customers' Surname and house code, you need to run query:
Select R.*, C.Surname, H.Code
From [dbo].[reservations] R
inner join [dbo].[customers] C on C.Id = R.CustomerId
inner join [dbo].[houses] H on H.Id = R.HouseId
Try this:
select r.*,c.surname,h.code from reservation r,customers c,houses h where
r.customer_id=c.customer_id and r.house_id=h.house_id

LINQ Expression for CROSS APPLY two levels deep

Fairly new to LINQ and am trying to figure out how to write a particular query. I have a database where each CHAIN consists of one or more ORDERS and each ORDER consists of one or more PARTIALS. The database looks like this:
CREATE TABLE Chain
(
ID int NOT NULL PRIMARY KEY CLUSTERED IDENTITY(1,1),
Ticker nvarchar(6) NOT NULL,
Company nvarchar(128) NOT NULL
)
GO
CREATE TABLE [Order]
(
ID int NOT NULL PRIMARY KEY CLUSTERED IDENTITY(1,1),
Chart varbinary(max) NULL,
-- Relationships
Chain int NOT NULL
)
GO
ALTER TABLE dbo.[Order] ADD CONSTRAINT FK_Order_Chain
FOREIGN KEY (Chain) REFERENCES dbo.Chain ON DELETE CASCADE
GO
CREATE TABLE Partial
(
ID int NOT NULL PRIMARY KEY CLUSTERED IDENTITY(1,1),
Date date NOT NULL,
Quantity int NOT NULL,
Price money NOT NULL,
Commission money NOT NULL,
-- Relationships
[Order] int NOT NULL
)
GO
ALTER TABLE dbo.Partial ADD CONSTRAINT FK_Partial_Order
FOREIGN KEY ([Order]) REFERENCES dbo.[Order] ON DELETE CASCADE
I want to retrieve the chains, ordered by the earliest date among all the partials of all the orders for each particular chain. In T-SQL I would write the query as this:
SELECT p.DATE, c.*
FROM CHAIN c
CROSS APPLY
(
SELECT DATE = MIN(p.Date)
FROM PARTIAL p
JOIN [ORDER] o
ON p.[ORDER] = o.ID
WHERE o.CHAIN = c.ID
) AS p
ORDER BY p.DATE ASC
I have an Entity Framework context that contains a DbSet<Chain>, a DbSet<Order>, and a DbSet<Partial>. How do I finish this statement to get the result I want?:
IEnumerable<Chain> chains = db.Chains
.Include(c => c.Orders.Select(o => o.Partials))
.[WHAT NOW?]
Thank you!
.[WHAT NOW?]
.OrderBy(c => c.Orders.SelectMany(o => o.Partials).Min(p => p.Date))
Here c.Orders does join Chain to Order, while o.SelectMany(o => o.Partials) does join Order to Partial. Once you have access to Partial records, you can use any aggregate function, like Min(p => p.Date) in your case.

How can I access data from my junction table?

I have created a junction table between two of my tables to create a many to many relationship between them.I am able to save data to them, but can't access that data again. This is written in MVC ASP.NET by the way.
My first table:
CREATE TABLE [dbo].[UserInfo] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[FirstName] NVARCHAR (50) NULL,
[LastName] NVARCHAR (50) NULL,
[Email] NVARCHAR (256) NOT NULL,
[Image] VARBINARY (MAX) NULL,
[Approved] BIT NOT NULL,
[Color] NVARCHAR (10) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
My second table:
CREATE TABLE [dbo].[Events] (
[Id] NVARCHAR (128) NOT NULL,
[Name] NVARCHAR (100) NOT NULL,
[StartDate] DATETIME NULL,
[EndDate] DATETIME NULL,
[Approved] BIT NOT NULL,
[room_id] INT NULL,
[color] NVARCHAR (10) NOT NULL,
[Owner] INT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_Events_Rooms] FOREIGN KEY ([room_id]) REFERENCES [dbo].[Rooms] ([_key])
);
My junction table:
CREATE TABLE [dbo].[UserToEvent] (
[UserId] INT NOT NULL,
[EventId] NVARCHAR (128) NOT NULL,
CONSTRAINT [UserId_EventId_pk] PRIMARY KEY CLUSTERED ([UserId] ASC, [EventId] ASC),
CONSTRAINT [FK_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[UserInfo] ([Id]),
CONSTRAINT [FK_Event] FOREIGN KEY ([EventId]) REFERENCES [dbo].[Events] ([Id])
);
Code to add new relationship:
Event e = await db.Events.FindAsync(id);
string email = User.Identity.Name;
UserInfo user = db.UserInfoes.Where(x => x.Email == email).First();
user.Events.Add(e);
e.UserInfoes.Add(user);
db.Entry(user).State = EntityState.Modified;
db.Entry(e).State = EntityState.Modified;
await db.SaveChangesAsync();
Code to access relationship:
UserInfo user = await db.UserInfoes.FindAsync(id);
List<Events> events = user.Events;
I would expect events to be filled with all events associated with user, but it never has any events.
I have found a work-around which is sufficient to my needs. I added another attribute to my junction table, which then allowed me to access it within my controllers (Since there weren't only two primary keys). From here I was able to gather the data from it just like any other table. Not sure why the above method does not work however. I have used that method before without a hitch. If anyone has an answer, I would love to hear it.

Querying Dynamic Category /Sub Category from database with Entity Framework and LINQ

I need to come up with a solution to have infinite category and subcategories in a database. So this is my idea: creating a table that references parents/child as follows:
As you can see items can be followed down by its id and ParentItemID. However I don't know how I can apply this solution using LINQ.
I have create a model for above table as follow:
class Items
{
public int id { get; set; }
public string ItemName { get; set; }
public int ParentItemID { get; set; }
}
I have loaded list of ‘Items’ form database using EF, and I would like to query the list so it can be grouped and browsed like this:
How can it be done?
Thank in advance for any help.
1) With your model
Add a foreign key (self reference) between parent item id and item id.
CREATE TABLE [dbo].[26957446_All]([id] [int] NOT NULL,[name] [varchar](50) NOT NULL, [parentid] [int] NULL, CONSTRAINT [PK_26957446_All] PRIMARY KEY CLUSTERED ( [id] ASC )
ALTER TABLE [dbo].[26957446_All] WITH CHECK ADD CONSTRAINT [FK_26957446_Circular] FOREIGN KEY([parentid]) REFERENCES [dbo].[26957446_All] ([id])
ALTER TABLE [dbo].[26957446_All] CHECK CONSTRAINT [FK_26957446_Circular]
Generated model: , notice the self reference, names auto generated, All1 are children, All2 is parent reference.
var ents = new DynamicCategory.StackOverflowEntities26957446All();
// all root items loop
foreach (var item in ents.C26957446_All.Where(x => x.C26957446_All2 == null))
{
Console.WriteLine("Id: {0} Name: {1}", item.id, item.name);
PrintChildrenRecursively(item);
}
static int i = 1; //level
static void PrintChildrenRecursively (DynamicCategory.C26957446_All item)
{
foreach (var c in item.C26957446_All1)
{
Console.WriteLine("{2} Child Id: {0} Name: {1}", c.id, c.name, new string('\t', i));
if (c.C26957446_All1.Count > 0)
{
i++;
PrintChildrenRecursively(c);
i--;
}
Console.WriteLine();
}
}
Output:
2) With a different db organization. Separate items and relationships into separate tables. Add foreign keys from Relationship.Child and Relationship.Parent to Items table.
CREATE TABLE [dbo].[26957446_Items]([id] [int] NOT NULL, [name] [varchar](50) NOT NULL, CONSTRAINT [PK_26957446_Items] PRIMARY KEY CLUSTERED ([id] ASC))
CREATE TABLE [dbo].[26957446_Relationships](ParentId] [int] NOT NULL, [ChildId] [int] NOT NULL, CONSTRAINT [PK_Relationships] PRIMARY KEY CLUSTERED ([ParentId] ASC, [ChildId] ASC ))
ALTER TABLE [dbo].[26957446_Relationships] WITH CHECK ADD CONSTRAINT [FK_Child] FOREIGN KEY([ChildId]) REFERENCES [dbo].[26957446_Items] ([id])
ALTER TABLE [dbo].[26957446_Relationships] CHECK CONSTRAINT [FK_Child]
ALTER TABLE [dbo].[26957446_Relationships] WITH CHECK ADD CONSTRAINT [FK_Parent] FOREIGN KEY([ParentId]) REFERENCES [dbo].[26957446_Items] ([id])
ALTER TABLE [dbo].[26957446_Relationships] CHECK CONSTRAINT [FK_Parent]
Generated EF: , notice only class generated with both bottom-up and top-down references. Output is identical, code is very much similar with the exception: item.ItemChildren are children, and root items acces is :
var ents = new DynamicCategory.StackOverflowEntities26957446();
ents.C26957446_Items.Where (x=>x.ItemParents.Count==0)

Lambda Expression joining another table in my query for average

I am trying to join a table (db.Students) within this query to get firstname and lastname included in the query by joining on the StudentID. How do I do this? I've come up with about 50 queries that don't work and one that only gives me half of what I want. This is what I have so far that is working.
var gradeaverages = db.Grades
.Where(r => r.StudentID == r.StudentID)
.GroupBy(g => g.StudentID, r => r.Grades)
.Select(g => new
{
StudentID = g.Key,
Rating = g.Average()
});
var data = gradeaverages.ToList();
dataGridView1.DataSource = data;
It does have a foreign key. Here is the constraint:
CONSTRAINT [FK_Grades_Students] FOREIGN KEY ([StudentID]) REFERENCES [dbo].[Students] ([StudentID])
Here are my tables:
CREATE TABLE [dbo].[Grades] (
[GradeID] INT NOT NULL,
[StudentID] INT NOT NULL,
[Date] NCHAR (10) NULL,
[Grades] DECIMAL (18) NULL,
PRIMARY KEY CLUSTERED ([GradeID] ASC),
CONSTRAINT [FK_Grades_Students] FOREIGN KEY ([StudentID]) REFERENCES [dbo].[Students] ([StudentID])
CREATE TABLE [dbo].[Students] (
[StudentID] INT NOT NULL,
[First Name] NVARCHAR (40) NOT NULL,
[Last Name] NVARCHAR (40) NOT NULL,
[Phone] NVARCHAR (24) NULL,
CONSTRAINT [PK_Table] PRIMARY KEY CLUSTERED ([StudentID] ASC)
I'm looking for an out put of
StudentID FirstName LastName AverageGrade (according to StudentID I assume)
Actually there is not enough information about db structure, but I guess your query might look like this:
var data = db.Students.Include("Grades")
.Select(x => new
{
StudentId = x.StudentId,
Rate = x.Grades.Avg(y => y.Mark)
})
.ToList();
This .Where(r => r.StudentID == r.StudentID) is meaningless, because you compare some value with itself.
Or like this
var data = db.Grades
.GroupBy(x => x.StudentId)
.Select(x => new
{
StudentId = x.Key,
Rate = x.Avg(y => y.Mark)
})
.ToList();

Categories