如何在Linq

时间:2017-09-01 04:57:18

标签: c# .net entity-framework linq entity-framework-core

我有3张表,其中包含以下数据&结构:

Modules

Id          Modulename
----------------------
1           Corp
2           Local
3           Medium

RuleChange

Id      CanDrop     CanLoad     SensorId
----------------------------------------
10      yes         No          113
11      Yes         No          113
12      No          Yes         113
12      No          Yes         114

Rules

Id      Message     ModuleId
----------------------------
10      Xyz         1
11      CVV         0
12      RTV         2
13      LBL         2

我需要在3个表RulesModulesRuleChange以及where子句

上执行左外连接

任务:列出所有规则及其RuleChange数据和模块名称。

SensorId = 113

预期产出:

Id      Message     Modulename      CanLoad     CanDrop
-------------------------------------------------------
10      Xyz          Corp               Yes      No
11      CVV          Null               No       Yes     
12      RTV          Local              Yes      No
13      LBL          Local              Null     Null

我尝试了什么:

var query = from sr in _context.Rules
            join m in (
                       (from md in _context.Modules
                        select new { md.Id, md.ModuleName })) on sr.ModuleId equals m.Id into moduleRule
                        from m in moduleRule.DefaultIfEmpty()
                        join t in (
                            (from e in _context.RuleChanges
                             where
         e.SensorId == sensorId
                             select new
                             {
                                 e.Sid,
                                 e.CanLoad,
                                 e.Drop
                             })) on sr.Sid equals t.Sid into RuleDiff
                        from t in RuleDiff.DefaultIfEmpty()
                        select new
                        {
                            sr.Sid,
                            sr.Message,
                            CanLoad = t.CanLoad,
                            Drop = t.Drop,
                            sr.ModuleId,
                            ModuleName = m.ModuleName
                        };

var result = query.ToList();

然而,我收到此错误:

  

NullReferenceException:对象引用未设置为对象的实例..

我认为这是由于连接操作中的空键...但我没有找到该密钥。

我注意到EF生成了一个SQL查询,它可以产生所需的输出:

SELECT 
    [t].[Id], [t].[ModuleName], 
    [t0].[Sid], [t0].[CanLoad], [t0].[Drop], 
    [sr].[Sid] AS [Sid0], [sr].[Message], [sr].[ModuleId]
FROM
    [SuricataRules] AS [sr]
LEFT JOIN 
    (SELECT 
         [md].[Id], [md].[ModuleName]
     FROM 
         [Modules] AS [md]) AS [t] ON [sr].[ModuleId] = [t].[Id]
LEFT JOIN 
    (SELECT 
         [e].[Sid], [e].[CanLoad], [e].[Drop]
     FROM 
         [RuleChanges] AS [e]
     WHERE 
         [e].[SensorId] = @__sensorId_0) AS [t0] ON [sr].[Sid] = [t0].[Sid]

2 个答案:

答案 0 :(得分:3)

在这种情况下,CanLoad属性CanLoad = t.CanLoad,的访问会导致NullReferenceException异常。因此,请使用null-conditional operator进行检查:

select new
{
    sr.Sid,
    sr.Message,
    CanLoad = t?.CanLoad,
    Drop = t?.Drop,
    sr.ModuleId,
    ModuleName = m?.ModuleName
};

使用method syntax

rules
    .GroupJoin(modules, _ => _.ModuleId, _ => _.Id, (r, ms) => new { r, ms })
    .SelectMany(_ => _.ms.DefaultIfEmpty().Select(m => new { _.r, m }))
    .GroupJoin(ruleChanges, _ => _.r.Id, _ => _.Id, (rm, rc) => new { rm, rc })
    .SelectMany(_ => _.rc.DefaultIfEmpty().Select(rc => new {_.rm, rc}))
    .Select(_ => new 
    { 
        Id = _.rm.r.Id, 
        Message = _.rm.r.Message, 
        Modulename = _.rm.m?.Modulename, 
        CanLoad = _.rc?.CanLoad, 
        CanDrop = _.rc?.CanDrop
    });

答案 1 :(得分:0)

你能用SQL编写查询吗?

我也对linq感到困惑所以当事情变得太复杂时我会这样做!

我将在sql中编写/测试我的查询,然后使用实体框架将查询粘贴到“Database.SQLQuery”方法中。您可以根据需要修改以下代码段。在这种情况下,我只返回 int 列表

中的IDClient
            using (var _context = new DB.Entities())
            {
                var IDClients = _context.Database.SqlQuery<int>("select distinct idclient FROM dbo.ReportClient LEFT OUTER JOIN dbo.ReportClientDocument ON dbo.ReportClient.IDClient = dbo.ReportClientDocument.IDClient");
                foreach (var IDClient in IDClients)
                {
                    // process the row here
                }
            }