Linq to Entities strange results - c#

I have the following View in my database
SELECT YEAR(Received) AS YEAR,
MONTH(Received) AS MONTH,
LEFT(DATENAME(MONTH, Received), 3) AS MMM,
COUNT(Received) AS Submissions,
COUNT(Quoted) AS Quotes,
COUNT(Bound) AS Binders,
COALESCE (SUM(BndPremium), 0) AS Premium,
ProducerID
FROM dbo.Quote AS Q WITH (NOLOCK)
WHERE (Received >= DATEADD(year, - 1, GETDATE()))
GROUP BY ProducerID, YEAR(Received), MONTH(Received), DATENAME(MONTH, Received)
And I have added the view to my EDMX. I query the view this way:
var submissions = from s in db.WSS_PortalSubmissions
where s.ProducerID == ID
select s;
The results in 'submissions' however, is 12 copies of the first month rather than the results from the past 12 months. Running the query in Linq today I get 12 copies of the results from April 2016. If I run the query in SSMS I get the expected results, a list of the last 12 months.
I have tried .ToList(), .ToArray(), even tried some sorting of the results, but it doesn't change. It is only giving me 12 copies of the first month. Any reasons why that I can't see?

I would change the view so that there is a unique column(s) if there is not one already and make sure it is mapped as the primary key in EF.
If that is not an option try changing the code to
var submissions = from s in db.WSS_PortalSubmissions.AsNoTracking()
where s.ProducerID == ID
select s;
so that EF does not track the entity, this should force it to just return exactly the results of the query without trying to track based on a primary key.

Related

Retrieving the last values from the database - should the results be sorted?

The database stores the currency exchange rate on a given day. Each day, one currency exchange value is collected and stored in the database as:
ID (int, AI)
VALUE
DATE
1
2.5
20.01.2021
2
2.7
21.01.2021
3
2.6
22.01.2021
If I would like to calculate the average exchange rate from the last 10 days, should I first sort the data by date and only retrieve the last 10 records when downloading the data, or is it enough to download the last 10 records from the database without sorting?
You can simply do in SQL Server database
SELECT TOP 10 AVG(VALUE) AS AverageRate
FROM YourTable
ORDER BY Id DESC
Concept should be same in other relational databases.
Tables (and table expressions such as views and CTEs) in SQL represent unordered sets. To get data in a particular order, you must specify an ORDER BY clause.
In fairly generic SQL you can do
SELECT AVG(VALUE) AS AverageRate
FROM (
SELECT VALUE
FROM YourTable AS t
ORDER BY Id DESC
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY
) AS t
In some RDBMSs, instead of OFFSET FETCH, you use either LIMIT or TOP to achieve the same effect. You still need ORDER BY.
You can do it in both ways.
If you're using SQL with Dapper or ADO.NET, then you can write a query.
It should be sorted if you need the last 10 values
SELECT TOP 10 AVG(your value) AS average
FROM YourCurrencyExchangeTable
ORDER BY DATE DESC
If you're using EntityFrameWorkCore, you can write
var avg = db.yourDbContext
.Where(c => c.Date >= tenDaysAgoDate)
.Average(c => c.yourValue)
I hope my answer helps :)
Basically you have to sort first ( on date) and then get the last 10 values, so you're on the right track.

EF - IQueryable - two selects with one db call

I am carrying out a pretty normal select data from table using Entity Framework Core and IQueryable. I am using paging in my search so want to fetch rows x to y, depending on the page size and current page.
Here's my code:
_dbContext.Orders.Where(o => o.UserId == userId)
.Skip((pageNo - 1) * pageSize).Take(pageSize).ToListAsync();
And resulting SQL:
SELECT [o].[UserId], [o].[OrderId], [o].[OrderDate], [o].[OrderType], [o].[FromNameAddressId], [o].[ToNameAddressId], [o].[Status]
FROM [Orders] AS [o]
WHERE [o].[UserId] = 12
ORDER BY (SELECT 1) OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY;
The problem I'm facing is that I also want to return the total record count as part of the query results and end up (currently) having to do that as a separate call to the db.
Here is my code:
_dbContext.Orders.Where(o => o.UserId == userId).CountAsync();
And resulting SQL:
SELECT COUNT(*) FROM [Orders] AS [o] WHERE [o].[UserId] = 12;
I am looking to make this more efficient, so was looking to either return the total record count as part of the first query OR to run the two selects with one db call rather than two. Has anyone achieved this before? I'm fairly new to Entity Framework, so this is probably fairly straight forward to achieve.
Thanks in advance for any pointers!

LINQ returns wrong value for one specific column in SQL View query

