Entity framework with "Group By" and/or "Order by" - c#

Say we've got a project that allows user to download things. On the main page, I want to show the Most downloaded files ordered by the number of download! All that using EF.
How can i do this !! I've tried many things with Group By (Its a nightmare when you've got a lot of informations in an object). And i still dunno how to do this...
var query = from details in m_context.TransactionDetails
where details.Chanson != null
group details by details.Items into AnItem
orderby AnItem.Count()
select new Item() {
IdItem = Chansons.Key.IdItem,
ItemState= Chansons.Key.ItemState,
[...This object got something like 20 including links to other objects ... ]
};
Anyone have an idea?
Thanks :o)
Oh and sorry for my english, I'm giving my best but im from Quebec (Usualy talk french).

Salut!
I'm going to guess at your data model a little, here, but I don't think you need to group:
var query = from details in m_context.TransactionDetails
where details.Chanson != null
orderby details.Items.Count() descending
select new Item
{
IdItem = details.Chanson.IdItem,
ItemState= details.Chanson.ItemState,
// ...
};
Bonne chance!
Update: For albums:
var query = from details in m_context.TransactionDetails
where details.DisqueCompact != null
orderby details.Items.Count() descending
select new Item
{
IdItem = details.DisqueCompact.IdItem,
ItemState= details.DisqueCompact.QuelqueChose...
// ...
};
You probably need two queries given your data model.

For grouping data, you can read this How-To from MSDN.

This is an example of how you should do it:
//this is a entity framework objects
CTSPEntities CEntity = new CTSPEntities();
//and this is your example query
var query = (from details in CEntity.Purchase_Product_Details
group details by new { details.Product_Details.Product_Code, details.Product_Details.Product_Name} into Prod
select new
{
PID = Prod.Key.Product_Code,
PName = Prod.Key.Product_Name,
Amount = Prod.Sum(c => c.Lot_Amount),
count= Prod.Count()
}).OrderBy(x => x.Amount);
foreach (var item in query)
{
Console.WriteLine("{0},{1},{2},{3}",item.PID,item.PName,item.Amount,item.count);
}
Console.ReadLine();

Related

LINQ troubles in C# using Entity Framework

