I am trying to write a query to collect the Job number, start date, customer name, Model, and completion date for jobs at my work. To get this info, I look at 3 different tables, using joins to put them together. Here are the three tables:
STAGE - (stages each job goes through during production)
ORDER - (this is where I get the customer's name)
JOBS (start date, completion date, job number, model)
So most of the info is from the JOBS table. But I'm joining onto the ORDER table by Job Number (JobNum) to obtain the customer's name. Here's what the query looks like. I created it in SQL before I tried to translate it into one of my ViewModels:
var CompletedTrucksQuery =
(from FA in context.JOBS
join ORD in context.ORDER on FA.ORGANIZATION_ID equals ORD.ORGANIZATION_ID
where FA.ORDER_NUMBER == ORD.ORDER_NUMBER
join StageF in context.STAGE on FA.JobNum equals StageF.JobNum
where StageF.StageID == 325
join TruckComp in context.STAGE on FA.JobNum equals TruckComp.JobNum
where TruckComp.StageID == 327
join INSP in context.STAGE on FA.JobNum equals INSP.JobNum
where INSP.StageID == 487
orderby StageF.CompDate descending, FA.JobNum ascending
select new {FA.JobNum, FA.StartDate, ORD.CUSTOMER_NAME, FA.MODEL_NAME, StageF.CompDate});
At this point, I'm wanting to select the
Job number (from JOBS),
the start date, (From JOBS),
the Customer's name (from ORDER),
the Model of product (from JOBS),
and the date it was completed in StageF (from STAGE)
as you can see in my select statement. I DO have an object to hold each of these called CompJob, and have tried to do a 'group by' and select a new CompJob and set the properties, but I can't seem to group it right and get 'access' to all of the properties I want to set. Here's an excerpt of what I'm talking about:
group new {FA.JobNum, O = ORD} by StageF into grp
select new CompletedTruck
{
JobNum = grp.Key.JobNum,
StartDate = grp. //???
}
As you can tell I stopped, because for some reason I couldn't 'find' the start date. I know it's something to do with my grouping. I'm very new to linq and databases, in general.
MY QUESTION: What's the best way I can select these columns of interest into my
ObservableCollection<CompJob> CompJobList;
so that I may use it in my scrollviewer in a view?
Thanks to everyone for helping me out. I solved the issue and this is what I did. I followed Gert Arnold's suggestion of selecting a new CompJob object. This would set each row of the query to a new object:
select new CompJob {JobNum = FA.JobNum, StartDate = FA.StartDate, Customer = ORD.CUSTOMER_NAME,.....}
and then said
).ToList();
At the end of the query. Then I set my ObservableCollection to the list returned by my query:
CompJobList = CompletedTrucksQuery ;
Thanks again for helping me out; I know I'm new to all of this!
Related
I have a console app that processes orders generated since 18:30 on the previous day. The method returns an array of order numbers.
The first operation is to retrieve a list of orders from a table called Docstore (which contains orders that have been printed, which are the only orders that are needed) into an array:
string[] orders;
using (var db = new TCRContext())
{
var query = from docs in db.Docstore
where docs.DateCreated >= fromDate && docs.DocumentType == "InvoiceCredit"
select docs.PrimaryKey.Trim();
orders = query.Distinct().ToArray();
}
Typically there may be at most 40 such orders. There are a couple of further considerations. First, there's a database VIEW called MatchingCustomerOrders which JOINs Orders (from the actual Order table, not the Docstore table) onto another table CPCustomers which contains a subset of all the company's Customers who participate in this particular operation (about 90 out of 2,370).
CREATE OR ALTER VIEW [dbo].[MatchingCustomerOrders]
AS
SELECT
Orders.order_no,
Orders.invoice_date
FROM
Orders INNER JOIN
dbo.CPCustomer ON Orders.customer = dbo.CPCustomer.Customer
WHERE
(dbo.CPCustomer.IsDeleted = 0)
GO
So we only need orders that match these customers. And we want to restrict them to those which match the invoice date parameters (i.e. from 18:30 the previous day to now) and also we don't want to process orders that have already been processed (hence the ProcessedInvoices part)
var query = from matches in db.MatchingCustomerOrders
where orders.Contains(matches.order_no.Trim()) &&
!(from processed in db.ProcessedInvoices select processed.order_no.Trim()).Contains(matches.order_no.Trim()) &&
matches.invoice_date >= fromDate.Date && matches.invoice_date <= toDate
select matches.order_no;
orders = query.Distinct().ToArray();
This is not particularly performant because the VIEW MatchingCustomerOrders has 90,000+ rows, and my suspicion is that LINQ is operating over the whole set. I've been banging my head trying to refactor this but none of my solutions seems to work.
Lets suppose I have a table called Transactions
Transactions has the following columns
OrderId,
OrderType (Can be 0 = Sale or 1 = Purchase) <--- this can increase
Amount
Now I want to get the relevant data based on the OrderType
if OrderType = 0 then join from Sale Table else Join from Purchase Table.
Currently what I am doing is that doing three calls to the database to get the some other values from the other tables(which works but highly inefficient in long run as 3 Calls are bad performance wise).
My solution is using left join with SQL
SELECT ap.*,
coalesce(s.orderNo,p.orderNo) as orderNo
FROM apptransactions AS ap
LEFT JOIN sales AS s ON (ap.orderType = 0 and ap.orderId = s.id)
LEFT JOIN purchases AS p ON (ap.orderType = 1 and ap.orderId = p.id);
how can this query be converted to EF Core?
Why is your query not like this?
var results = context.Transactions.Select(t =>
new
{
/* t.column list, there's no t.* in LINQ */,
OrderNo = t.OrderType == 0 ? t.Sale.OrderNo : t.Purchase.OrderNo
});
Let EF generate any underlying joins it needs to, concern yourself with getting the results you want.
This also alludes to what #caius mentions. Your model is likely not high level enough or incorrectly mapped.
I'm a junior developer and trying to convert the following linq statement to T-SQL:
var items = from u in DataContext.Users_SearchUsers(searchPara.UserFirstName,
searchPara.UserLastName,
searchPara.UserEmailAddress,
fetchOptions.page,
fetchOptions.rp,
fetchOptions.sortname,
fetchOptions.sortorder)
.ToList()
join a in DataContext.UserAccesses
.Where(x => x.Access.AccessTypeId == 4).ToList() on u.UserID equals a.UserId into accessGroup
select new {};
Can one please help me ? into accessGroup ---> (very important)
First of all you need to understand where your data is coming from. You are loading information from Users_SearchUsers on the one hand and UserAccesses on the other hand. The first query looks like
select <somecolumns>
from users
where <somefilters>;
(you need to use your actual columns and criteria, but Users_SearchUsers is not specified in the question at all). I have ignored paging here for the sake of simplicity
The second query looks like this:
select *
from user_accesses
where access_type_id = 4;
Let's join the two:
select <someoutercolumns>
from
(
select <someinnercolumns>
from users
where <somefilters>
) t1
join
(
select <someotherinnercolumns>
from user_accesses
where access_type_id = 4
) t2
on t1.user_id = t2.user_id;
These queries are probably not the exact solutions you need, but you want the answers to improve, then improve your question.
The requirement makes sense if the LINQ query is very slow. In that case you will need to refactor it in the following manner:
select <somecolumns>
from users
join user_accesses
on users.user_id = user_accesses.user_id and user_accesses.access_type_id = 4
where <somefilters>;
you can use this code
select *(you can put your columns instead *)
from Users
join UserAccesses
on Users.userid = UserAccesses.userid
where UserAccesses.typeid = 4;
I am trying to figure out how to get all the notifications from relations that get multiple notifications, because i want to combine these notifications to 1 notification so the relation wil only get 1 e-mail instead of multiple.
I created the following SQL statement, which for as far as i can tell does what i want:
select distinct r.Notificatie
, r.RelatieNr
FROM [configuratie].[dbo].[NotificatieRecID] r
join [configuratie].[dbo].[Notificatie] n on r.Notificatie = n.ID
where n.Verzonden = 0
and r.RelatieNr in(select RelatieNr from [configuratie].[dbo].[NotificatieRecID]
group by RelatieNr having count(*) > 1)
order by r.RelatieNr
It returns the following
Notification Relation
3A2A53B9-D92A-4504-874D-5A901AD01041 114147
4C499F6C-53C8-49E0-B529-8B045819BE10 114147
AF4ED8CB-D033-47A4-96AE-F379BB484532 114147
977885C5-4C12-431B-AB72-59383B1824C6 303327
3A2A53B9-D92A-4504-874D-5A901AD01041 303327
4C499F6C-53C8-49E0-B529-8B045819BE10 303327
AF4ED8CB-D033-47A4-96AE-F379BB484532 303327
Later in my c# code i will get all the values from the different notifications and simply combine them but first i need to write this SQL statement in a way i can use it with linq in c#.
I have no idea how to do SELECT DISTINCT, and r.RelatieNr in and group by RelatieNr having count(*) > 1
Could someone provide me with an example? (it does not have to be 1 linq statement, i've kind of figured that's impossible, though i would like as little temporary Lists/Iqueriables since the tables are huge)
You can use the following
var details= (from r in NotificatieRecID
join n in Notificatie on r.Notificatie=n.ID
where n.Verzonden=0 &&
(from t in NotificatieRecID
group t by t.RelatieNr into grp
where grp.Count()>1
select grp.Key).Contains(r.relatieNr)
select new {
Notificate=r.Notificatie,
RelatieNr=r.RelatieNr
}).Distinct();
I have this hql query, which works perfect:
select m
from Media m
join m.Productlines p
join m.Categories c
join m.Spaces sp
join m.Solutions so
where m.Uid != 0
and p.Uid in (:productlines)
and c.Uid in (13)
and sp.Uid in (52)
and so.Uid in (15,18)
group by m.Uid
But now it needs to be parameterized/made dynamic, not only the parameters, but also the joins (it is possible to select only from Media, without any joins, and so no *.Uid in will be required in this case).
I dont want to mess around with a StringBuilder instance and build the hql query that way, I would rather like to use the Criteria API, but I cant get a
SELECT m.*
....
GROUP BY m.Uid
query to work with Criteria.
If I add a
Projections.GroupProperty("Uid")
to my query, nhibernate selects
SELECT m.Uid
....
GROUP BY m.Uid
which is of course wrong.
After that, I also need to count the unique rows the query returned, as the result is paged.
So, my other query is quite similiar, but I cant find a Criteria equivalent for
SELECT COUNT(DISTINCT m.Uid)
Here is the HQL:
select count(distinct m.Uid)
from Media m
join m.Productlines p
join m.Categories c
join m.Spaces sp
join m.Solutions so
where m.Uid != 0
and p.Uid in (:productlines)
and c.Uid in (13)
and sp.Uid in (52)
and so.Uid in (15,18)
How can this be done with Criteria API?
Please, (N)Hibernate experts - help me with this, I cant find a working solution. Any help is greatly appreciated!
Group columns are implicitly returned as result, but you can add more columns. AFAIK, you can return full entities:
var query = session.CreateCriteria(typeof(Media), "m")
.Add(Projections.GroupProperty("m"))
.Add(Restrictions.NotEq("m.Uid", 0));
// dynamically add filters
if (filterProductLines)
{
query
.CreateCriteria("m.Productlines", "p")
.Add(Restrictions.Eq("p.Uid", productLines));
}
// more dynamic filters of this kind follow here...
IList<Media> results = query.List<Media>();
To count the full number of results you can just build up the same query with different projection:
var query = session.CreateCriteria(typeof(Media), "m")
.SetProjection(Projections.CountDistinct("m.Uid"));
// rest of the query the same way as above
long totalNumberOfResults = query.UniqueResult<long>();
I'm getting unsure about the Projections.GroupProperty("m"), you need to try this. If it doesn't work, you could make it an DetachedQuery that only returns ids:
var subquery = DetachedCriteria.For(typeof(Media), "m")
.Add(Projections.GroupProperty("m.Uid"))
.Add(Restrictions.NotEq("m.Uid", 0));
// add filtering
var query = session.CreateCriteria(typeof(Media), "outer")
.Add(Subqueries.PropertyIn("outer.Uid", subquery));
IList<Media> results = query.List<Media>();
This creates a sql query like this:
select outer.* // all properties of Media to create an instance
from Media outer
where outer.Uid in (
select Uid
from media m
where // filter
)
var count = session.CreateCriteria(typeof(Media))
// Add other criterias...
.SetProjection(Projections.CountDistinct("Id")) // or whatever the id property of Media class is called
.UniqueResult<long>();
As to your GROUP BY question, the query:
SELECT m.*
....
GROUP BY m.Uid
makes no sense because you need to select only columns that appear in the group by clause or aggregate functions. Could you elaborate a little more as to what exactly are you trying to achieve?