简体   繁体   English

SQL 到 C# 实体框架

[英]SQL to C# Entity Framework

Can anybody jump in and help me finish my code?任何人都可以加入并帮助我完成我的代码吗? I'd like to convert this SQL Query to C# EF.我想将此 SQL 查询转换为 C# EF。 I have attached below my attempt.我在下面附上了我的尝试。 I should be able to finish the rest if I have a sample for the ReferredCode part.如果我有 ReferredCode 部分的示例,我应该能够完成 rest。

Please enlighten me if it even is possible to convert.如果甚至可以转换,请赐教。 Any help is appreciated.任何帮助表示赞赏。 Thanks!谢谢!

SQL Query SQL 查询

SELECT cd.id, 
            cd.RunOrder,
            cd.ItemId,
            code =  
                case
                    when cd.IsItemAssembly=0 or cd.IsItemAssembly is null then
                        (select cast(ma.Code as varchar) as code
                        from materials.Material ma

                        inner join materials.MaterialPrice mp
                        on ma.ID=mp.MaterialID
                        and mp.HistoryStatusID=2

                        where cd.ItemID=ma.ID
                        )
                    else
                        (select cast(ass.Code as varchar) as code
                        from Materials.tblAssemblies ass

                        where cd.ItemID=ass.Assembly_ID
                        and ass.HistoryStatusID=2
                        )
                end,
            isnull(cd.IsItemAssembly,0) as IsItemAssembly,
            cd.ReferredItemID,
            ReferredCode =
                case
                    when cd.IsReferredItemAssembly=0 or cd.IsReferredItemAssembly is null then
                        (select cast(ma.Code as varchar) as code
                        from materials.Material ma

                        inner join materials.MaterialPrice mp
                        on ma.ID=mp.MaterialID
                        and mp.HistoryStatusID=2

                        where cd.ReferredItemID=ma.ID
                        )
                    else
                        (select cast(ass.Code as varchar) as code
                        from Materials.tblAssemblies ass

                        where cd.ReferredItemID=ass.Assembly_ID
                        and ass.HistoryStatusID=2
                        )
                end,
            isnull(cd.IsReferredItemAssembly,0) as IsReferredItemAssembly,
            cd.Factor,
            cd.LinkedCalculatorID,
            cast(lc.Name as varchar) as LinkedCalcName,
            cd.CalculatorRuleID,
            cast(cr.Name as varchar) as RuleName,
            cast(cr.Code as varchar) as RuleCode

        from dbo.Calculator ch
        inner join dbo.CalculatorDetail cd
        on ch.ID = cd.CalculatorID
            and ch.IsActive = 1

        inner join dbo.CalculatorRule cr
        on cd.CalculatorRuleID=cr.ID

        left join dbo.Calculator lc
        on  lc.ID = cd.LinkedCalculatorID
            and lc.IsActive = 1


        where ch.ID=@CalculatorID

        order by cd.RunOrder

My attempt:我的尝试:

 var query = (from ch in dbContext.Calculators
                         join cd in dbContext.CalculatorDetails on ch.ID equals cd.CalculatorID where ch.IsActive == true
                         join cr in dbContext.CalculatorRules on cd.CalculatorRuleID equals cr.ID
                         join lc in dbContext.Calculators on cd.LinkedCalculatorID equals lc.ID where lc.IsActive == true
                         where ch.ID == calculatorIDParameter
                         orderby cd.RunOrder
                         select new GetCalculatorMaterialsModel
                         {
                             id = cd.ID,
                             RunOrder = cd.RunOrder,
                             ItemId = cd.ItemID,
                             
                             ReferredItemID = cd.ReferredItemID,
                             ReferredCode = 

                             IsReferredItemAssembly = cd.IsReferredItemAssembly == null ? false : true,
                             Factor = cd.Factor,
                             LinkedCalculatorID = cd.LinkedCalculatorID,
                             LinkedCalcName = lc.Name,
                             CalculatorRuleID = cd.CalculatorRuleID,
                             RuleName = cr.Name,
                             RuleCode = cr.Code
                         }).ToList();

Firstly, all of the relationships between the tables should be able to be covered by setting up navigation properties and configuring their associated FKs.首先,表之间的所有关系都应该能够通过设置导航属性和配置它们的关联 FK 来涵盖。 This avoids the need to specify Join conditions in EF Linq statements.这避免了在 EF Linq 语句中指定 Join 条件的需要。

public class Calculator
{
    [Key]
    public int Id { get; set; }
    // ...

