How to join two tables with Linq in an MVC controller - c#

I have two sql database tables with a 1:n relationship. For my ASP.NET MVC-solution I have enabled EF-code-first-migration and the proper DBContext and classes established.
I would like to write an MVC-controller that joins both tables in order to select specific records for display in a view.
Here are the two classes:
public class Tbl_Group_Communities : Entity
{
public string GKZ { get; set; }
public int G_ID { get; set; }
}
public class Katastralgemeinden : Entity
{
public string KGNr { get; set; }
public string KGName { get; set; }
public string GKZ { get; set; }
public string GemeindeName { get; set; }
}
So far I have been able to come up with a working controller for the tables by themselves but not joined. Below the working controller for the first class:
public IEnumerable<Tbl_Group_Communities> Get()
{
var entities = UnitOfWork.GetAll<Tbl_Group_Communities>().ToList();
return entities;
}
I think, the join can be done with Linq but I have no idea how/where to start.
The common key for both tables is GKZ; so the join should be established via GKZ. And then I need to select specific records from the joined records where G_ID = a certain value.
If someone could give me some help, I'd be very thankful.
Manu

You can do inner join as shown below.
Assumption : Hope your table names are like Tbl_Group_Communities and Katastralgemeinden.In other words same name as the class names.
from s in db.Tbl_Group_Communities
join sa in db.Katastralgemeinden on s.GKZ equals sa.GKZ
where s.G_ID == 1
select s
You can learn more about join here : Join Operators