I have a few tables and this is what I need to achieve.
This gets all the rows from one table
var FRA = from prod in _cctDBContext.Fra
where prod.ActTypeId == 1
From within that, I get all the rows where ActTypeID.
Then I need to query another table from with the ID's get from that
foreach (var item in FRA)
{
var FRSA = _cctDBContext.Frsa
.Select(p => new { p.Fraid, p.Frsa1,
p.Frsaid, p.CoreId,
p.RelToEstId, p.ScopingSrc,
p.Mandatory })
.Where(p => p.Fraid == item.Fraid)
.ToList();
}
I then need to push each one of these to Entity Framework. I usually do it this way:
foreach (var item in FRA)
{
var FinanicalReportingActivity = new FinancialReportingActivity { FinancialReportingActivityId = item.Fraid, ScopingSourceType = item.ScopingSrc, Name = item.Fra1, MandatoryIndicator = item.Mandatory, WorkEffortTypeId = 0 };
_clDBContext.FinancialReportingActivity.AddRange(FinanicalReportingActivity);
}
But because I have used 2 for each loops, I cannot get the variables to work because I cannot find a way to get local variables as the entity context.
Can anyone think of a better way to code this?
Thanks
It looks like you can do this as a single join:
var query =
from prod in _cctDBContext.Fra
where prod.ActTypeId == 1
join p in _cctDBContext.Frsa on prod.Fraid equals p.Fraid
select new
{
p.Fraid,
p.Frsa1,
p.Frsaid,
p.CoreId,
p.RelToEstId,
p.ScopingSrc,
p.Mandatory
};
It looks like you are loading data from one set of entities from one database and want to create matching similar entities in another database.
Navigation properties would help considerably here. Frsa appear to be a child collection under a Fra, so this could be (if not already) wired up as a collection within the Fra entity:
Then you only need to conduct a single query and have access to each Fra and it's associated Frsa details. In your case you look to be more interested in the associated FRSA details to populate this ReportingActivity:
var details = _cctDBContext.Fra
.Where(x => x.ActTypeId == 1)
.SelectMany(x => x.Frsa.Select(p => new
{
p.Fraid,
p.Frsa1,
p.Frsaid,
p.CoreId,
p.RelToEstId,
p.ScopingSrc,
p.Mandatory
}).ToList();
though if the relationship is bi-directional where a Fra contains Frsas, and a Frsa contains a reference back to the Fra, then this could be simplified to:
var details = _cctDBContext.Frsa
.Where(x => x.Fra.ActTypeId == 1)
.Select(p => new
{
p.Fraid,
p.Frsa1,
p.Frsaid,
p.CoreId,
p.RelToEstId,
p.ScopingSrc,
p.Mandatory
}).ToList();
Either of those should give you the details from the FRSA to populate your reporting entity.

Linq: let Count result into a specified column

I've got a table Installation which can contains one or many Equipements.
And for functionnal reasons, I've overwritten my table Installation and added a field NbrEquipements.
I want to fill this field with Linq, but I'm stuck...
Due to special reasons, there is no relation between these to tables. So, no Installation.Equipements member into my class. Therefore, no Installation.Equipements.Count...
I'm trying some stuff. Here is my code:
var query = RepoInstallation.AsQueryable();
// Some filter
query = query.Where(i => i.City.RegionId == pRegionId));
int?[] etatIds = { 2, 3 };
query = (from i in query
select new Installation
{
NbrEquipements= (from e in RepoEquipement.AsQueryable()
where e.InstallationSpecialId == i.SpecialId
&& (etatIds.Contains(e.EquEtat))
select e.SasId
).Count()
});
But with this try, I got this error:
The entity or complex type 'myModel.Installation' cannot be constructed in a LINQ to Entities query
I've tried some other stuff but I'm always turning around...
Another thing that can be useful for me: It would be great to fill a field called Equipements which is a List<Equipement>.
After that, I would be able to Count this list...
Is it possible ?
Tell me if I'm not clear.
Thanks in advance.
Here is the final code:
//In the class:
[Dependency]
public MyEntities MyEntities { get; set; }
//My Methode code:
var query = MyEntities .SasInstallations.AsQueryable();
// Some filter
query = query.Where(i => i.City.RegionId == pRegionId));
var liste = new List<Installation>();
var queryWithListEquipements =
from i in query
select new
{
Ins = i,
EquipementsTemp = (from eq in MyEntities.Equipements.AsQueryable()
where eq.SpecialId == i.SpecialId
&& (etatIds.Contains(eq.SasEquEtat))
select eq
).ToList()
};
var listWithListEquipements = queryWithListEquipements.ToList();
foreach (var anonymousItem in listWithListEquipements)
{
var ins = anonymousItem.Ins;
ins.Equipements = anonymousItem.EquipementsTemp;
ins.NumberEquipements = ins.Equipements.Count();
liste.Add(ins);
}
return liste;
By the way, this is very very fast (even the listing of Equipements). So this is working exactly has I wished. Thanks again for your help everyone!
Use an anonymous type. EF does not like to instantiate entity classes inside a query.
var results = (from i in query
select new
{
NbrEquipements= (from e in RepoEquipement
where e.InstallationSpecialId == i.SpecialId
&& (etatIds.Contains(e.EquEtat))
select e.SasId
).Count()
})
.ToList();
Notice how I used select new instead of select new Installation.
You can then use the data inside the list (which is now in memory) to create instances of type Installation if you want like this:
var installations = results.Select(x =>
new Installation
{
NbrEquipements = x.NbrEquipements
}).ToList();
Here is how to obtain the list of equipment for each installation entity:
var results = (from i in query
select new
{
Installation = i,
Equipment = (from e in RepoEquipement
where e.InstallationSpecialId == i.SpecialId
&& (etatIds.Contains(e.EquEtat))
select e).ToList()
})
.ToList();
This will return a list of anonymous objects. Each object will contain a property called Installation and another property called Equipment (which is a list). You can easily convert this list (of anonymous objects) to another list of whatever type that you want.

Implement this "not in" where clause in LINQ

