How to create linq query to join rows into string? - asp.net-mvc

I have a table with the following fields:
Id Name Score Event
(1 John 2 3)
(2 John 4 3)
(3 john 5 3)
and I would like to get the following result:
(John, "2 +4+5", 11(Total score))
I'm trying to combine the results to show the sum in a string format then show the sum result.
Can anyone please help me with this issue.
Thank you,
Franciso

You need to call the toList() method before using methods like string.Format or string.Join because they are not supported by Linq to SQL.
You should modify your code into something like this:
var group = (from Classificacao in _dbSet.classificacao
from Evento in _dbSet.evento
where Classificacao.class_id_Evento == id_evento
where Evento.id_evento == id_evento
group Classificacao by new
{
Classificacao.class_atletaNome,
Classificacao.class_numAtleta,
Classificacao.class_atletaEquipa,
Classificacao.class_paisAtleta,
Evento.even_name,
Evento.local.local_nome,
Evento.compTipo.CompTipo_name
} into g).ToList()
The idea is to materialize the query into a list before calling the methods.
var model = group.Select(g => new
{
g.Key.class_numAtleta,
g.Key.class_atletaEquipa,
g.Key.class_atletaNome,
g.Key.class_paisAtleta,
class_fianlAtleta = g.Sum(c => c.class_fianlAtleta.Value),
class_classGeral = g.Min(c => c.class_fianlAtleta.Value),
class_nome = g.Key.even_name,
local_nome = g.Key.local_nome,
CompTipo_name = g.Key.CompTipo_name,
class_40ponto = ((from u in g
where u.class_id_Evento == id_evento
group u by new
{
u.class_atletaNome,
u.class_fianlAtleta
}
into k
select new
{
//Score = string.Concat(k.Key.class_fianlAtleta.ToString(), " + ", g.Key.class_atletaNome)
Score = string.Format("{0}",k.Key.class_fianlAtleta)
})).Select(c=>c.Score).FirstOrDefault()
}).OrderBy(c => c.class_fianlAtleta).ThenBy(c => c.class_classGeral)).toList();
I can't check if the code is correct therefore I leave it to you, anyway once you have your List in memory you can apply the methods supported by Linq to entity.

Here is my code:
var model = (from Classificacao in _dbSet.classificacao
from Evento in _dbSet.evento
where Classificacao.class_id_Evento == id_evento
where Evento.id_evento == id_evento
group Classificacao by new
{
Classificacao.class_atletaNome,
Classificacao.class_numAtleta,
Classificacao.class_atletaEquipa,
Classificacao.class_paisAtleta,
Evento.even_name,
Evento.local.local_nome,
Evento.compTipo.CompTipo_name
} into g
select new
{
g.Key.class_numAtleta,
g.Key.class_atletaEquipa,
g.Key.class_atletaNome,
g.Key.class_paisAtleta,
class_fianlAtleta = g.Sum(c => c.class_fianlAtleta.Value),
class_classGeral = g.Min(c => c.class_fianlAtleta.Value),
class_nome = g.Key.even_name,
local_nome = g.Key.local_nome,
CompTipo_name = g.Key.CompTipo_name,
class_40ponto = ((from u in g
where u.class_id_Evento == id_evento
group u by new
{
u.class_atletaNome,
u.class_fianlAtleta
}
into k
select new
{
//Score = string.Concat(k.Key.class_fianlAtleta.ToString(), " + ", g.Key.class_atletaNome)
Score = string.Format("{0}",k.Key.class_fianlAtleta)
})).Select(c=>c.Score).FirstOrDefault()
}).OrderBy(c => c.class_fianlAtleta).ThenBy(c => c.class_classGeral);de here

You need something like this:
var result = table
.GroupBy(t => new { t.Name, t.Event })
.ToList()
.Select(t => new
{
Name = t.Key.Name,
JoinedScores = string.Join(" + ", t.Select(group => group.Score).ToArray()),
TotalScore = t.Sum(group => group.Score).ToString() + " (Total Score)"
}).ToList();
The first call to the ToList() method is needed because Linq to SQL will not support the calls to string.Join(). I'm not sure but probably you can replace it with a call to AsEnumerable().

Related