I figured it out - here is my controller that works:
using System.Linq;
using System.Web.Http;
using System.Web.Http.OData.Query;
using IndireKat.Data.Contracts;
using IndireKat.Data.Contracts.Entities;
using IndireKat.Shared.Framework.Security;
namespace Presentation.Host.Controllers
{
public class KatastralgemeindenController : BaseODataController
{
private readonly IIdentityStorage identityStorage;
public KatastralgemeindenController(IUnitOfWork unitOfWork, IIdentityStorage identityStorage)
{
UnitOfWork = unitOfWork;
this.identityStorage = identityStorage;
}
[Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
public IQueryable<Katastralgemeinden> Get()
{
IIndireKatPrincipal indireKatPrincipal = identityStorage.GetPrincipal();
var comunityIds = UnitOfWork.GetAll<UserGroup>()
.Where(group => group.Id == indireKatPrincipal.GroupId)
.SelectMany(group => group.Tbl_Group_Communities).Select(comunity => comunity.GKZ).ToList();
IQueryable<Katastralgemeinden> result = null;
if (comunityIds.Any())
{
result = UnitOfWork.GetAll<Katastralgemeinden>().Where(company => comunityIds.Contains(company.GKZ));
}
return result;
}
}
}
Regards, Manu

Related

how to show values of three table with foreign key associated in table using entity framework c#?

hello all i am new to entity and asp.net M.V.C i am using entity framework code first approach with already made database i want to show three tables data in a table using inner join and confused how to do it
i have tried the following code given below
public List<NewGroupRoles> GetAllGroups()
{
try
{
using(var p=new VMSDBContext())
{
var group = (from group_role in p.group_roles
join groups in p.groups on group_role.group_id equals groups.group_id
join roles in p.roles on group_role.roles_id equals roles.role_id
select new
{
Id = group_role.group_roles_id,
group_name = groups.group_name,
group_role = roles.role_name
}).ToList();
}
}
catch(Exception ex)
{
return new List<NewGroupRoles>();
}
}
i want to return it from a function in model
model classes areths class defines all the database entity classes
this a group table
[this is group role class][3]
role class
You are trying to do work, which EF is supposed to do for you.
It looks like you have many-to-many relationship between the groups and roles tables. Why wouldn't you remove the group_roles class and just define navigation properties
public virtual IEnumerable<roles> roles { get; set; }
in groups model class and
public virtual IEnumerable<groups> groups { get; set; }
in roles model class
and get list of groups and roles somehow like this:
var groupRoles = p.groups.SelectMany(g=>g.roles, (g,r)=>new {Group = g.group_name, Role = r.role_name}).ToList();
Or if your use EF Core, which yet does not support many-to-many relationships without intermediate model class or just insist on having an intermediate class group_roles in your model, you can define two navigation properties in it, something like this:
public class group_roles
{
[Key]
public int group_roles_id { get; set; }
[ForeignKey("groups")]
public int group_id { get; set; }
[ForeignKey("roles")]
public int role_id { get; set; }
public virtual groups group { get; set; }
public virtual roles role { get; set; }
}
Then your query is just
var groupRoles = p.group_roles.Select(gr=> new {gr.group_roles_id, Group=gr.group.group_name, Role=gr.role.role_name).ToList();
Use this as you need to have new object while selecting
public List<NewGroupRoles> GetAllGroups()
{
try
{
using(var p=new VMSDBContext())
{
var group = (from group_role in p.group_roles
join groups in p.groups on group_role.group_id equals groups.group_id
join roles in p.roles on group_role.roles_id equals roles.role_id
select new NewGroupRoles()
{
Id = group_role.group_roles_id,
group_name = groups.group_name,
group_role = roles.role_name
}).ToList();
}
}
catch(Exception ex)
{
return new List<NewGroupRoles>();
}
return group;
}

linq queries in train database

I have a train database, with all required fields such as Train, Route, Station, Passenger, Reservation etc. I want to get trains between a pair of stations using LINQ(I know the SQL Query, but I am unable to convert it to LINQ). Please anyone help me.
One more thing, I want the Extension method approach of LINQ Queries(not the keywords like from, in, select), like
var trains = _context.Trains.FirstOrDefault(a => a.Id == text);
The SQL Query
SELECT Route.TrainId, Train.TrainName
FROM Route
INNER JOIN Train ON Route.TrainId=Train.TrainId
WHERE
(Route.StationId IN
(SELECT Source.StationId
FROM Route AS Source
INNER JOIN Route AS Destination ON Source.TrainId=Destination.TrainId
WHERE
(Source.StopNumber - Destination.StopNumber < 0)
AND
(Source.StationId = #Source)
AND
(Destination.StationId = #Destination)
)
)
Please comment me if you want any more details like table structures. I got the table structure and queries from an online slide.
I used classes to model your database. Try something like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Train> trains = new List<Train>();
string source = "abc";
string destination = "xyz";
var results = trains.Where(x => x.Routes.Any(y => y.StationId == source) && x.Routes.Any(y => y.StationId == destination))
.Select(x => new {
source = x.Routes.Where(y => y.StationId == source).FirstOrDefault(),
destination = x.Routes.Where(y => y.StationId == destination).FirstOrDefault()
})
.Where(x => x.destination.StopNumber > x.source.StopNumber)
.ToList();
}
}
public class Train
{
public string TrainName { get; set; }
public List<Route> Routes { get; set; }
}
public class Route
{
public string TrainId { get; set; }
public string StationId { get; set; }
public int StopNumber { get; set; }
}
}

Linq joining into list property of object

Hey I have two following classes:
public class Project
{
public int Id { get; protected set; }
public string ProjectName { get; protected set; }
public List<Task> TaskList{ get; protected set; }
}
public class Task
{
public int Id { get; protected set; }
public int ProjectId { get; protected set; }
public string Name { get; protected set; }
}
If I am using Entity Framework is it possible to get Project object from database (eg. by id) and in the same time join tasks list into [Project] TaskList property, or I should first get a project, and then tasks?
How it should be implemented properly?
If you described relationship between tables Project and Task as explained here
than you can directly just call your Project entity; it will come with a list of related Tasks; if you didn't described relationships than you have to create a join query by linq to etnity or use .Inlcude for relate entites to each other.
var tasks = (from items in db.Task
join projects in db.Project on items.ProejctId equals projects.Id
where 1==1 // you can add some other confitions to here
select new SelectItemsList() { //Items you want to select })
Do you require the Project class object like below code? without using .include<>
var res = (from p in db.ProjectTable
select new Project
{
Id = p.Id,
ProjectName = p.ProjectName,
TaskList = (from q in db.TaskTable
where q.ProjectId = p.Id
select q
).ToList()
}).ToList();
return res; //you will get List<Project> with their List<TaskList>

Dynamically set the table name in LINQ query

I am working on data warehouse application and we have 4 tables where schema is identical. Only difference between those tables is just Table Name.
Table Example:
ps_Contractor
ps_Employee
ps_Union
ps_NonUnion
Schema
id
hourly
benefit
total
Now i need to generate 4 reports based on these tables. Instead of writing 4 separate LINQ queries i would like to write single query where i can pass the table name dynamically.
The question How do i pass the table name dynamically in following LINQ query ?
var data = ( from q in _dbcontext.ps_Contractor
join _l in _dbcontext.log on q.id equals l.tablelogid
where q.hourly = 8
select new{
hourly=q.hourly,
benefit=q.benefit,
total=q.total,
log = l.message
}.ToList();
I have looked at all similar questions suggested by stack overflow. I do not want to use ExecuteStoreQuery.
what options do i have ?
If all the tables have the same columns, then I'd extract an interface out of those tables and create partial entity classes just to implement that interface, finally use that interface to query.
For example:
//entities
public partial class ps_Contractor: ICommonInterface{}
public partial class Table2 : ICommonInterface{}
in the search method I'd pass IEnumerable<ICommonInterface> or IQueryable<ICommonInterface> and apply that query on that. All you'd need to do is to pass different tables to that search method.
Or you can even have kind of generic class of type ICommonInterface and use that to do the query.
public void Example(IQueryable<ICommonInterface>dataSource)
{
var data = ( from q in dataSource
join _l in _dbcontext.log on q.id equals l.tablelogid
where q.hourly = 8
select new{
hourly=q.hourly,
benefit=q.benefit,
total=q.total,
log = l.message
}.ToList();
}
Example(_dbcontext.ps_Contractor.AsQueryable())
This is just a sample that I tested now:
public class Repository
{
private List<string> GetData(IQueryable<IContractor> data)
{
return (from d in data select d.Name).ToList();
}
public List<string> GetFullTime()
{
using (var context = new TestDbEntities())
{
return GetData(context.FTContractors.AsQueryable());
}
}
public List<string> GetPartTime()
{
using (var context = new TestDbEntities())
{
return GetData(context.PTContractors.AsQueryable());
}
}
}
Entities:
public interface IContractor
{
int Id { get; set; }
string Name { get; set; }
}
public partial class FTContractor : IContractor
{
public int Id { get; set; }
public string Name { get; set; }
}
public partial class PTContractor : IContractor
{
public int Id { get; set; }
public string Name { get; set; }
}
Test:
[TestMethod]
public void Temp()
{
var tester = new Repository();
var ft = tester.GetFullTime();
var pt = tester.GetPartTime();
Assert.AreEqual(3, ft.Count);
Assert.AreEqual(4, pt.Count);
}
In the database there are two tables containing just Id and Name columns
EF Core no longer has a non generic .set method but This extension class makes it easy to query your table based on a string using dynamic Linq
public static class DbContextExtensions
{
public static IQueryable<Object> Set(this DbContext _context, Type t)
{
return (IQueryable<Object>)_context.GetType().GetMethod("Set").MakeGenericMethod(t).Invoke(_context, null);
}
public static IQueryable<Object> Set(this DbContext _context, String table)
{
Type TableType = _context.GetType().Assembly.GetExportedTypes().FirstOrDefault(t => t.Name == table);
IQueryable<Object> ObjectContext = _context.Set(TableTypeDictionary[table]);
return ObjectContext;
}
}
}
usage:
IQueryable<Object> query = db.Set("TableName");
// Filter against "query" variable below...
List<Object> result = query.ToList();
// or use further dynamic Linq
IQueryable<Object> query = db.Set("TableName").Where("t => t.TableFilter == \"MyFilter\"");
Here's a way to do a dynamic function that accepts a DbSet<T> (type of database class that you want to pass as a parameter) and a specific expression to build a query on that table:
private IQueryable<T> BuildQueriedCollection<T>(Expression<Func<T, bool>> exp, DbSet<T> dbTable) where T : class
{
var appliedQueryCollection = dbTable.AsExpandable().Where(exp);
return appliedQueryCollection;
}
and you could call the function like so:
Expression<Func<MyClass, bool>> myExp = myList => myList... // some condition...;
var dbset = dbContext.MyTable;
var query = BuildQueriedCollection(myExp, dbset);

Fill property of DTO with SubQuery in NHibernate Query

I have a DTO object like this:
public class TreeViewDTO
{
public string Value { get; set; }
public string Text { get; set; }
public bool HasChildren { get; set; }
}
and my entity mapped with Nhibernate is:
public class Entity
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Entity Parent { get; set; }
/* other properties */
}
I would like to know, how can I get a List of my DTOs and fill the HasChildren property using a count method or a subquery to know if there are childrens?
I have tried this, but does not work:
return Session.QueryOver<Entity>
.Select(entity => new TreeViewViewModel() {
Value = entity.Id.ToString(),
Text = entity.Name,
HasChildren = (Session.QueryOver<Entity>().Where(x => x.ParentId == entity.Id).RowCount() > 0)})
.ToList();
I got an exception with this: NotSupportedException and the messages says: x => (x.Parent.Id == [100001].Id) and it is not supported.
How could I create a query to fill this property?
PS: I would like to have a query to select only the Id, Name and Count... because my entity can have 30 fields or more...
Thank you.
Using the NHibernate Linq provider then you can do this:-
public class dto
{
public long Value { get; set; }
public int Count { get; set; }
public bool HasCount { get { return Count > 0; } }
}
Note: my DTO has a read-only property that looks at the actual count, the query is then:-
var a = Db.Session.Query<Support>().Select(
s => new dto {
Value = s.Id,
Count = s.CommentList.Count
}
).ToList();
This generates the following sQL
select support0_.Id as col_0_0_,
(select cast(count(*) as SIGNED)
from supportcomment commentlis1_
where support0_.Id = commentlis1_.SupportId) as col_1_0_
from support support0_
I have never seen a working example of this using QueryOver. I have had had a stab at it but couldn't get it working..
Didn't you consider the option of using something else rather than NHibernate for this job?
In my opinion, lightweight library like Dapper can be a brilliant solution for this use case. You'll end up with a resonably simple sql query instead of jiggling with Nhibernate.
Edit:
dapper code will be as simple as this:
public IDbConnection ConnectionCreate()
{
IDbConnection dbConnection = new SQLiteConnection("Data Source=:memory:;pooling = true;");
dbConnection.Open();
return dbConnection;
}
public void Select()
{
using (IDbConnection dbConnection = ConnectionCreate())
{
var query = #"SELECT e1.id as Value, e1.name as Text, CASE WHEN EXISTS
(SELECT TOP 1 1 FROM Entity e2 WHERE e2.parent = e1.id)
THEN 1 ELSE 0 END as HasChildren
FROM Entity e1";
var productDto = dbConnection.Query<TreeViewDTO>(query);
}
}

Categories