I have a table here where it gets popuplated with ActiveDirectory users every night. This list included generic AD accounts used for a variety of purposes.
Examples of lastnames of generic accounts:
vendor testing
IT support
Dept1 Printer
Visitor1
Visitor2
Guest1
Guest2 and etc
I want to retrieve all records ignoring these records. Something like
select * from table where lastname not like '%visitor%'
and lastname not like "%support%"
and so on I made this query but it does not do substring comparison.
List<String> _ignoreList = new List<String> { "visitor", "test" };
IQueryable<String> _records =
from _adUserDatas in _adUserDataDBDataContext.ADUserDatas
where
_adUserDatas.accountActive.ToLower().Contains("yes")
&& _adUserDatas.staffStudentType.ToLower().Contains("neither")
&& !_ignoreList.Contains(_adUserDatas.lastName)
orderby _adUserDatas.username
select _adUserDatas.username;
Here's the resulting SQL being sent to SQL Server.
{
SELECT[t0].[username]
FROM[dbo].[ADUserData] AS[t0]
WHERE
(LOWER([t0].[accountActive]) LIKE# p0)
AND
(LOWER([t0].[staffStudentType]) LIKE# p1)
AND
(NOT([t0].[lastName] IN(#p2, #p3)))
ORDER BY[t0].[username]
}
in LINQ query above, it did not ignore a record with the lastname "only for testing acct".
Any ideas on how to implement it using LINQ?
I've search the net but nothing came up.
Thanks a lot
That is because your are checking whether ignoreList contains the LastName, try doing it the other way.. i.e Whether LastName conatins anything from the ignoreList..
&& !_ignoreList.Any( il => _adUserDatas.lastName.Contains( il ) )
This way it will check whether "only for testing acct" contains anything from { "visitor", "test" }
Hm.. it could be hard to get to work like predicate with in clausule.. My solution would be other:
var queryable = from _adUserDatas in _adUserDataDBDataContext.ADUserDatas
where
_adUserDatas.accountActive.ToLower().Contains("yes")
&& _adUserDatas.staffStudentType.ToLower().Contains("neither")
orderby _adUserDatas.username
select _adUserDatas.username;
foreach (var ignore in _ignoreList)
{
var localIgnore = ignore;
queryable = queryable.Where(userName => !userName.Contains(localIgnore))
}
var result = queryable.ToList();
The answer from pwas lead me to one that works for my situation. PredicateBuilder which is mentioned in lots of topics here in SOF.com. http://www.albahari.com/nutshell/predicatebuilder.aspx
Here's the final code:
ADUserDataDBDataContext _adUserDataDBDataContext = new ADUserDataDBDataContext();
IQueryable<String> _records = null;
Expression<Func<ADUserData,Boolean>> _whereClause = PredicateBuilder.True<ADUserData>();
_whereClause = _whereClause.And(ADUserData => ADUserData.accountActive.ToLower().Contains("yes"));
foreach (var _item in _ignoreList)
{
_whereClause = _whereClause.And(ADUserData => !ADUserData.lastName.ToLower().Contains(_item));
}
_records = _adUserDataDBDataContext.ADUserDatas
.Where(_whereClause)
.Select(ADUserData => ADUserData.fan);
return _records.ToList();

problem using foreach in linq query result

I have linq query as follows:
var result = (from Customer cust in db select new { userNameList = cust.UserName }).ToList();
i want to loop through each value in the list<>
I tried to use the foreach to accomplish this. It is stupid i could not figure it out
I'm using something like this
foreach (List<string> item in result)
{
if (item.ToString() == userName)
{
userExistsFlag = 1;
}
}
But the .net compiler is just freaking out:
and giving me these errors
Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.List'
Cannot convert type 'AnonymousType#1' to 'System.Collections.Generic.List'
Thanks in anticipation
OF ALL THESE IMPLEMENTATIONS WHICH ONE IS MOST EFFICIENT AND CONSUMES LESS RESOURCES.
IT WOULD BE KIND ENOUGH IF SOME ONE CAN CLARIFY THIS FOR ME.
Shorter using Linq:
bool userExistsFlag = result.Any( x=> x.userNameList == userName);
As suggested in the other answers you do not need to project to an anonymous type:
var userNames = (from Customer cust in db select cust.UserName).ToList();
bool userExists = userNames.Contains(userName);
Edit:
The most efficient - if you do not need the set of user names otherwise - is to query the DB directly to check whether the user name exists, so
bool userExists = db.Any( x => x.UserName == userName);
Credit goes to #Chris Shaffer in the comments and #Cybernatet's answer - he was almost there. I would suggest you accept his answer but use Any() ;-)
Try:
var result = (from Customer cust in db select new { userNameList = cust.UserName }).ToList();
userExistsFlag = result.Where(a=> a.userNameList == userName).Count() > 0;
or
userExistsFlag = (
from Customer cust in db
where cust.UserName = userName
select cust
).Count() > 0;
If your query returns a list of names, your FOREACH loop should look like this
foreach( String name in results ){
...
}
Skip using new { userNameList = cust.UserName } which is making it an anonymous instance. You can try
var result = (from Customer cust in db select cust.UserName ).ToList();
if you're just getting the one property and want a list of strings there is no reason to use an anonymous type. code should work like this:
var result = (from Customer cust in db select cust.UserName).ToList();

Linq to SQL: DataTable.Rows[0]["ColumnName"] equivalent

Consider this:
var query = from r in this._db.Recipes
where r.RecipesID == recipeID
select new { r.RecipesID, r.RecipesName };
How would i get individual columns in my query object without using a for-loop?
Basicly: how do I translate DataTable.Rows[0]["ColumnName"] into Linq syntax?
It's really unclear what you are looking for, as your two samples are compatible.
As close as I can figure, what you want is:
var rows = query.ToList();
string name = rows[0].RecipesName;
string name = this._db.Recipes.Single(r => r.RecipesID == recipeID).RecipesName;
This is the way to go about it:
DataContext dc = new DataContext();
var recipe = (from r in dc.Recipes
where r.RecipesID == 1
select r).FirstOrDefault();
if (recipe != null)
{
id = recipe.RecipesID;
name = recipe.RecipesName;
}
Sorry, misunderstood your question. As others are saying, you can use ToList() to get a List back. An alternative if all you need is the first one, just use:
query.First().ColumnName
or if you want to avoid an exception on empty list:
var obj = query.FirstOrDefault();
if (obj != null)
obj.ColumnName;
Original Answer (so the comment makes sense):
Use Linq to Datasets. Basically would be something like:
var query = from r in yourTable.AsEnumerable()
select r.Field<string>("ColumnName");

Categories

Resources