Cast to decimal(18,2) in LINQ - c#

I have the following SQL Query:
SELECT
[nu_ano],
[nu_mes],
[id_projeto],
[id_fase],
'Financial Progress ("CompetĂȘncia")' as ds_categoria,
'Baseline' as ds_curva,
vl_baseline as vl_curva,
cast((vl_baseline / (pc_baseline / 100)) as decimal(18,2)) as vl_curva_total
FROM [Alvarez_Marsal].[dbo].[Schedule_Status]
And my LINQ query is like this:
var result = (from l in db.Schedule_Status
.Where(x => x.nu_mes == 12)
.Select(x => new Retorno
{
nu_ano = x.nu_ano,
nu_mes = x.nu_mes,
id_projeto = x.id_projeto,
id_fase = x.id_fase,
ds_categoria = "Financial Progress ('CompetĂȘncia')",
ds_curva = "Baseline",
vl_curva = x.vl_baseline,
vl_curva_total = decimal.Round((decimal)(x.vl_baseline / x.pc_baseline / 100), 2)
})
select l);
Transforming my LINQ query in SQL query, the result is:
SELECT
[Extent1].[nu_ano] AS [nu_ano],
[Extent1].[nu_mes] AS [nu_mes],
[Extent1].[id_projeto] AS [id_projeto],
[Extent1].[id_fase] AS [id_fase],
N'Financial Progress (''CompetĂȘncia'')' AS [C1],
N'Baseline' AS [C2],
[Extent1].[vl_baseline] AS [vl_baseline],
ROUND(([Extent1].[vl_baseline] / [Extent1].[pc_baseline]) / cast(100 as decimal(18)), 2) AS [C3]
FROM [dbo].[Schedule_Status] AS [Extent1]
WHERE 12 = [Extent1].[nu_mes]
Class Retorno
class Retorno
{
public int nu_ano { get; set; }
public short nu_mes { get; set; }
public int id_projeto { get; set; }
public int id_fase { get; set; }
public string ds_categoria { get; set; }
public string ds_curva { get; set; }
public decimal? vl_curva { get; set; }
public decimal? vl_curva_total { get; set; }
}
Given that there is no Convert.ToDecimal() in SQL language, how could I transcribe as decimal(18,2) in LINQ? is it possible? I have tried using decimal.Round() but it is not working.
The field vl_curva_total in my LINQ query is returning
3000.0000000000000000000 while correct would be to return 30000000.00

Your order of operations has changed between the two queries.
SQL Query
(vl_baseline / (pc_baseline / 100))
LINQ Query
(x.vl_baseline / x.pc_baseline / 100)
This explains the difference in the two values (3000 vs 30000000). Simply add the parentheses to your LINQ query to fix this.
(x.vl_baseline / (x.pc_baseline / 100))

Related

How can i use SQL inner join statement as query in LINQ

SELECT
Id,
No,
NetAmount,
PaidAmount,
NetAmount - PaidAmount AS AmountToBePayed
FROM
(
SELECT
m.Id,
m.No,
SUM(NetAmount) as NetAmount,
(
SELECT
COALESCE( SUM( PaidAmount ), 0 )
FROM
A_Account_Payable_Payment_Invoice
) as PaidAmount
FROM
A_Account_Payable_Invoice_M m
INNER JOIN A_Account_Payable_Invoice_Item d ON
m.Id = d.A_Account_Payable_Invoice
GROUP BY
m.Id,
m.No
) a
How can i use this query directly in LINQ C#
As you mentioned on comment section you don't want to translate SQL to LINQ, you just want to directly run this script.
To do so first you need to create class that will match with your Script like:
[DataContract()]
public class PaymentInvoiceResult
{
[DataMember]
public int Id { get; set; }
[DataMember]
public int No { get; set; }
[DataMember]
public int NetAmount { get; set; }
[DataMember]
public int PaidAmount { get; set; }
[DataMember]
public int AmountToBePayed { get; set; }
}
Then you need to use SqlQuery as following:
List<PaymentInvoiceResult> paymentInvoiceResultList = db.Database.SqlQuery<PaymentInvoiceResult>("Your Script").ToList();
You can simply use:
var results = db.ExecuteQuery(typeof(DTO), "sql query ");
Your dto should have members:
Id,
No,
NetAmount,
PaidAmount,
NetAmount - PaidAmount AS AmountToBePayed

How to query a composite id key inside a list

How can I query a composite key field in a multiple IN clause SQL?
My Subsidiary is a composite of a String and a Company
public class Company
{
public virtual String Id { get; set; }
}
public class Subsidiary
{
public virtual String Id { get; set; }
public virtual Company Company { get; set; }
}
public class Disponibility
{
public virtual String IdCompany { get; set; }
public virtual String IdSubsidiary { get; set; }
}
Currently stuck at this
var subsidiarys = session.Query<Subsidiary>().ToList();
var result = session.Query<Disponibility>().Where(x => subsidiarys.Contains(???) ).ToList();
The generated query needs to be
SELECT * FROM VW_DISPONIBILITY D
WHERE (D.COMPANY, D.SUBSIDIARY) IN (SELECT S.COMPANY, S.SUBSIDIARY FROM SUBSIDIARY S);
Not all databases support oracle multiple IN clause so the only way to do this is by concatenating multiples or.
var disjunctions = Restrictions.Disjunction();
foreach (var sub in subsidiarys)
{
disjunctions.Add(Restrictions.Where<Disponibility>(x => x.IdCompany == sub.Company.Id && x.IdSubsidiary == sub.Id));
}
var result = session.QueryOver<Disponibility>()
.Where(disjunctions)
.List<Disponibility>();
Generated SQL
SELECT
...
FROM
VW_DISPONIBILITY this_
WHERE
(
(
this_.COMPANY = :p0
and this_.SUBSIDIARY = :p1
)
or (
this_.COMPANY = :p2
and this_.SUBSIDIARY = :p3
)
...
);

Write own functions to be used in c# linq statement

I have an object
public class Product{
public int Id { get; set; }
public double Cost { get; set; }
public DateTime DatePurchased { get; set; }
public string Name { get; set; }
public string Barcode { get; set; }
public string Category { get; set; }
}
I also have a function public void TotalProductDiscountHistory(DateTime datePurchased, double cost) that does some complex maths and return the discount values from the day it was purchased to date.
I would like to basically be able to call this function inside my query statement to return the sum of all possible for all products as show below.
var query = db.Products.where(x => x.clientId == clientId)
.GroupBy(c => c.Category).Select(a => new {
Category = a.Category,
Cost = a.Sum(u => u.Cost),
TotalDiscounts = a.Sum( TotalProductDiscountHistory(a.DatePurchased,
a.Cost))
});
My questions is how do I achieve this or rather how do I create a function so that I am able to call it within a linq query statement, pass values and return a result.
Your main problem is that the EF is trying to convert the LINQ query into SQL. As there is no SQL equivalent of your function, it really has to just pluck out the data needed for that calculation, and do it after the SQL query, in code.
Linq2SQL was excellent as handling that automatically. EF (even after 6 versions), not so much.
So, we'll have to do it manually:
public double TotalProductDiscountHistory(DateTime datePurchased, double cost) {...}
class CategoryTotals
{
public int Category {get; set;}
public double Cost {get; set;}
public double TotalDiscounts {get; set;}
}
var query = from p in db.Products
where P.clientId == clientId
group p by p.Category;
var totals = new List<CategoryTotals>();
foreach(var grp in query)
{
var ct = new CategoryTotals
{
Category =grp.Category,
Cost = grp.Sum(u => u.Cost),
TotalDiscounts = grp.Sum(u=>
TotalProductDiscountHistory(u.DatePurchased, u.Cost))
};
totals.add(ct);
}

Only parameterless constructors are supported in LINQ to Entities

I have this error in my LINQ statement, however i dont understand whats the problem with it or how can i solve it:
This is my LINQ:
int year = 2016;
int month = 11;
DateTime dateFrom = new DateTime(year, month, 1);
DateTime dateTo = dateFrom.AddMonths(1);
int daysInMonth = DateTime.DaysInMonth(year, month);
var data = db_pdv.Pdv.Where(x => x.Fecha >= dateFrom && x.Fecha < dateTo);
var model_pdv = data.GroupBy(x => new { Pdv = x.Clave_PDV, Nombre_Pdv = x.Nombre_Pdv, Turno = x.Turno, Nombre_Turno = x.Nombre_Turno, Pla_ID = x.Platillo, Nombre_Platillo = x.Nombre_Platillo, Precio = x.Precio })
.Select(x => new DishVM()
{
Clave_PDV = x.Key.Pdv,
Nombre_Pdv = x.Key.Nombre_Pdv,
Turno = x.Key.Turno,
Nombre_Turno = x.Key.Nombre_Turno,
Platillo = x.Key.Pla_ID,
Nombre_Platillo = x.Key.Nombre_Platillo,
Precio = x.Key.Precio,
Days = new List<int>(new int[daysInMonth]),
Data = x
}).ToList();
And this is my "DishVM" CLass
public class DishVM
{
public string Clave_PDV { get; set; }
public string Nombre_Pdv { get; set; }
public string Turno { get; set; }
public string Nombre_Turno { get; set; }
public int Platillo { get; set; }
public string Nombre_Platillo { get; set; }
[DisplayFormat(DataFormatString = "{0:C}")]
public decimal Precio { get; set; }
public List<int> Days { get; set; }
[Display(Name = "Quantity")]
public int TotalQuantity { get; set; }
[DisplayFormat(DataFormatString = "{0:C}")]
[Display(Name = "Total")]
public decimal TotalPrice { get; set; }
public IEnumerable<Pdv> Data { get; set; }
}
How can i solve this problem?
Thanks in advance
How can I solve this problem?
Start by knowing what the problem is.
In Entity Framework, any expression that operates on a DbSet, like db_pdv.Pdv, is translated into SQL. The whole expression. In your case, this "whole expression" is model_pdv, which is structured as db_pdv.Pdv.Where(...).GroupBy(...).Select(). The expression contains new List<int>(new int[daysInMonth]). You'll understand that it's impossible to translate this into SQL; how would a database engine know how to construct a .Net List<T> object?
So how to solve it?
You could build the list first and then build the expression:
...
var daysList = new List<int>(new int[daysInMonth]);
var data = db_pdv.Pdv.Where(...
...
Precio = x.Key.Precio,
Days = daysList,
Data = x
Now you've reduced the SQL translation task to converting primitive values (integers) into SQL. EF knows perfectly well how to do that. But the result is... funny. If you check the generated SQL you see that EF converts the list of integers into some sort of a SQL table. Which looks like ...
CROSS JOIN (SELECT
0 AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
UNION ALL
SELECT
0 AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable2]
UNION ALL
SELECT
0 AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable3]
UNION ALL
...
... etcetera.
What happens here, basically, is build a list in c#, convert it into a SQL construct, let the database construct a result set, convert the result set into a list in c# -- complicated.
Another option is to run the whole statement in memory:
var data = db_pdv.Pdv.Where(x => x.Fecha >= dateFrom && x.Fecha < dateTo)
.AsEnumerable();
var model_pdv = ...
Normally, I don't advocate this approach, for reasons explained here. But in this case it would be OK, because in the end you're going to use all data (Data = x), so you won't fetch more than you need from the database.
A more profound solution would be to remove the list from the view model altogether. Redundancy is the mother of inconsistency. Why should all model instances need the same list of integers? You should be able to build the list only once where you need it to present a UI.

Using a calculated value in the OrderBy clause with EF

I'm trying to use a calculated value in my OrderBy clause in a LINQ query.
The error I am getting is:
DbArithmeticExpression arguments must have a numeric common type.
My model looks like this:
public class PostModel
{
public int ID { get; set; }
public DateTime Created { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string FilePath { get; set; }
public float Rank { get; set; }
public UserProfile Creator { get; set; }
public bool ShowPost { get; set; }
public PostModel()
{
Created = DateTime.Now;
Rank = 0;
ShowPost = false;
}
}
and I'm trying to select posts using this:
var todaysDate = DateTime.Now.AddDays(-10);
var result = _database.Posts
.Where(p => p.ShowPost == true)
.OrderBy(x => ((float)x.Rank) - (((float)(x.Created - todaysDate).TotalDays)) / 2f)
.Skip(page * StaticVariables.ResponseDataPageSize)
.Take(StaticVariables.ResponseDataPageSize)
.Select(s => new
{
id = s.ID,
rank = s.Rank,
title = s.Title,
description = s.Description
}
);
It's the order by causing the error. I first thought it was that I was not casting all my variables to the same type, but adding (float) does not seem to help.
The purpose of the code is to make make high ranking posts fall down the list over time as to allow newer information to be shown.
Any ideas?
Use EntityFunctions in LinqToEntity:
EntityFunctions.DiffDays(todaysDate, x.Created)

Categories

Resources