Linq select instead of foreach - c#

I have two collections
var campaigns = new List<Campaigns>();
IEnumerable<CampaignsDb> campaignsFromDB = db.Campaigns
.Where(c => (c.IsDeleted == false))
.OrderBy(c => c.ScheduleTime)
.ToArray();
Next I'm filling one collection from another using foreach() :
foreach (var campaign in campaignsFromDB)
{
campaigns.Add(new Campaigns { CampaignID = campaign.CampaignID, OwnerID = campaign.CreatedBy, AccountID = campaign.AccountID });
}
Can I use Select() linq method instead of foreach loop ?

Unless you need the original empty list to start with (e.g. to add some other campaigns first), you can use:
var campaigns = campaignsFromDB
.Select(c => new Campaigns
{
CampaignID = c.CampaignID,
OwnerID = c.CreatedBy,
AccountID = c.AccountID
})
.ToList();
However, that will still have fetched the complete campaign information from the database in order to populate campaignsFromDB. That's fine if you need that array for some other reason, but if not, you could make it more efficient by putting the projection into the query:
var campaigns = db.Campaigns
.Where(c => !c.IsDeleted)
.OrderBy(c => c.ScheduleTime)
.Select(c => new Campaigns
{
CampaignID = c.CampaignID,
OwnerID = c.CreatedBy,
AccountID = c.AccountID
})
.ToList();

Yes. Just
var campaigns = db.Campaigns
.Where(c => (c.IsDeleted == false))
.OrderBy(c => c.ScheduleTime)
.Select(c => new Campaigns { CampaignID = c.CampaignID, OwnerID = c.CreatedBy, AccountID = c.AccountID })
.ToList();
or if you need the source set from the database too
var campaignsFromDB = db.Campaigns
.Where(c => (c.IsDeleted == false))
.OrderBy(c => c.ScheduleTime)
.ToArray();
var campaigns = campaignsFromDB
.Select(c => new Campaigns { CampaignID = c.CampaignID, OwnerID = c.CreatedBy, AccountID = c.AccountID })
.ToList();

Yes, like this:
var campaigns = db.Campaigns
.Where(c => !c.IsDeleted)
.OrderBy(c => c.ScheduleTime)
.Select(c => new Campaigns
{
CampaignID = c.CampaignID,
OwnerID = c.CreatedBy,
AccountID = c.AccountID
})
.ToList();

Related

Entity Framework get all columns with group by

we are migrating reports from SQL to EF. In the process I just stumbled over the following query:
SELECT
pl.clientid,
pl.loginname,
COUNT(*)
FROM
(
SELECT
DISTINCT
s.clientid,
s.doctype
FROM
Specifications s
) A
INNER JOIN portal_logins pl ON A.clientid = pl.clientid
WHERE
A.clientid != '0'
GROUP BY
A.clientid,
A.doctype
My current solution is the following
return await _nfContext.Specifications
.Select( x => new
{
Clientid = x.Clientid,
Doctype = x.Doctype
})
.Distinct()
.Join(
_nfContext.PortalLogins,
s => s.Clientid,
p => p.Clientid,
(spec, login) => new
{
loginName = login.Loginname,
clientId = spec.Clientid,
doctype = spec.Doctype
}
)
.Where(x => x.clientId != "0")
.GroupBy(c => new
{
c.clientId,
c.doctype,
c.loginName
})
.Select(result => new TotalActiveConnections
{
ActiveConnections = result.Count(),
ClientId = result.Key.clientId,
LoginName = result.Key.loginName
})
.OrderByDescending(x => x.ActiveConnections)
.ToListAsync()
.ConfigureAwait(false);
My problem is, I need all three columns as described in the Group by, but I don't want to group by login name. Does anyone have an idea what I can do? Thanks in advance for the help....
You should just use Min or Max to get any random login value
.GroupBy(c => new
{
c.clientId,
c.doctype
})
.Select(result => new TotalActiveConnections
{
ActiveConnections = result.Count(),
ClientId = result.Key.clientId,
LoginName = result.Min(g => g.loginName),
})
Presumably it worked in SQL because you were using MySQL/MariaDB and did not have ONLY_FULL_GROUP_BY turned on.

How to sort data based on CreatedUtc Date using mongodb query in c#?