Date formatting from model is not working for datatype date

Hi I have on e query where I need to format date in MM/dd/YYYY format but it is but working
I have tried query as
var query = (from sr in db.StudentRequests
join r in db.Registrations on sr.RegistrationId equals r.RegistrationId
join cc in db.Campus on r.CampusId equals cc.CampusId
join c in db.Classes on sr.ClassId equals c.ClassId
from tc in db.TutorClasses.Where(t => t.ClassId == sr.ClassId).DefaultIfEmpty()
from srt in db.StudentRequestTimings.Where(s => s.StudentRequestId == sr.StudentRequestId).DefaultIfEmpty()
from tsr in db.TutorStudentRequests.Where(t => t.StudentRequestId == srt.StudentRequestId && t.TutorId == registrationid).DefaultIfEmpty()
from r1 in db.Registrations.Where(t => t.RegistrationId == tsr.TutorId).DefaultIfEmpty()
where tc.RegistrationId == registrationid
orderby sr.CreatedOn descending
select new
{
StatusId = tsr.StatusId == null ? 1 : tsr.StatusId,
Time = db.StudentRequestTimings.Where(p => p.StudentRequestId == sr.StudentRequestId)
.Select(p => p.FromTime.ToString() + "-" + p.ToTime +" " +p.Date+ "<br/>"),
}).ToList().GroupBy(p => new { p.StudentRequestId }).Select(g => g.First()).ToList();
Here at down you can see the time where p.date is there currently it is showing format as YYYY/MM/dd format but I want it to shown MM/dd/YYYY format
On Model side I had tried doing as
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public Nullable<System.DateTime> Date { get; set; }
but still not working
On controller side I had tried converting to format like below
Time = db.StudentRequestTimings.Where(p => p.StudentRequestId == sr.StudentRequestId).
Select(p => p.FromTime.ToString() + "-" + p.ToTime + " " + Convert.ToString(Convert.ToDateTime(p.Date).ToString("MM/dd/yyyy")) + "<br/>")
but in this case it is giving error as
Additional information: LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated into a store expression.
I had also made use of converting to as enumerable
var model = query.AsEnumerable().Select(x => new TutorDashboard
{
Name = x.Name,
Phone = x.Phone,
Email = x.Email,
ProfilePicture = x.ProfilePicture,
TutorReviewRequestID = x.TutorReviewRequestID,
StudentRequestId = x.StudentRequestId,
RegistrationId = x.RegistrationId,
Location = x.Location,
PaymentMethod = x.PaymentMethod,
CreatedOn = x.CreatedOn,
AcceptedOn = x.AcceptedOn,
ClassName = x.ClassName,
CampusName = x.CampusName,
StripeId = x.StripeId,
AvailableMonth = Month,
AvailableYear = Year,
StatusId = x.StatusId == null ? 1 : x.StatusId,
Time = string.Join("", x.Time),
}).ToList().ToPagedList(page ?? 1, 10);
Change this
Convert.ToString(Convert.ToDateTime(p.Date).ToString("MM/dd/yyyy"))
to this:
p.Dated.HasValue? ((DateTime)p.Dated).ToString("dd/MM/yyyy") : ""
Your LINQ query is translated into SQL statements, and thus there are limitations to writing LINQ. Type conversations are included in those limitations.
However, you can do formatting elsewhere too like in View.
#Model.Date.ToString("MM/dd/YYYY");
If you don't want to bother, you can set your Culture to enUS and use .ToShortDateString() as well.
To use ToString("format_string") method from LINQ to Entities query, you need to materialize into IEnumerable object first with AsEnumerable() method:
var time = db.StudentRequestTimings.Where(p => p.StudentRequestId == sr.StudentRequestId)
.AsEnumerable() // insert this method
.Select(p => p.FromTime.ToString() + "-" + p.ToTime + " " + Convert.ToString(Convert.ToDateTime(p.Date).ToString("MM/dd/yyyy")) + "<br/>");
Then, pass IEnumerable<string> result to anonymous type part of second query:
var query = (from sr in db.StudentRequests
join r in db.Registrations on sr.RegistrationId equals r.RegistrationId
join cc in db.Campus on r.CampusId equals cc.CampusId
join c in db.Classes on sr.ClassId equals c.ClassId
from tc in db.TutorClasses.Where(t => t.ClassId == sr.ClassId).DefaultIfEmpty()
from srt in db.StudentRequestTimings.Where(s => s.StudentRequestId == sr.StudentRequestId).DefaultIfEmpty()
from tsr in db.TutorStudentRequests.Where(t => t.StudentRequestId == srt.StudentRequestId && t.TutorId == registrationid).DefaultIfEmpty()
from r1 in db.Registrations.Where(t => t.RegistrationId == tsr.TutorId).DefaultIfEmpty()
where tc.RegistrationId == registrationid
orderby sr.CreatedOn descending
select new
{
...
Time = time,
...
}).ToList().GroupBy(p => new { p.StudentRequestId }).Select(g => g.First()).ToList();
If you have large amount of stored data, besides materialization you can use either view formatting or using separate string property to display formatted date:
#* Display in view *#
#Model.Date.ToString("MM/dd/yyyy")
// using string property in viewmodel class for formatted DateTime
public string FormattedDate
{
get { return Date.ToString("MM/dd/yyyy"); }
}
NB: Entity Framework's LINQ to Entities tries to convert all query methods to SQL statements, currently ToString("format_string") has no SQL statement equivalent associated to that method unlike ToString() has (similar to CONVERT(VARCHAR(n), #Date)).
Similar issue:
How can I convert DateTime to String in Linq Query?

