Multiple data query with LINQ - c#

I have a function to get data from my database with join on it. I want to take data from different tables, how can I achieve this? I want to take "libelle_motif" which is from the table "motif_deplacement"
My function right now:
public static List<personne> getPersonne_Deplacement(int numDeplacement)
{
List<personne> desP = new List<personne>();
var query = (from Per in db.personne.ToList()
join Dep in db.deplacement_personne.ToList() on Per.num_personne equals Dep.num_personne
join Mot in db.motif_deplacement.ToList() on Dep.id_motif equals Mot.id_motif
where Dep.id_deplacement == numDeplacement
select new personne
{
nom_personne = Per.nom_personne,
num_personne = Per.num_personne,
ref_personne = Per.ref_personne,
libelle_motif = Mot.libelle_motif,
});
desP = query.ToList();
return desP;
}
And this is how my database looks like :

You will have to create a new class which will act as the model with the properties you want. Construct one of those in your select based on the included relationships.
Also it much easier to manage this query if you model your relationships in your EF entities as opposed to writing out join statements in every query.
Also notice that I removed all the calls to ToList. Your previous code was materializing all entities from each table and then joining and filtering in memory which is extremely inefficient.
public static List<SomeModel> getPersonne_Deplacement(int numDeplacement)
{
var query = from Per in db.personne
join Dep in db.deplacement_personne on Per.num_personne equals Dep.num_personne
join Mot in db.motif_deplacement on Dep.id_motif equals Mot.id_motif
where Dep.id_deplacement == numDeplacement
select new SomeModel
{
nom_personne = Per.nom_personne,
num_personne = Per.num_personne,
ref_personne = Per.ref_personne,
libelle_motif = Mot.libelle_motif,
};
return query.ToList();
}
SomeModel.cs
public class SomeModel
{
public string nom_personne {get;set;}
public string num_personne {get;set;}
public string ref_personne {get;set;}
public string libelle_motif {get;set;}
// add additional properties as needed
}

I don't know if my answer is related to your question. But why don't you use .Include()
Ex:
var result = db.personne.Include(x => x.deplacement_personne).ThenInclude(x => x.motif_deplacement)
It will give you this structure:
obj personne { nom_personne, ... , obj deplacement_personne { ... , obj motif_deplacement }
You can also select any cols with .Select() , or filter it with .Where().

Related

EF LINQ query master-details into new model

There are lots of EF master-detail questions, I've looked through most of them. I can't find any that address the syntax approach I'm using which include transformation of the EF query results into a new business model, but I'm sure there is a way.
Here is the business model to emit from the DAL (header properties not shown)
public class Order : OrderHeader, IOrder
{
public virtual List<OrderDetail> OrderDetails { get; set; } = new List<OrderDetail>();
}
Here is the query reduced to show the problem I'm facing which is loading the collection of OrderDetails at the same time of pulling the orders. I could run another query after loading the headers but that sounds very slow and clunky.
public async Task<List<Business.Models.Order>> GetSimplifyOrders()
{
var query = (from n in _context.SalesOrderHeaders
join c in _context.Customers on n.CustomerId equals c.CustomerId
join d in _context.SalesOrderDetails on n.SalesOrderId equals d.SalesOrderId
select new Business.Models.Order
{
SalesOrderNumber = n.SalesOrderNumber,
Customer = new Business.Models.Customer()
{ CompanyName = c.CompanyName,
FullName = $"{c.FirstName} {c.LastName}",
EmailAddress = c.EmailAddress},
**OrderDetails = ??**
}).AsNoTracking()
.ToList<Business.Models.Order>();
return query;
}
Can someone help me with the specific syntax to load the details inline as shown above?
Rather than doing a join at the top level, you can use another internal LINQ query to populate a collection inside of your model.
from n in _context.SalesOrderHeaders
join c in _context.Customers on n.CustomerId equals c.CustomerId
select new Business.Models.Order
{
SalesOrderNumber = n.SalesOrderNumber,
Customer = new Business.Models.Customer()
{
CompanyName = c.CompanyName,
FullName = $"{c.FirstName} {c.LastName}",
EmailAddress = c.EmailAddress
},
OrderDetails =
(from d in _context.SalesOrderDetails
where n.SalesOrderId == d.SalesOrderId
select new Business.Models.OrderDetail()
{
...
})
.ToList()
}

Dynamic Join of multiple entities based on some filter in Entity Framework

I am pretty new to Entity Framework and LINQ and I have an entity with more than 10+ other associated entities (one-to-many relationships). Now, I'm planning to make a search page in my application in which users could select which fields (i.e. those 10+ tables) they want to be considered when searching.
Now, I'm trying to write a query to achieve the above goal. Any help how I could sort this out using LINQ method syntax? I mean, to write a multiple join query based on user's choice. (i.e. which of Class1, Class2, ... to join with main Entity to finally have all the related fields in one place). Below is a sample code (Just a hunch, in fact)
if(somefilter#1)
result = db.Companies.Join(db.Channels, p => p.Id, k => k.CId,
(p, k) => new {Company = p, Channels=k});
if(somefilter#2)
result = result.Join(db.BusinnessType, ........);
if(somefilter#3)
result = result.Join(db.Values, .......);
For complex queries it may be easier to use the other LINQ notation. You could join multiple entities like this:
from myEntity in dbContext.MyEntities
join myOtherEntity in dbContext.MyOtherEntities on myEntity.Id equals myOtherEntity.MyEntityId
join oneMoreEntity in dbContext.OneMoreEntities on myEntity.Id equals oneMoreEntity.MyEntityId
select new {
myEntity.Id,
myEntity.Name,
myOtherEntity.OtherProperty,
oneMoreEntity.OneMoreProperty
}
You can join in other entities by adding more join statements.
You can select properties of any entity from your query. The example I provided uses a dynamic class, but you can also define a class (like MyJoinedEntity) into which you can select instead. To do it you would use something like:
...
select new MyJoinedEntity {
Id = myEntity.Id,
Name = myEntity.Name,
OtherProperty = myOtherEntity.OtherProperty,
OneMoreProperty = oneMoreEntity.OneMoreProperty
}
EDIT:
In case when you want to have conditional joins you can define MyJoinedEntity with all the properties you will need if you were to join everything. Then break up the join into multiple methods. Like this:
public IEnumerable<MyJoinedEntity> GetEntities() {
var joinedEntities = from myEntity in dbContext.MyEntities
join myOtherEntity in dbContext.MyOtherEntities on myEntity.Id equals myOtherEntity.MyEntityId
join oneMoreEntity in dbContext.OneMoreEntities on myEntity.Id equals oneMoreEntity.MyEntityId
select new MyJoinedEntity {
Id = myEntity.Id,
Name = myEntity.Name,
OtherProperty = myOtherEntity.OtherProperty,
OneMoreProperty = oneMoreEntity.OneMoreProperty
};
if (condition1) {
joinedEntities = JoinWithRelated(joinedEntities);
}
}
public IEnumerable<MyJoinedEntity> JoinWithRelated(IEnumerable<MyJoinedEntity> joinedEntities) {
return from joinedEntity in joinedEntities
join relatedEntity in dbContext.RelatedEntities on joinedEntity.Id equals relatedEntity.MyEntityId
select new MyJoinedEntity(joinedEntity) {
Comments = relatedEntity.Comments
};
}

How to join two or more tables in entity framework and display selected columns from each tables in data grid view

I have generated Entity from database using VS. Now when I want to join two tables from my database and show the result using datagrid view.
my LINQ is :
result = (from lang in my_entity.LANGUAGE
join c in my_entity.COUNTRY
on lang.COUNTRY_ID equals c.ID
select lang).ToList<LANGUAGE>();
dgvresult.DataSource = result;
dgvresult.Refresh();
All the columns from Language tables are shown but none are shown from Country table.
I want few columns from language and few columns from country table to be shown in datagrid view.
How do I do it. Any learning links are also appreciated.
Also I want to learn DataGrid View in detail. If any one can suggest good books or materials , please do.
You can create a new anonymous type and then bind to it, like so:
result = (from lang in my_entity.LANGUAGE
join c in my_entity.COUNTRY
on lang.COUNTRY_ID equals c.ID
select new
{
lang.Col1,
land.col2,
c.Col1,
c.Col2
}).ToList();
dgvresult.DataSource = result;
dgvresult.Refresh();
Or you can create a view model and simply select the values into it:
public class LangCountryModel
{
public string LangCol1 { get; set; }
public string LangCol2 { get; set; }
public string CountryCol1 { get; set; }
public string CountryCol2 { get; set; }
}
result = (from lang in my_entity.LANGUAGE
join c in my_entity.COUNTRY
on lang.COUNTRY_ID equals c.ID
select new LangCountryModel
{
LangCol1 = lang.Col1,
LangCol2 = land.col2,
CountryCol1 = c.Col1,
CountryCol2 = c.Col2
}).ToList();
var result = (from ob1 in lista1
join ob2 in lista2
on ob1.Id equals ob2.Id
select new
{
ob1.Age,
ob2.CarName
}).ToList();
dgvresult.DataSource = result;
dgvresult.Refresh();
Like #pingoo answer with a small edit:
You can do it without using the Join LINQ keyword by using the navigation property COUNTRY of the source table LANGUAGE like this:
result = (from lang in my_entity.LANGUAGE
select new {
lang.Col1,
lang.col2,
lang.COUNTRY.COUNTRY_ID
}).ToList();
dgvresult.DataSource = result; dgvresult.Refresh();`
(...).ToList<LANGUAGE>()
.Select(p=>new{p.LanguageProp,p.COUNTRY.COUNTRYProp,...})

How to group rows using LINQ to Entity separating values with commas?

Below is my LINQ Query, that im using to select ITEMS:
protected void Page_Load(object sender, EventArgs e)
{
whatsmydiscountEntities ctx = new whatsmydiscountEntities();
int IdRelationshipItems = Convert.ToInt32(Request.QueryString["IdRelationshipItems"]);
int IdProductService = Convert.ToInt32(Request.QueryString["IdProductService"]);
var Items = (from es in ctx.State
join ie in ctx.ItemsStates on es.StateId equals ie.StateId
join i in ctx.Items on ie.IdItem equals i.IdItem
join iir in ctx.ItemsRelationshipItems on i.IdItem equals iir.IdItem
join ir in ctx.RelationshipItems on iir.IdRelationshipItems equals ir.IdRelationshipItems
join ips in ctx.ItemsProductsServices on i.IdItem equals ips.IdItem
join ps in ctx.ProductsServices on ips.IdProductService equals ps.IdProductService
where iir.IdRelationshipItems == IdRelationshipItems
&& ips.IdProductService == IdProductService
&& ir.Active == 1
&& i.Active == 1
select new
{
ItemName = i.Name,
StateSigla = es.Sigla,
ProductServiceName = ps.Ttitle,
RelationshipItemName = ir.Name,
RelationshipItemImage = ir.Image,
RelationshipItemActive = ir.Active,
ItemSite = i.Site,
ItemDescription = i.Description,
ItemAddress = i.Address,
Iteminformationdiscount = i.information_discount,
ItemLogo = i.Logo,
ItemActive = i.Active,
StateId = ie.StateId,
IdRelationshipItems = iir.IdRelationshipItems,
IdProductService = ips.IdProductService
}).ToList();
}
As you can see, the result will be 1 row for each state, if the user passes the IdRelationshipItems and the IdProductService.
Instead of 1 row for each state with the same information, I'd like to show only 1 row and all the states separated by commas. What do I need to change to do this?
I had to solve this problem today. I have a view model that looks like this:
public class IndexViewModel
{
public string Search { get; set; }
public IPagedList<MembershipUser> Users { get; set; }
public IEnumerable<string> Roles { get; set; }
public bool IsRolesEnabled { get; set; }
public IDictionary<string,string> Tags { get; set; }
}
I needed to return a unique list of users and all of the Tags that are assigned to them as a comma separated string.
The data is stored like this:
"41FFEC0F-B920-4839-B0B5-862F8EDE25BD", tag1
"41FFEC0F-B920-4839-B0B5-862F8EDE25BD", tag2
"41FFEC0F-B920-4839-B0B5-862F8EDE25BD", tag3
And I needed output that looked something like this:
"41FFEC0F-B920-4839-B0B5-862F8EDE25BD", "tag1, tag2, tag3"
I ended up creating a List of UserId's like this (I'm using the MembershipProvider which exposes the UserId as ProviderUserKey):
var userIdList = users.Select(usr => (Guid) usr.ProviderUserKey).ToList();
The object "users" is a MembershipUser object. I then call a function in my service passing the List in like this:
Tags = _usersTagsService.FindAllTagsByUser(userIdList)
And my service function looks like this:
public IDictionary<string, string> FindAllTagsByUser(IList<Guid> users)
{
var query = (from ut in _db.UsersTags
join tagList in _db.Tags on ut.TagId equals tagList.Id
where users.Contains(ut.UserId)
select new {ut.UserId, tagList.Label}).ToList();
var result = (from q in query
group q by q.UserId
into g
select new {g.Key, Tags = string.Join(", ", g.Select(tg => tg.Label))});
return result.ToDictionary(x=>x.Key.ToString(),y=>y.Tags);
}
I'm pretty sure these two linq statements can probably be combined into one but I find it easier to read this way. Still only hits the database once.
Things to watch out for:
I was originally passing just IList users into the function FindAllTagsByUser and linq couldn't infer the type and therefore wouldn't let me use the .Contains extension method. Kept saying that linq to entities didn't support Contains.
You need to do a .ToList() on the first query to materialize it or you will get trouble from linq to entity when you try to use string.Join to create the comma separated list.
Good luck
dnash

How can I query this hierarchical data using LINQ?

I have 3 kinds of objects: Agency, BusinessUnit and Client (each with their own respective table)
In terms of hierarchy, Agencies own BusinessUnits, and BusinessUnits own Clients.
I have 3 C# POCO Objects to represent them (I usually select new {} into them, rather than use the LINQ generated classes):
public class Agency
{
public IEnumerable<BusinessUnit> BusinessUnits { get; set; }
}
public class BusinessUnit
{
public IEnumerable<Client> Clients { get; set; }
}
public class Client
{
public int NumberOfAccounts { get; set; }
public Decimal AmountOfPlacement { get; set; }
public Decimal AvgBalance { get; set; }
public Double NeuPlacementScore { get; set; }
}
You can see that Agencies contain a list of BusinessUnits, and BusinessUnits contain a list of Clients.
I also have a mapping table called BAC_Map in the database which says which owns which, and it looks something like this:
How can I construct a query, so I can query for and return a list of Agencies? Meaning that, I want each Agency to have its list of BusinessUnit objects set, and I want the list of BusinessObjects to have its list of Clients set.
I can do basic LINQ queries, but this is a little over my head concerning the Map table and the multiple? queries.
How could I construct a method like GetAllAgencies() which would query, for not only all agencies, but populate its BusinessUnits that Agency owns, and the Clients those BusinessUnits own?
Edit: Any tips or info is appreciated. Do I need to do joins? Does this need to be multiple queries to return an Agency list, with its submembers populated?
If you drop all four tables (Agency, BusinessUnit, Client, Map) on the linq to sql designer, and draw relationships from Map to the other three, there will be some useful properties on Map.
//construct a query to fetch the row/column shaped results.
var query =
from m in db.map
//where m.... ?
let a = m.Agency
let b = m.BusinessUnit
let c = m.Client
// where something about a or b or c ?
select new {
AgencyID = a.AgencyID,
AgencyName = a.Name,
BusinessUnitID = b.BusinessUnitID,
ClientID = c.ClientID,
NumberOfAccounts = c.NumberOfAccounts,
Score = c.Score
};
//hit the database
var rawRecords = query.ToList();
//shape the results further into a hierarchy.
List<Agency> results = rawRecords
.GroupBy(x => x.AgencyID)
.Select(g => new Agency()
{
Name = g.First().AgencyName,
BusinessUnits = g
.GroupBy(y => y.BusinessUnitID)
.Select(g2 => new BusinessUnit()
{
Clients = g2
.Select(z => new Client()
{
NumberOfAccounts = z.NumberOfAccounts,
Score = z.Score
})
})
})
.ToList();
If approriate filters are supplied (see the commented out where clauses), then only the needed portions of the tables will be pulled into memory. This is standard SQL joining at work here.
I created your tables in a SQL Server database, and tried to recreate your scenario in LinqPad. I ended up with the following LINQ statements, which basically result in the same structure of your POCO classes:
var map = from bac in BAC_Maps
join a in Agencies on bac.Agency_ID equals a.Agency_ID
join b in BusinessUnits on bac.Business_Unit_ID equals b.Business_Unit_ID
join c in Clients on bac.Client_ID equals c.Client_ID
select new
{
AgencyID = a.Agency_ID,
BusinessUnitID = b.Business_Unit_ID,
Client = c
};
var results = from m in map.ToList()
group m by m.AgencyID into g
select new
{
BusinessUnits = from m2 in g
group m2 by m2.BusinessUnitID into g2
select new
{
Clients = from m3 in g2
select m3.Client
}
};
results.Dump();
Note that I called map.ToList() in the second query. This actually resulted in a single, efficient query. My initial attempt did not include .ToList(), and resulted in nine separate queries to produce the same results. The query generated by the .ToList() version is as follows:
SELECT [t1].[Agency_ID] AS [AgencyID], [t2].[Business_Unit_ID] AS [BusinessUnitID], [t3].[Client_ID], [t3].[NumberOfAccounts], [t3].[AmountOfPlacement], [t3].[AvgBalance], [t3].[NeuPlacementScore]
FROM [BAC_Map] AS [t0]
INNER JOIN [Agencies] AS [t1] ON [t0].[Agency_ID] = [t1].[Agency_ID]
INNER JOIN [BusinessUnits] AS [t2] ON [t0].[Business_Unit_ID] = [t2].[Business_Unit_ID]
INNER JOIN [Clients] AS [t3] ON [t0].[Client_ID] = [t3].[Client_ID]
Here is a screenshot of the results:
alt text http://img411.imageshack.us/img411/5003/agencybusinessunitclien.png
If you are doing this with direct LINQ to SQL, there is no way to do this without some kind of recursion, whether you do it yourself or you hide it behind an extension method. Recursive SQL is very bad (many round trips, many single queries).
There are two options here. One is to pull the entire table(s) with the hierarchy into memory and use LINQ to Objects on it. Leave the "details" tables in SQL. If you have less than several thousand entities, this is probably the most efficient way to go. You can keep a single copy of the table(s) in cache and refresh them when necessary. When you need to fetch more detailed data from the DB for a single record, you can reattach that entity from your cached hierarchy to a new DataContext and fetch it.
The other option is to use a more complex relationship model in your database. Storing parent only by nature demands recursion, but you can use the adjacency list model to construct a single query which can span many levels of inheritance. This will mean your LINQ to SQL queries become less intuitive (querying against Entity.Right and Entity.Left isn't quite as pretty as Parent or Children...) but you can do in one query what might take hundreds or thousands in the literal recursive approach.

Categories

Resources