    [ForeignKey("CalculatorDetailsId")]
    public virtual CalculatorDetails CalculatorDetails { get; set; }
}

public class CalculatorDetails
{
    [Key]
    public int Id { get; set; }
    // ...

    [ForeignKey("LinkedCalculatorId")]
    public virtual Calculator LinkedCalculator { get; set; }
    [ForeignKey("CalculatorRulesId")]
    public virtual Calculator CalculatorRules { get; set; }

    public int ItemId { get; set; }
    public int ReferredItemId { get; set; }
}

These are by no means complete but should give you some idea about what the navigation properties would look like.这些绝不是完整的,但应该让您对导航属性的外观有所了解。 I don't recommend adding properties for the FKs, but rather shadow properties to link the FK.我不建议为外键添加属性,而是建议添加阴影属性来链接外键。 This keeps the model with one source of truth for the relationship.这使 model 与关系的一个真实来源保持一致。

Where it gets ugly is your association between CalculatorDetail and either Materials or Assemblies based on the ReferredItemId.它变得丑陋的地方是您在 CalculatorDetail 与基于 ReferredItemId 的 Materials 或 Assemblies 之间的关联。 This is quite bad relational DB design as you cannot count on FK constraints to enforce referential integrity.这是非常糟糕的关系数据库设计,因为您不能指望 FK 约束来强制执行参照完整性。 This also means we cannot use navigation properties here either.这也意味着我们也不能在这里使用导航属性。

I would probably keep the initial query simple then fetch the appropriate referred item separately:我可能会保持初始查询简单,然后分别获取适当的引用项目:

var data = dbContext.Calculators
    .Where(x => x.Id == calculatorIdParameter)
    .Select(x => new GetCalculatorMaterialsModel
    {
        id = x.ID, // Is this supposed to be the calculator ID or the CalculatorDetails ID?
        RunOrder = x.CalculatorDetails.RunOrder,
        ItemId = x.CalculatorDetails.ItemID,
                             
        ReferredItemID = x.CalculatorDetails.ReferredItemID,
        IsItemAssembly = x.CalculatorDetails.IsItemAssembly ?? false,
        IsReferredItemAssembly = x.CalculatorDetails.IsReferredItemAssembly ?? false,
        Factor = x.CalculatorDetails.Factor,
        LinkedCalculatorID = x.CalculatorDetails.LinkedCalculator.ID,
        LinkedCalcName = x.CalculatorDetails.LinkedCalculator.Name,
        CalculatorRuleID = x.CalculatorDetails.CalculatorRule.ID,
        RuleName = x.CalculatorDetails.CalculatorRule.Name,
        RuleCode = x.CalculatorDetails.CalculatorRule.Code
    }).Single();

Then find and populate your Item/Referred details based on whichever table it needs to come from.然后根据需要来自哪个表来查找并填充您的 Item/Referred 详细信息。 It isn't clear from your SQL why you need to join on MaterialPrice for when all you seem to want is Material.Code, or why you would be checking on IsActive as I would assume that the IDs are unique.从您的 SQL 中不清楚为什么您需要加入 MaterialPrice,因为当您似乎想要的只是 Material.Code,或者为什么您要检查 IsActive,因为我认为 ID 是唯一的。 If they are pointing at an inactive material/Assembly you would want the code to be #Null?如果他们指向非活动材料/程序集,您会希望代码为#Null 吗?

if (data.IsItemAssembly)
    data.ItemCode = _dbContext.Assemblies
        .Where(x => x.Id == data.ItemId && x.IsActive)
        .Select(x => x.Code)
        .SingleOrDefault();
else
    data.ItemCode = _dbContext.Materials
        .Where(x => x.Id == data.ItemId && x.IsActive)
        .Select(x => x.Code)
        .SingleOrDefault();

Then the same again for setting the related item code.然后再次设置相关项目代码。

It may certainly be possible to find a way to compose this into one Linq expression, but it would arguably be a bit harder to understand, where this would work perfectly fine for loading a single detailed item.肯定有可能找到一种方法将其组合成一个 Linq 表达式,但可以说它会有点难以理解,这对于加载单个详细项目来说非常好。

Overall though it would be better to fix the relational model to better handle this relationship.总的来说,修复关系 model 以更好地处理这种关系会更好。 EF is designed to work with valid relational models and can do so quite easily and performantly. EF 旨在使用有效的关系模型,并且可以非常轻松且高效地执行此操作。 As soon as you start introducing deviations to good DB design things start to get uglier all around.一旦您开始对良好的数据库设计引入偏差,事情就会开始变得更加丑陋。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM