c# - 如何在 EF Core 中实现这种“通过之间的连接”SQL?
问题描述
我有这个 SQL:
SELECT `o`.*,
(SELECT ROUND(`o`.`norm` * `sr`.`multiplier`, 2)) AS `time`,
(SELECT ROUND(`c`.`rate` * `sr`.`multiplier`, 2)) AS `tariff`
FROM `operations` AS `o`
INNER JOIN `plan_structures` AS `ps` ON `ps`.`id` = `o`.`plan_structure_id`
INNER JOIN `plans` AS `pl` ON `pl`.`id` = `ps`.`plan_id`
LEFT JOIN `surcharges` AS `sr` ON `pl`.`pairs` BETWEEN `sr`.`pairs_min` AND `sr`.`pairs_max`
LEFT JOIN `class_rates` AS `c` ON `c`.`class` = `o`.`class`
如何在 EF Core 中实现这一点?
- 我的第一个想法是使用 DB 视图 - 这很有效,但后来我必须拥有 EF 中实体关系的所有相关表的视图。我无法将
Operation
和链接OperationView
到PlanStructure
。 - 我的第二个想法是“以某种方式”
BETWEEN
在 SQL 中加入它,但我发现这是不可能的(或者是吗?) - 虚拟列 - 在独立表之间也是不可能的。
那么...除了数据库视图还有其他方法吗?
我的实体:
public class Plan
{
public Guid Id { get; set; }
public int Pairs { get; set; }
public ICollection<PlanStructure> PlanStructures { get; set; }
}
public class PlanStructure
{
public Guid Id { get; set; }
public Plan Plan { get; set; }
public ICollection<Operation> Operations { get; set; }
}
public class Operation
{
public Guid Id { get; set; }
public int Class { get; set; }
public int Norm { get; set; }
public double Time { get; } // computed somehow
public double Tariff { get; } // computed somehow
public PlanStructure PlanStructure { get; set; }
}
public class ClassRate
{
public int Class { get; set; }
public double Rate { get; set; }
}
public class Surcharge
{
public int PairsMin { get; set; }
public int PairsMax { get; set; }
public double Multiplier { get; set; }
}
编辑:这在Operations
包含时也应该起作用 - 当我这样做时context.Plans.Include(p => p.PlanStructures).ThenInclude(s => s.Operations);
,所有这些操作都应该具有那些计算的属性。
解决方案
LEFT JOIN 可以表示为Where(...).DefaultIfEmpty()
。还Math.Round
没有翻译,所以计算是在客户端完成的。
var query =
from o in ctx.Operations
from sr in ctx.Surcharges
.Where(sr => o.PlanStructure.Plan.Pairs >= sr.PairsMin && o.PlanStructure.Plan.Pairs <= sr.PairsMax)
.DefaultIfempty()
join c in ctx.ClassRates on o.Class equals c.Class into gj
from c in gj.DefaultIfempty()
select new
{
Operation = o,
Rate = (double?)c.Rate,
Multiplier = (double?)sr.Multiplier
};
var result = query.AsEnumerable()
.Select(e => new
{
e.Operation,
time = e.Multiplier == null
? (double?) null
: Math.Round(e.Multiplier.Value * e.Operation.Norm),
tariff = e.Multiplier == null == null || e.Rate == null
? (double?) null
: Math.Round(e.Multiplier.Value * e.Rate.Value)
});
推荐阅读
- java - Antlr4 带模式的常用令牌
- r - R 中仅适用于第 n 个单词的正则表达式
- jdbc - Google BigQuery,在准备好的语句中为空值引发异常
- azure-devops - Azure Pipeline Yaml 错误:当前操作系统无法运行此任务
- expo - Expo Go 无法连接项目
- python - pip show 和 python 导入是不同的
- excel - 在文件夹内的多个文件中查找和替换文本
- mongodb - NestJS mongoose $in 运算符
- php - 我试图理解我在互联网上找到的“井字游戏”游戏代码。我坚持在那里
- julia - 在 Julia 中声明一个多元商环