I want to sort the data based on CreatedUtc time. I have tried to use Reverse function, it seems to work out but still looking for some alternate option.
var result = _participantRepo.AsQueryable().Where(x => x.Id == ParticipantId).SelectMany(x =>
x.Relations).ToList().Where(x => x.UserId != AppUserId).Select(r => new RelationVM
{
IsOwner = r.UserId == participant.CreatedByUserId,
FirstName = r.FirstName,
LastName = r.LastName,
Email = r.Email,
UserId = r.UserId,
RelationType = r.RelationType,
Role = r.Role,
IsAccepted = r.IsAccepted,
AvatarUrl = r.AvatarUrl,
CreatedUtc = r.CreatedUtc
}).Reverse().ToList();
There are 2 things you need to concern:
You can sort the elements of a sequence by using OrderBy
You should not .ToList() when you have not done, So you might to read LINQ deferred (or immediate?) execution to have a better understanding.
As a result, your query should look like this
var result = _participantRepo.AsQueryable().Where(x => x.Id == ParticipantId).SelectMany(x =>
x.Relations).Where(x => x.UserId != AppUserId).Select(r => new RelationVM
{
IsOwner = r.UserId == participant.CreatedByUserId,
FirstName = r.FirstName,
LastName = r.LastName,
Email = r.Email,
UserId = r.UserId,
RelationType = r.RelationType,
Role = r.Role,
IsAccepted = r.IsAccepted,
AvatarUrl = r.AvatarUrl,
CreatedUtc = r.CreatedUtc
}).Reverse().OrderBy(g => g.CreatedUtc).ToList();
How about .OrderBy(g => g.CreatedUtc) ?

LINQ not sorting List<> properly