My issue seems to be simple, but I can't figure out what's happening.
I have the following LINQ query:
(from p in db.VW_PROJETOS
join ic in db.vw_InstanciaCarteira
on p.CodigoProjeto equals ic.CodigoProjeto
where ic.CodigoCarteira == 125
orderby p.CodigoProjeto
select p).ToList();
It returns 9 entries from VW_PROJETOS, such as IDs, FKs, string, dates... If I execute same query in SQL Server Management Studio, as the following
select * from VW_PROJETOS p
inner join vw_InstanciaCarteira ic on p.CodigoProjeto = ic.CodigoProjeto
where ic.CodigoCarteira = 125
order by p.CodigoProjeto
it will return the same 9 entries, with the same data for each entry, except for column "Desempenho". Here's a short example:
SQL Server returns:
CodigoProjeto NomeProjeto Desempenho
13 Projeto 1 Satisfatório
1247 Projeto 2 NULL
1435 Projeto 3 Crítico
LINQ query returns:
CodigoProjeto NomeProjeto Desempenho
13 Projeto 1 Crítico
1247 Projeto 2 Crítico
1435 Projeto 3 Satisfatório
I saw some examples of using ROW_NUMBER to create indexes for the views, in order to help LINQ to not loses itself when working with views, but I couldn't make it work right (the index that was shown in SQL query was always different from the index that LINQ returns).
Is this a common issue? Is it easy to correct or workaround? It can be an error in the View itself?
EDIT:
Following some of your advices, I checked the relation between unique keys and fields in Entity Framework entities. I put several keys, properly ordered, in both EF entities, but the result was the same. I got the SQL query generated by my LINQ and it gives exactly the same result as the one I posted above. I've also generated the models again, using Code-First from Database, in order to have keys ordered by the code generation, and it was useless as well.
Use this query.
(from p in db.VW_PROJETOS
join ic in db.vw_InstanciaCarteira
on p.CodigoProjeto equals ic.CodigoProjeto
where ic.CodigoCarteira == 125
orderby p.CodigoProjeto
select new {
CodigoProjeto=p.CodigoProjeto,
NomeProjeto=p. NomeProjeto,
Desempenho=ic.Desempenho
}.ToList();
Check the data type for the column "CodigoProjeto" in both db.vw_InstanciaCarteira and db.VW_PROJETOS. They should match.

EF and LINQ query to database speed

I just wondering if I am wasting my time or is there anything I could to improve this query which in turn will improve performance.
Inside a Repository, I am trying to get the 10 most recent items
public List<entity> GetTop10
{
get
{
return m_Context.entity.Where(x => x.bool == false).OrderByDescending(x => x.Created).Take(10).ToList();
}
}
But this is taking a long time as the table its querying has over 11000 rows in it. So my question is, is there anyway I could speed up this kind of query?
I am trying to get my SQL hat on regarding performance, I know the order would slow it down, but how I could I achieve the same result?
Thanks
The particular query you posted is a potential candidate for using a filtered index. Say you have a SQL table:
CREATE TABLE Employees
(
ID INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(100),
IsAlive BIT
)
You can imagine that generally you only want to query on employees that have not (yet) died so will end up with SQL like this:
SELECT Name FROM Employees WHERE IsAlive = 1
So, why not create a filtered index:
CREATE INDEX IX_Employees_IsAliveTrue
ON Employees(IsAlive)
WHERE IsAlive = 1
So now if you query the table it will use this index which may only be a small portion of your table, especially if you've had a recent zombie invasion and 90% of your staff are now the walking dead.
However, an Entity Framework like this:
var nonZombies = from e in db.Employees
where e.IsAlive == true
select e;
May not be able to use the index (SQL has a problem with filtered indexes and parameterised queries). To get round this, you can create a view in your database:
CREATE VIEW NonZombies
AS
SELECT ID, Name, IsAlive FROM Employees WHERE IsAlive = 1
Now you can add that to your framework (how you do this will vary depending on if you are using code/model/database first) and you will now be able to decide which employees deserve urgent attention (like priority access to food and weapons):
var nonZombies = from e in db.NonZombies
select e;
From your LINQ query will be created SQL SELECT similar to this:
SELECT TOP(10) * FROM entity
WHERE bool = 0
ORDER BY Created DESC
Similar because instead of the '*' will server select concrete columns to map these to entity object.
If this is too slow for you. The error is in the database, not in the EntityFramework.
So try adding some indexes to your table.

sql Top 1 vs System.Linq firstordefault

I am rewriting an SProc in c#. the problem is that in SProc there is a query like this:
select top 1 *
from ClientDebt
where ClinetID = 11234
order by Balance desc
For example :I have a client with 3 debts, all of them have same balance. the debt ids are : 1,2,3
c# equivalent of that query is :
debts.OrderByDescending(d => d.Balance)
.FirstOrDefault()
debts represent clients 3 debts
the interesting part is that sql return debt with Id 2 but c# code returns Id 1.
The Id 1 make sense for me But in order to keep code functionality the same I need to change the c# code to return middle one.
I do not sure what is the logic behind sql top 1 where several rows match the query.
The query will select one debt and update the database. I would like the linq to return the same result with sql
Thanks
debts.OrderByDescending(d => d.Balance).ThenByDescending(d => d.Id)
.FirstOrDefault()
You can start SQL Profiler, execute stored procedure, review result, and then catch query which application send through linq, and again review result.
Also, you can easily view execution plan of you procedure, and try it to optimize, but with linq query, you cannot easily do this.
AFAIK, IN SQL if you select rows without ORDER BY, it orders the resultset based on the primary key.
With Order BY CLAUSE [field], implicitly next order is [primarykey].

Categories

Resources