使用实体框架将SQL查询转换为Linq

时间:2019-04-07 17:20:22

标签: c# entity-framework linq sql-to-linq-conversion

我正在尝试将此SQL查询转换为存储库中的LINQ:

SELECT 
    ministry.Id, ministry.Name as ministry, 
    MemberGroup.Name as memberGroup
FROM 
    Ministry, MemberGroup
WHERE 
    ministry.Id = MemberGroup.MinistryId;

我的Linq尝试:

var ministries = await _context.Ministries
    .Join(_context.MemberGroups, d => d.Id, f => f.MinistryId, (d, f) => d)
    .ToList();
return ministries;

2 个答案:

答案 0 :(得分:0)

要回答此问题,我们需要查看您的Ministry和MemberGroup之间的关系如何。像EF这样的ORM的要点和功能是将其设置为了解表之间的关系,并使其自动管理联接。

例如:如果部委引用单个会员组,以在部委和会员组之间形成一对一或多对一的关系,则您可能具有类似于以下的实体结构:

(多对1)

public class Ministry
{
   public int MinistryId { get; set; }
   public string Name { get; set; }

   public virtual MemberGroup MemberGroup { get; set; }
}

public class MemberGroup
{
   public int MemberGroupId { get; set; }
   public string Name { get; set; }
}

在映射时可以使用

设置部

(EF 6) .HasRequired(x => x.MemberGroup).WithMany().Map(x => x.MapKey("MemberGroupId")

(EF核心) .HasOne(x => x.MemberGroup).WithMany().HasForeignKey("MemberGroupId")

...然后,用于检索详细信息的查询将类似于:

public class MinistryViewModel
{
   public int MinistryId { get; set; }
   public string Ministry { get; set; } 
   public string MemberGroup { get; set; }
}

var ministries = _context.Ministries
   .Select(x => new MinistryViewModel
   {
      MinistryId = x.MinistryId,
      Ministry = x.Name,
      MemberGroup = x.MemberGroup.Name
   }).ToList();

您的示例中的要点: .Select()可以填充匿名类型,但是不能(或不应)从函数中返回这些匿名类型。创建一个视图模型/ DTO,以获取要返回的数据的详细信息。不应鼓励从方法返回的实体以及从其装入的上下文之外的实体。这很容易导致错误,性能问题和安全性问题。

如果使用异步操作,则使用

await / async: var ministries =等待_context.Ministries

.Select(x => new MinistryViewModel
{
   MinistryId = x.MinistryId,
   Ministry = x.Name,
   MemberGroup = x.MemberGroup.Name
}).ToListAsync();

...将它们定位于长时间运行的查询,但最好将简单的快速查询留作同步调用。

答案 1 :(得分:0)

可惜的是,您没有给我们您的类和查询的要求,而是给了我们一些SQL语句,我们必须从中猜测您的类以及类之间的关系。

在我看来,您有一个表Ministries,其中每个Ministry至少具有属性IdName。您还有一个表MemberGroups,每个MemberGroup都有一个IdName和一个外键MemberGroupId

在我看来MinistriesMemberGroups之间存在一对多的关系:每个Ministry都具有零个或多个MemberGroups,每个{{1 }}恰好属于一个MemberGroup,这是外键指向的部。

可能一对多是相反的。或这是一对一的关系。这就是为什么我想要一个要求。如果是相反的话,答案将是相似的,但是您将获得要点。

如果您遵循Entity Framework Code first conventions,则将具有类似的课程:

Ministry

这是实体框架检测表,列和表之间的关系所需要知道的全部内容。仅当您想要偏离默认行为时,才需要属性或流畅的API

  

在实体框架中,表的列由非虚拟属性表示。虚拟属性表示表之间的关系(一对多,多对多)

如果您遵循约定,则查询将非常简单直观:

要求:为我提供所有(或某些)政府部门的ID和名称(可能还有其他属性),每个都具有其MemberGroups的名称(可能还有其他属性)< / p>

class Ministry
{
    public int Id {get; set;}
    public string Name {get; set;}

    // every Ministry has zero or more MemberGroups (one-to-many)
    public virtual ICollection<MemberGroup> MemberGroups {get; set;}
}
class MemberGroup
{
    public int Id {get; set;}
    public string Name {get; set;}

    // every MemberGroup belongs to exactly one Ministry, using foreign key
    public int MinistryId {get; set;}
    public virtual Ministry Ministry {get; set;}
}
public MyDbContext : DbContext
{
    public DbSet<Ministry> Ministries {get; set;}
    public DbSet<MemberGroup> MemberGroups {get; set;}
}

实体框架知道您的一对多关系,并且足够聪明,可以检测到为此而需要(组)联接。

顺便说一句,如果您只需要memberGroups的名称:

var result = dbContext.Ministries
    .Where(ministry => ...)               // only if you don't want all Ministries
    .Select(ministry => new
    {
        // Select only the properties that you plan to use
        Id = ministry.Id,
        Name = ministry.Name,
        ...

        MemberGroups = ministry.MemberGroups
            .Where(memberGroup => ...)       // only if you don't want all its MemberGroups
            .Select(memberGroup => new
            {
                // again: only the properties that you plan to use
                Id = memberGroup.Id,
                Name = memberGroup.Name,
                ...

                // not needed: you know the value
                // MinistryId = memberGroup.MinistryId,
            })
            .ToList(),
       });

如果您真的想自己加入GroupJoin:

...
MemberGroupNames = ministry.MemberGroups
                           .Select(memberGroup => memberGroup.Name)
                           .ToList(),

最后:如果您不希望各部委将其MemberGroups作为GroupJoin,而作为简单的联接,请使用SelectMany代替Select,或者使用Join代替GroupJoin:

var result = dbContext.Ministries.GroupJoin(
    dbContext.MemberGroup,
    ministry => ministry.Id,
    memberGroup => memberGroup.MinistryId,

    (ministry, memberGroupsOfThisMinistry) => new
    {
        Id = ministry.Id,
        Name = ministry.Name,

        MemberGroups = memberGroupsOfThisMinistry.Select(memberGroup => new
        {
            Id = memberGroup.Id,
            Name = memberGroup.Name,
            ...
        })
        .ToList(),
     });