My EF query is supposed to be sorting by the date of the first Product in the list, but for some reason, it only sorts most of the products and some of the dates are in the wrong order.
Here's the code...
using (var context = new SalesEntities())
{
var groupedData = context.s84_Schedule.AsExpandable()
.Where(predicate)
.GroupBy(c => new { c.CustomerID, c.s84_Customer.CustomerName, c.SubdivisionID, c.s84_Subdivision.SubdivisionName, c.LotNumber })
.Select(grouped => new s84_Report_Project_POCO
{
CustomerID = grouped.Key.CustomerID,
CustomerName = grouped.Key.CustomerName,
SubdivisionID = grouped.Key.SubdivisionID,
SubdivisionName = grouped.Key.SubdivisionName,
LotNumber = grouped.Key.LotNumber,
Products = grouped.Select(x => new s84_Report_Project_Product
{
ProductID = x.ProductID,
ProductName = x.s84_Product.ProductName,
ProductDate = x.CustomerExpectedDate,
FieldRepID = x.FieldRepID,
FieldRepName = x.s84_FieldRep.FieldRepName,
InstallerID = x.InstallerID,
InstallerName = x.s84_Installer.InstallerName,
StatusID = x.StatusID,
StatusColor = x.s84_Status.StatusColor,
StatusName = x.s84_Status.StatusName,
Completed = x.Completed
}).ToList()
});
var finalList = groupedData.ToList().Where(x => x.Products.Last().Completed == false).ToList();
List<s84_Report_Project_POCO> lst = finalList.OrderBy(x => x.Products.First().ProductDate).ToList();
return lst;
}
Code seems good to me, but look at how one of the dates is out of order...
weird sorting http://www.84sales.com/weird_sort.png
Try doing the order by on the inital select
var groupedData = context.s84_Schedule.AsExpandable()
.Where(predicate)
.GroupBy(c => new { c.CustomerID,
c.s84_Customer.CustomerName,
c.SubdivisionID,
c.s84_Subdivision.SubdivisionName,
c.LotNumber })
.Select(grouped => new s84_Report_Project_POCO
{
CustomerID = grouped.Key.CustomerID,
CustomerName = grouped.Key.CustomerName,
SubdivisionID = grouped.Key.SubdivisionID,
SubdivisionName = grouped.Key.SubdivisionName,
LotNumber = grouped.Key.LotNumber,
Products = grouped
.Select(x => new s84_Report_Project_Product
{
ProductID = x.ProductID,
ProductName = x.s84_Product.ProductName,
ProductDate = x.CustomerExpectedDate,
FieldRepID = x.FieldRepID,
FieldRepName = x.s84_FieldRep.FieldRepName,
InstallerID = x.InstallerID,
InstallerName = x.s84_Installer.InstallerName,
StatusID = x.StatusID,
StatusColor = x.s84_Status.StatusColor,
StatusName = x.s84_Status.StatusName,
Completed = x.Completed
}).OrderBy(x => x.CustomerExpectedDate).ToList()
});
The problem is the .First() function, witch returns the first record, but not necessarly in date order. if you wich to order your grouped datas by date so that the First() function returns the most recent date, you'll need to order your datas before grouping them, and then REorder your results with the First()function :
using (var context = PrimaryConnection.returnNewConnection())
{
var groupedData = context.s84_Schedule.AsExpandable()
.Where(predicate)
.GroupBy(c => new { c.CustomerID, c.s84_Customer.CustomerName, c.SubdivisionID, c.s84_Subdivision.SubdivisionName, c.LotNumber })
.Select(grouped => new s84_Report_Project_POCO
{
CustomerID = grouped.Key.CustomerID,
CustomerName = grouped.Key.CustomerName,
SubdivisionID = grouped.Key.SubdivisionID,
SubdivisionName = grouped.Key.SubdivisionName,
LotNumber = grouped.Key.LotNumber,
Products = grouped
.Select(x => new s84_Report_Project_Product
{
ProductID = x.ProductID,
ProductName = x.s84_Product.ProductName,
ProductDate = x.CustomerExpectedDate,
FieldRepID = x.FieldRepID,
FieldRepName = x.s84_FieldRep.FieldRepName,
InstallerID = x.InstallerID,
InstallerName = x.s84_Installer.InstallerName,
StatusID = x.StatusID,
StatusColor = x.s84_Status.StatusColor,
StatusName = x.s84_Status.StatusName,
Completed = x.Completed
}).Orderby(t => t.CustomerExpectedDate).ToList()
});
var finalList = groupedData.ToList().Where(x => x.Products.Last().Completed == false).ToList();
List<s84_Report_Project_POCO> lst = finalList.OrderBy(x => x.Products.First().ProductDate).ToList();
All SQL queries (and hence Linq queries, when attached to a SQL database) have a random order, unless you sort them.
Products is not sorted - hence it has a random order.
You sort by Products.First(), but Products has a random order, so your sort will also be random.
Make sure Products is sorted within the query, and you should be ok.
Products = grouped.Select(....)
.OrderBy(x => x.ProductDate)
.ToList()

Select inside select (SQL to lambda linq expression)

Select Label,
(SELECT COUNT(*) from [CourtSessions] cs where cs.iDCity = Cit.ID) as courts,
(Select COUNT(*) from [Cases] c inner join [CourtSessions] cs ON c.ID = cs.iDCase where cs.iDCity = Cit.ID) as csnatures
FROM Cities Cit
Group by Label, id
I tried this but it doesn't work
var data = db.Cities
.GroupBy(a => a.label)
.Select(g => new
{
city = g.Key,
sessions = db.CourtSessions.Include(p => p.CityTB).Count(o => o.CityTB.label == g.Key),
cases = db.Cases.Join(db.CourtSessions, u => u.ID, ui => ui.iDCase, (u, ui) => new { u, ui }).Count(m => m.ui.CityTB.label == g.Key)
});
Where CityTB is a foreign key
Cases (ID ...)
Cities (ID, Label)
CourtSession (ID, iDCase, iDCity ... CasesTB, CityTB)
I am getting this exception
base {System.Exception} = {"LINQ to Entities does not recognize the method 'System.Linq.IQueryable1[LawbookMVC.Models.CourtSession] Include[CourtSession,City](System.Linq.IQueryable1[LawbookMVC.Models.CourtSession], System.Linq.Expressions.Expression1[System.Func2[LawbookMVC.Mod...
Thanks.
Well i solved it, thanks you all
var dat = db.Cities
.GroupBy(a => new { a.label, a.ID})
.Select(g => new
{
city = g.Key.label,
sessions = db.CourtSessions.Count(o => o.iDCity == g.Key.ID),//,
cases = db.Cases.Join(db.CourtSessions, u => u.ID, ui => ui.iDCase, (u, ui) => new { u, ui }).Count(m => m.ui.CityTB.label == g.Key.label)
});

How AliasJoin in QueryOver for this sample

The Person class has a association by Identity class (one-to-one) FirstName and LastName are a property of Person class also Sex and BirthDate are a property of Identity class.
I have a sql query as the following examples:
select FirstName,LastName,Identity.Sex,Identity.BirthDate from Person_Person as Person
inner join Person_Identity as Identity on Person.Id = Identity.Person_id_fk
WHERE FirstName like '%jack%' and LastName like '%smit%'
I convert it into QueyOver.
var q = SessionInstance.QueryOver<Person>();
if (!String.IsNullOrEmpty(searchPersonDto.FirstName)) //necessary
q = q.Where(p => p.FirstName.IsLike(searchPersonDto.FirstName, MatchMode.Anywhere));
if (!String.IsNullOrEmpty(searchPersonDto.LastName)) //necessary
q = q.Where(p => p.LastName.IsLike(searchPersonDto.LastName, MatchMode.Anywhere));
Person aliasPerson = null;
q = q.SelectList(list => list
.Select(p => p.Id).WithAlias(() => aliasPerson.Id)
.Select(p => p.FirstName).WithAlias(() => aliasPerson.FirstName)
.Select(p => p.LastName).WithAlias(() => aliasPerson.LastName)
.Select(p => p.Identity.Sex).WithAlias(() => aliasPerson.Identity.Sex)
.Select(p => p.Identity.BirthDate).WithAlias(() => aliasPerson.Identity.BirthDate))
.TransformUsing(Transformers.AliasToBean<Person>());
q.List<Person>();
But join in this query is not correct. It throw a exceotion by this message :
could not resolve property: Identity.Sex of: Domain.Entities.Person
How I should join Identity by Person?
Updated : Add the similar linq query
var q = SessionInstance.Query<Person>()
.Where(p => p.FirstName == searchPersonDto.FirstName)
.Select(p => new Person(p.Id)
{
FirstName = p.FirstName,
LastName = p.LastName,
Identity = new Identity()
{
Sex = p.PersonIdentity.Sex,
BirthDate = p.Identity.BirthDate
}
}).ToList<Person>();
I need to a query by QueryOver similar to above query by Linq.
Update2: not pretty but here goes
var results = q
.JoinAlias(p => p.Identity, () => identityAlias)
.SelectList(list => list
.Select(p => p.Id)
.Select(p => p.FirstName)
.Select(p => p.LastName)
.Select(p => identityAlias.Sex)
.Select(p => identityAlias.BirthDate)
.List<object[]>()
.Select(values => new Person((int)values[0])
{
FirstName = (string)values[1],
LastName = (string)values[2],
Identity = new Identity()
{
Sex = (string)values[3],
BirthDate = (DateTime)values[4],
}
})
.ToList<Person>();
Update: from your comments i would say, this is what you need.
code to fill a PersonDto
PersonDTO aliasDTO = null;
q = q
.JoinAlias(p => p.Identity, () => identityAlias)
.SelectList(list => list
.Select(p => p.Id).WithAlias(() => aliasDTO.Id)
.Select(p => p.FirstName).WithAlias(() => aliasDTO.FirstName)
.Select(p => p.LastName).WithAlias(() => aliasDTO.LastName)
.Select(p => identityAlias.Sex).WithAlias(() => aliasDTO.Sex)
.Select(p => identityAlias.BirthDate).WithAlias(() => aliasDTO.BirthDate))
.TransformUsing(Transformers.AliasToBean<PersonDTO>())
.List<PersonDTO>();
Orginal Answer:
q.JoinAlias(p => p.Identity, () => identityAlias)
// and later
.Select(p => identityAlias.Sex)
Update: in the code posted the AliasToBeanTransformer is not needed at all
var q = SessionInstance.QueryOver<Person>();
if (!String.IsNullOrEmpty(searchPersonDto.FirstName)) //necessary
q = q.Where(p => p.FirstName.IsLike(searchPersonDto.FirstName, MatchMode.Anywhere));
if (!String.IsNullOrEmpty(searchPersonDto.LastName)) //necessary
q = q.Where(p => p.LastName.IsLike(searchPersonDto.LastName, MatchMode.Anywhere));
var results = q.Fetch(p => p.Identity).Eager
.List<Person>();

Categories

Resources