Select query from 2 table using entity framework

select p.ProduitNom,v.VonduDate,p.ProduitPrix from Produits p,Vondus v
where p.ProduitId = v.ProduitId and p.CentreId=1
How to do this request in entity framework ?
You can do that as shown below.
Inner Join :
from p in db.Produits
join v in db.Vondus on p.ProduitId equals v.ProduitId
where p.CentreId=1
select new {
ProduitNom = p.ProduitNom,
VonduDate = v.VonduDate,
ProduitPrix = p.ProduitPrix
}
If you would like to learn,you can refer this : Queries in LINQ to Entities
You can use Join:
EDIT:
You should have a context to connect with Database first, or else, at least 2 lists:
List<Produits> Produits = new List<Produits>();
List<Vondus> Vondus = new List<Vondus>();
Then using below lambda expression:
var res = Produits.Join(Vondus, p => p.ProduitId, v => v.ProduitId,
(p, v) => new { p, v })
.Where(pv => pv.p.ProduitId == pv.v.ProduitId && pv.p.CentreId == 1)
.Select(pv => new { pv.p.ProduitNom, pv.v.VonduDate, pv.p.ProduitPrix)
.ToList();
The res will be a list containts of ProduitNom, VonduDate and ProduitPrix

LINQ Join with where condition

I can use LINQ's Join with Lambda notations no problem, but I can't work out how one would then add a where condition.
var q = query.Join(context.CustomerIds,
x => x.CustomerId,
y => y.CustomerId,
(x, y) => new CustomerLookupResult()
{
dob = x.DateOfBirth.ToString(),
forenames = x.Forenames,
surname = x.Surname,
loyaltyNo = y.Identifier,
customerId = x.CustomerId
});
The table I'm joining the first to contains the loyaltyNo in its Identifier column, but also contains other information in the same column and so uses a second column IdentifierTypeCode to allow filtering.
So how do I now add .Where(x => x.IdentifierTypeCode == "LOYALTY") like I would in SQL. Appending this to end refers to the new object.
You could apply your Where before doing the join.
var q = customerLoyalties
.Where(x => x.IdentifierTypeCode == "LOYALTY")
.Join(customers,
x => x.CustomerId,
y => y.CustomerId,
(x, y) => new CustomerLookupResult()
{
CustomerId = y.CustomerId,
Name = y.Name,
IdentifierTypeCode = x.IdentifierTypeCode
});
You can also use this way to achieve that using Linq.
var match = from t1 in context.orders
join t2 in context.orderdetails on
new { t1.OrderID } equals
new { t2.OrderID }
join t3 in context.products on
new { t2.ProductID } equals
new { t3.ProductID }
where t3.ProductID == id
select t3;
return match.ToList();
The first parameter to the Join takes any IEnumerable, so you can apply the Where at that point, or earlier
var q = query.Join(context.CustomerIds.Where(x=>x.IdentifierTypeCode=="LOYALTY"),
x => x.CustomerId,
y => y.CustomerId,
(x, y) => new CustomerLookupResult()
{
dob = x.DateOfBirth.ToString(),
forenames = x.Forenames,
surname = x.Surname,
loyaltyNo = y.Identifier,
customerId = x.CustomerId
});
alternatively, if you don't like to put too much on one line:
var filteredLoyalties = context.CustomerIds.Where(x=>x.IdentifierTypeCode=="LOYALTY");
var q = query.Join(filteredLoyalties,
...

Need help to build an EF query with LEFT JOIN

I can't find the correct way to build an EF (4.1) query that will return the same result as this SQL containing a LEFT JOIN:
SELECT
s.id_service,
s.description,
x.id_service as isDisponible
FROM
role.service_disponible s
LEFT JOIN
role.service_disponible_x_ue x
ON s.id_service = x.id_service AND x.id_ue = 1 and flg_actif = '1'
In fact I'm just trying to obtain the complete list of services disponible (ServiceDisponible) adding a field that tell me if service is disponible for a specific entity (filtered with the id_ue) which information come from a many to many related table (ServiceDisponibleXUe).
My model is:
Ideally, I would like this query to return this viewModel object what is basically my serviceDisponible domain with one more field indicating the disponibility of the service.
public ServiceDisponibleViewModel(ServiceDisponible ServiceDisponible, bool isDisponible)
{
this.serviceDisponible = serviceDisponible;
this.isDisponible = isDisponible;
}
What I have so far is this query but the syntax is invalid:
services = context.ServiceDisponible
.Select(a => new ServiceDisponibleViewModel
{
c => new ServiceDisponible
{
id_service = a.id_service,
description = a.description
},
isDisponible = a.ServiceDisponibleXUe
.Any(b => b.flg_actif && b.id_ue == idUe)
}).ToList();
Try this:
ServiceDisponibleViewModel services =
from sd in context.ServiceDisponible
from sdx in context.ServiceDisponibleXUe
.Where(x => x.id_ue == 1 && flg_actif == '1' && x.id_service == sd.id_service)
.DefaultIfEmpty()
select new ServiceDisponibleViewModel(
new ServiceDisponible
{
id_service = sd.id_service,
description = sd.description
},
sdx.id_service
);
Having SQL as example often makes one jump to a join in linq. But using navigation properties produces much more succinct syntax:
from sd in context.ServiceDisponible
from sdx in sd.ServiceDisponibleXUes.Where(x => x.id_ue == 1
&& x.flg_actif == "1")
.DefaultIfEmpty()
select new
{ sd.id_service,
sd.description,
isDisponible = sdx.id_service
};
(I couldn't help using the plural form of ServiceDisponibleXUe which imo is more clear).

Issue With Showing Distinct fields using Linq

var getAllProducts = _productService.GetAllProducts();
if (productstest.Count > 0)
{
model.idproduct.Add(new SelectListItem()
{
Value = "0",
Text = _localizationService.GetResource("Common.All")
});
foreach (var m in getAllProducts)
model.idproduct.Add(new SelectListItem()
{
Value = m.Id.ToString(),
**Text = m.Size.Distinct().ToString(),**
Selected = model.Pid == m.Id
});
}
public virtual IList<Product> GetAllProducts(bool showHidden = false)
{
var query = from p in _productRepository.Table
orderby p.Name
where (showHidden || p.Published) &&
!p.Deleted
select p;
var products = query.ToList();
return products;
}
The issue is even i tried to populate the select list with distinct size using: Text = m.Size.Distinct().ToString(), but it shows the duplicate for instance 100 products are of size 33 cm , the list will populate the dropdownlist in the view with 33cm occuring 100 times , I dont want to show 100 times , just want to show 1 time, Can any one assist me with this issue ?
Presumably you are only trying to show one product of each different size... if so initialising your getAllProducts variable like so will do the trick:
var getAllProducts = _productService.GetAllProducts().GroupBy(p => p.Size).Select(g => g.First());

Resources