I have been given the following skeleton code:
var test = SqlCompact(
"OrderID", "ASC", 5, 2,
out count, out sortCriteria, out sql);
This calls the SqlCompact method which performs joins of tables orders, employees and customers & then orders by the inputs e.g. "ASC" and "Column Name".
I have got the join query working but not sure how to order the results according to the input. This is my code for SqlCompact Method:
public List<MyJoin> SqlCompact(
string sort, string sortDir, int rowsPerPage, int page,
out int count, out string sortCriteria, out string sql) {
var cec = new SqlCeConnection(
string.Format(#"Data Source={0}\Northwind.sdf", Path));
var nwd = new DataContext(cec);
nwd.Log = new StringWriter();
var orders = nwd.GetTable<Order>();
var employees = nwd.GetTable<Employee>(); //
var customers = nwd.GetTable<Customer>(); //
count = orders.Count();
sortCriteria = "";
var q = (from od in orders
join em in employees on od.EmployeeID equals em.EmployeeID
join ct in customers on od.CustomerID equals ct.CustomerID
//orderby em.EmployeeID
select new
{
od.OrderID,
od.ShipCountry,
ct.CompanyName,
ct.ContactName,
FullName = em.FirstName + ' '+ em.LastName,
}).ToList();
q.Dump();
sortCriteria: a string composed from sort and sortDir – in the format directly usable by Dynamic LINQ, e.g.
OrderID ASC
ContactName DESC, OrderID DESC
This is what you want to do:
if (sort == "OrderId") {
q = q.OrderBy(x => x.OrderId);
}
Passing in the the column name as a string is not a great way to do it though.
Related
I am currently using Linq to join two tables together, mainTable and selectTable, they are joined on mainTable.ID = selectTable.mtID. I am trying to include a third table, myTable, that is joined on selectTable.ID = myTable.selID. There will be many records in myTable for one ID from selectTable so I'm trying to get List<myTable>. This is what I have so far that works:
public async Task<List<mainTableDto>> listAll()
{
var db = _repository.DbContext;
var result = await ( from mt in db.mainTable
join sel in db.selectTable
on mt.ID equals sel.mtID
select new mainTableDto
{
ID = mt.ID,
createDate = mt.createDate,
selectTable = new selectTableDto
{
ID = sel.ID
name = sel.name
}
}
}).ToListAsync;
return result;
I've tested getting data from selectTableDto with List< myTableDto> and it works.
I'm a little stuck on how to include a List<myTableDto> into this nested call. I've tried:
join sel in db.selectTableInclude(x=>x.myTableDto)
But when I do this I don't get the info from myTableDto and just get null instead (I've put data in the DB so there should be something)
I've also tried:
join sel in db.selectTable
on mt.ID equals sel.mtID
join my in db.myTable
on sel.ID equals my.selID
selectTable = new selectTableDto
{
ID = sel.ID
name = sel.name
myTableDto = new List<myTableDto>
{
ID = my.ID
}
}
But when I do this it says "ID is not a member of myTableDTO".
Any advice on what I'm doing wrong?
I believe you want a groupjoin (method syntax) or into (query syntax)
This is query syntax:
from mt in db.mainTable
join sel in db.selectTable
on mt.ID equals sel.mtID
into mainTableSels
select new mainTableDto
{
ID = mt.ID,
createDate = mt.createDate,
selectTable = from mts in mainTableSels select new selectTableDto
{
ID = mts.ID
name = mts.name
}
}
Though I do personally prefer a hybrid query/method syntax:
from mt in db.mainTable
join sel in db.selectTable
on mt.ID equals sel.mtID
into mainTableSels
select new mainTableDto
{
ID = mt.ID,
createDate = mt.createDate,
selectTable = mainTableSels.Select(mts => new selectTableDto
{
ID = mts.ID
name = mts.name
})
}
I'm not clear on what type your mainTableDto.selectTable property is; if it's an array or list you'll need a ToArray/ToList. If it's IEnumerable then it should work without
I have a GridView bound to an LinqToSql-Datasource.
The Datasource represents 3 Tables which I select with a Join in Linq-Query.
The Tables are for persons, instititutions and memberships (mitgliedschaft).
A Person could have various Memberships belonging to different institutions.
My Query gets all Memberships but in the Table are shown only informations of the person or the institution, so there are duplicated rows in the rable.
I want only one person shown, although there are 3 memberships for example.
In SQL I would do it with a left join o something else, but I am LINQ-Newbie.
My Query is:
neonDataContext db = new neonDataContext();
e.KeyExpression = "id";
e.QueryableSource = from mitgliedschaft in db.mitgliedschaft
join person in db.person on mitgliedschaft.person_id equals person.id
join institution in db.institution on mitgliedschaft.verein_id equals institution.id
select new
{
vorname = person.vorname,
nachname = person.nachname,
nameVerein = institution.name,
vereinid = mitgliedschaft.verein_id,
id = mitgliedschaft.id,
verbandsnummer = person.verbandsMitgliedsNummer,
strasse = person.strasse,
plz = person.plz,
ort = person.ort,
geburtsdatum = person.geburtsdatum,
geschlechtid = person.geschlechtid,
statusid = mitgliedschaft.statusid,
bezirk_id = mitgliedschaft.bezirk_id,
kreis_id = mitgliedschaft.kreis_id,
person_id = mitgliedschaft.person_id,
deletedFlag = mitgliedschaft.deletedFlag
};
Can someone tell me how to do distinct or left join with such a query, please?
Since you are returning an enumeration of complex objects, the Distinct() operator by itself is inapplicable. Consider creating a class to represent the Person entity in your code and having it implement the IEquatable interface. This will allow the runtime to decide when two Person objects are in fact identical, by your own custom comparison logic.
See this article for details: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinct?view=netframework-4.8
You can then use the Distinct() operator on the result set:
neonDataContext db = new neonDataContext();
e.KeyExpression = "id";
e.QueryableSource = (from mitgliedschaft in db.mitgliedschaft
join person in db.person on mitgliedschaft.person_id equals person.id
join institution in db.institution on mitgliedschaft.verein_id equals institution.id
select new Person()
{
vorname = person.vorname,
nachname = person.nachname,
nameVerein = institution.name,
vereinid = mitgliedschaft.verein_id,
id = mitgliedschaft.id,
verbandsnummer = person.verbandsMitgliedsNummer,
strasse = person.strasse,
plz = person.plz,
ort = person.ort,
geburtsdatum = person.geburtsdatum,
geschlechtid = person.geschlechtid,
statusid = mitgliedschaft.statusid,
bezirk_id = mitgliedschaft.bezirk_id,
kreis_id = mitgliedschaft.kreis_id,
person_id = mitgliedschaft.person_id,
deletedFlag = mitgliedschaft.deletedFlag
}).Distinct();
Tried several Ways to achieve the Goal (implementing distinct in different ways and implenenting distinctBy-Extension).
The only Way that works in my case was, grouping and selecting first one:
neonDataContext db = new neonDataContext();
e.KeyExpression = "id";
e.QueryableSource = (from mitgliedschaft in db.mitgliedschaft
join person in db.person on mitgliedschaft.person_id equals person.id
join institution in db.institution on mitgliedschaft.verein_id equals institution.id
select new
{
vorname = person.vorname,
nachname = person.nachname,
nameVerein = institution.name,
vereinid = mitgliedschaft.verein_id,
id = mitgliedschaft.id,
verbandsMitgliedsNummer = person.verbandsMitgliedsNummer,
strasse = person.strasse,
plz = person.plz,
ort = person.ort,
geburtsdatum = person.geburtsdatum,
geschlechtid = person.geschlechtid,
statusid = mitgliedschaft.statusid,
bezirk_id = mitgliedschaft.bezirk_id,
kreis_id = mitgliedschaft.kreis_id,
person_id = mitgliedschaft.person_id.Value,
deletedFlag = mitgliedschaft.deletedFlag
}).GroupBy(p => p.person_id).Select(p => p.First());
If you want to distinct by one field or multiple-field like person_id,you can add a extension function:
public static class CustomDistinct{
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
HashSet<TKey> seenKeys = new HashSet<TKey>();
foreach (TSource element in source)
{
if (seenKeys.Add(keySelector(element)))
{
yield return element;
}
}
}
}
Use it:
(from ... select...).DistinctBy(p => p.person_id); //one field
(from ... select...).DistinctBy(p => new{p.person_id,p.id}); //multiple-field
internal static IQueryable<TimeReviewDataModel> GetGridDetails(DiscoLlamaEntities context, string actor)
{
return (from t in context.TimeCaptures
join jc in context.JobCards on t.JobCardID equals jc.ID into jcSub
from jc in jcSub.DefaultIfEmpty()
join cu in context.Companies on jc.CustomerID equals cu.ID into cuSub
from tg in cuSub.DefaultIfEmpty()
where (t.CreatedBy == actor)
orderby t.Date descending
select new TimeReviewDataModel
{
ID = t.ID,
CustomerName = tg.Name,
Date = t.Date,
StartTime = t.StartTime,
EndTime = t.EndTime,
Description = t.Description,
Category = t.Category,
JobCardID = t.JobCardID,
VsoTask = t.VsoTaskID,
IsBillable = (bool)t.Billable
})
.OrderBy(e=>e.Date);
}
Hi, I'm trying to order my data in a grid. At the top I want the data that was entered today as the grid goes down I want the previously added entries. Currently it mixes the entries. I want to order using the Date property.
I'm using Linq and EntityFramework.
My Grid:
Try the following:
return (from t in context.TimeCaptures
join jc in context.JobCards on t.JobCardID equals jc.ID into jcSub
from jc in jcSub.DefaultIfEmpty()
join cu in context.Companies on jc.CustomerID equals cu.ID into cuSub
from tg in cuSub.DefaultIfEmpty()
where (t.CreatedBy == actor)
//orderby t.Date descending
select new TimeReviewDataModel
{
ID = t.ID,
CustomerName = tg.Name,
Date = t.Date,
StartTime = t.StartTime,
EndTime = t.EndTime,
Description = t.Description,
Category = t.Category,
JobCardID = t.JobCardID,
VsoTask = t.VsoTaskID,
IsBillable = (bool)t.Billable
})
.OrderByDescending(e=>e.Date).ThenByDescending(e=>eStartTime);
So, here you are ordering your final dataset, not an intermediate one.
I have a 3 tables Dish, Wine, Suggestion.
Then the idea is use table suggestion table to put the dish and the wine making one of them suggestion each other.
I'm using LINQ, but when one product doesn't have a suggestion he does not add to the json.
var query = (from m in db.Dish
join t in db.TypeDish on m.idTypeDish equals t.idTypeDish
join i in db.ImageDish on m.idDish equals i.idDish into g
join s in db.Suggestion on m.idDish equals s.idDish
join si in db.ImageWine on s.idWine equals si.idWine into f
where m.idTypeDish == dish
select new DishModel()
{
Name = m.name,
CalorificValue = m.calorificValue,
Price = m.price,
ShortName = m.shortName,
Time = m.manufactureTime,
Description = m.description,
UrlImageList = g.Select(i => _url + i.Image.urlImage).ToList(),
BeveragesList = new List<BeverageModel>()
{
new BeverageModel()
{
Name = s.Wine.name,
ShortName = s.Wine.shortName,
Price = s.Wine.price,
Description = s.Wine.description,
AlcoholContent = s.Wine.alcoholContent,
WineEnum = WineEnum.WhiteWine,
Region = s.Wine.Region.name,
WineCaste = s.Wine.wineCaste,
UrlImageList = f.Select(i => _url+i.Image.urlImage).ToList(),
}
}
}).ToList();
return query;
Now I have 2 items on DB, and he sends only one because the other don't have a suggestion.
The error is on joins probably, but I'm a newbie in Linq.
Thanks.
I have an Entity model with Invoices, AffiliateCommissions and AffiliateCommissionPayments.
Invoice to AffiliateCommission is a one to many, AffiliateCommission to AffiliateCommissionPayment is also a one to many
I am trying to make a query that will return All Invoices that HAVE a commission but not necessarily have a related commissionPayment. I want to show the invoices with commissions whether they have a commission payment or not.
Query looks something like:
using (var context = new MyEntitities())
{
var invoices = from i in context.Invoices
from ac in i.AffiliateCommissions
join acp in context.AffiliateCommissionPayments on ac.affiliateCommissionID equals acp.AffiliateCommission.affiliateCommissionID
where ac.Affiliate.affiliateID == affiliateID
select new
{
companyName = i.User.companyName,
userName = i.User.fullName,
email = i.User.emailAddress,
invoiceEndDate = i.invoicedUntilDate,
invoiceNumber = i.invoiceNumber,
invoiceAmount = i.netAmount,
commissionAmount = ac.amount,
datePaid = acp.paymentDate,
checkNumber = acp.checkNumber
};
return invoices.ToList();
}
This query above only returns items with an AffiliateCommissionPayment.
I'm not sure if EF supports this (nor am I sure if you are using EF2 or EF4), but this is the solution in Linq2Sql so it might be worth trying:
using (var context = new MyEntitities())
{
var invoices = from i in context.Invoices
from ac in i.AffiliateCommissions
join acp in context.AffiliateCommissionPayments on ac.affiliateCommissionID equals acp.AffiliateCommission.affiliateCommissionID into acp_join
from acp_join_default in acpg.DefaultIfEmpty()
where ac.Affiliate.affiliateID == affiliateID
select new
{
companyName = i.User.companyName,
userName = i.User.fullName,
email = i.User.emailAddress,
invoiceEndDate = i.invoicedUntilDate,
invoiceNumber = i.invoiceNumber,
invoiceAmount = i.netAmount,
commissionAmount = ac.amount,
datePaid = acp.paymentDate,
checkNumber = acp.checkNumber
};
return invoices.ToList();
}
The main change here is the into acpg after your join, and the DefaultIfEmpty line.
It's almost always a mistake to use join in LINQ to SQL and LINQ to Entities.
Guessing that the association from AffiliateCommission to AffiliateCommissionPayment is called Payment, you can just do:
using (var context = new MyEntitities())
{
var invoices = from i in context.Invoices
from ac in i.AffiliateCommissions
where ac.Affiliate.affiliateID == affiliateID
select new
{
companyName = i.User.companyName,
userName = i.User.fullName,
email = i.User.emailAddress,
invoiceEndDate = i.invoicedUntilDate,
invoiceNumber = i.invoiceNumber,
invoiceAmount = i.netAmount,
commissionAmount = ac.amount,
datePaid = (DateTime?) ac.Payment.paymentDate,
checkNumber = (int?) ac.Payment.checkNumber
};
return invoices.ToList();
}
LINQ to SQL and LINQ to Entities will both coalesce nulls. The casts are necessary because the inferred type will be based on the type of AffiliateCommissionPayment.paymentDate, which might not be nullable. If it is, you don't need the cast.