将实体及其子实体转换为DTO

时间:2018-11-29 09:54:28

标签: c# mysql entity-framework linq

尝试将实体对象转换为本地对象,以便我可以将其用于进一步的转换。

这是我用来转换实体对象的代码;

IEnumerable<SystemArea> result = (from sa in CurrentContext.systemarea                                 
                                 select new SystemArea
                                 {
                                     SystemAreaId = sa.SystemAreaId,
                                     SystemAreaCode = sa.SystemAreaCode,
                                     SystemAreaType = sa.SystemAreaType,
                                     SystemAreaDescription = sa.SystemAreaDescription,
                                     SystemAreaCreatedDate = sa.SystemAreaCreatedDate,
                                     SystemAreaUpdateDate = sa.SystemAreaUpdateDate,
                                     SystemAreaStatus = sa.SystemAreaStatus,
                                     Count = sa.systemareafunctionality.Count,
                                     SystemAreaFunctionality = sa.systemareafunctionality.Select(e => new SystemAreaFunctionality { SystemAreaCode =e.SystemAreaCode })
                                 }).ToList();

此处count变量用于确认其中是否有任何子数据。

SystemAreaFunctionality是我试图通过使用 SELECT 函数在此处进行转换的子对象,但它始终是空白集合。剩余数据已分配给父对象,但这里唯一缺少的是子表记录。我要去哪里错了,请帮忙!

生成的SQL:

SELECT
`Project3`.`C1`, 
`Project3`.`SystemAreaId`, 
`Project3`.`SystemAreaCode`, 
`Project3`.`SystemAreaType`, 
`Project3`.`SystemAreaDescription`, 
`Project3`.`SystemAreaCreatedDate`, 
`Project3`.`SystemAreaUpdateDate`, 
`Project3`.`SystemAreaStatus`, 
`Project3`.`C3` AS `C2`, 
`Project3`.`C2` AS `C3`, 
`Project3`.`SystemAreaCode1`
FROM (SELECT
`Project1`.`SystemAreaId`, 
`Project1`.`SystemAreaCode`, 
`Project1`.`SystemAreaType`, 
`Project1`.`SystemAreaDescription`, 
`Project1`.`SystemAreaCreatedDate`, 
`Project1`.`SystemAreaUpdateDate`, 
`Project1`.`SystemAreaStatus`, 
1 AS `C1`, 
`Project2`.`SystemAreaCode` AS `SystemAreaCode1`, 
`Project2`.`C1` AS `C2`, 
`Project1`.`C1` AS `C3`
FROM (SELECT
`Extent1`.`SystemAreaId`, 
`Extent1`.`SystemAreaCode`, 
`Extent1`.`SystemAreaType`, 
`Extent1`.`SystemAreaDescription`, 
`Extent1`.`SystemAreaCreatedDate`, 
`Extent1`.`SystemAreaUpdateDate`, 
`Extent1`.`SystemAreaStatus`, 
(SELECT
COUNT(1) AS `A1`
FROM `systemareafunctionality` AS `Extent2`
 WHERE `Extent1`.`SystemAreaCode` = `Extent2`.`SystemAreaCode`) AS `C1`
FROM `systemarea` AS `Extent1`) AS `Project1` LEFT OUTER JOIN (SELECT
`Extent3`.`SystemAreaCode`, 
1 AS `C1`
FROM `systemareafunctionality` AS `Extent3`) AS `Project2` ON `Project1`.`SystemAreaCode` = `Project2`.`SystemAreaCode`) AS `Project3`
 ORDER BY 
`Project3`.`SystemAreaCode` ASC, 
`Project3`.`C2` ASC

JSON输出:

  

[{“ SystemAreaId”:1,“ SystemAreaCode”:“ KIO”,“ SystemAreaType”:“ KIOSK”,“ SystemAreaDescription”:“任务   相关   接待员“,” SystemAreaCreatedDate“:” /日期(1543421018000)/“,” SystemAreaUpdateDate“:” /日期(1543421018000)/“,” SystemAreaStatus“:true,” SystemAreaFunctionality“:[],” Count“:1}] < / p>

PS:请不要建议自动映射器或扩展方法。谢谢!

4 个答案:

答案 0 :(得分:1)

使用此:

CurrentContext.systemarea.Include('systemareafunctionality')

IEnumerable<SystemArea> result = (from sa in CurrentContext.systemarea    
                             join systemareafunctionality in CurrentContext.systemareafunctionality on sa.systemareafunctionalityID equals systemareafunctionality.ID
                             select new SystemArea
                             {
                                 SystemAreaId = sa.SystemAreaId,
                                 SystemAreaCode = sa.SystemAreaCode,
                                 SystemAreaType = sa.SystemAreaType,
                                 SystemAreaDescription = sa.SystemAreaDescription,
                                 SystemAreaCreatedDate = sa.SystemAreaCreatedDate,
                                 SystemAreaUpdateDate = sa.SystemAreaUpdateDate,
                                 SystemAreaStatus = SystemAreaStatus,
                                 Count = systemareafunctionality.Count,
                                 SystemAreaFunctionality = systemareafunctionality.Select(e => new SystemAreaFunctionality { SystemAreaCode =e.SystemAreaCode })
                             }).ToList();

IEnumerable<SystemArea> result = (from sa in CurrentContext.systemarea    
                         join systemareafunctionality in CurrentContext.systemareafunctionality on sa.systemareafunctionalityID equals systemareafunctionality.ID into item1 from subitem1 in item1.DefaultIfEmpty() 
                         select new SystemArea
                         {
                             SystemAreaId = sa.SystemAreaId,
                             SystemAreaCode = sa.SystemAreaCode,
                             SystemAreaType = sa.SystemAreaType,
                             SystemAreaDescription = sa.SystemAreaDescription,
                             SystemAreaCreatedDate = sa.SystemAreaCreatedDate,
                             SystemAreaUpdateDate = sa.SystemAreaUpdateDate,
                             SystemAreaStatus = SystemAreaStatus,
                             Count = systemareafunctionality.Count,
                             SystemAreaFunctionality = systemareafunctionality.Select(e => new SystemAreaFunctionality { SystemAreaCode =e.SystemAreaCode })
                         }).ToList();

答案 1 :(得分:1)

意见:

花了我两天时间使MySQL(最新版本)与EF一起使用,并相信我这是艰苦的,相反,带有MSSQL的EF非常简单且易于实现。

我经历过的一件事是,甲骨文对提供免费的MySQL免费版本不感兴趣,因此它们在新版本的文档上草率行事,并提供不稳定的.NET连接器。

实际答案:

EF表现得很怪异,以至于只有当我要求EF将子实体的子对象(即SystemAreaFunctionalityEmployeeRoleMapping加载到SystemAreaFuncionality)时,它才将数据加载到子实体(SystemAreaFunctionality)中,这也意味着我不得不采取不必要的数据。

所以我的链接查询如下:

var result = (from sa in CurrentContext.systemarea
                          select new SystemArea
                          {
                              SystemAreaId = sa.SystemAreaId,
                              SystemAreaType = sa.SystemAreaType,
                              Count = sa.systemareafunctionality.Count,
                              SystemAreaFunctionalities = sa.systemareafunctionality.Select(saf => new SystemAreaFunctionality
                              {
                                  SystemAreaId = saf.SystemAreaId,
                                  SystemAreaFunctionalityController = saf.SystemAreaFunctionalityController,
                                  SystemAreaFunctionalityAction = saf.SystemAreaFunctionalityAction,
                                  SystemAreaFunctionalityType = saf.SystemAreaFunctionalityType,
                                  SystemAreaFunctionalityEmployeeRoleMappings = saf.systemareafunctionalityemployeerolemapping.Select(saferm => new SystemAreaFunctionalityEmployeeRoleMapping
                                  {
                                      SystemAreaFunctionalityEmployeeRoleMappingId = saferm.SystemAreaFunctionalityEmployeeRoleMappingId,
                                      SystemAreaFunctionalityCreatedDate = saferm.SystemAreaFunctionalityCreatedDate
                                  })
                              })
                          }).ToList();

替代:

这次使用PostgreSQL和npgsql连接器尝试对不同的数据库使用相同的linq查询(在OP中发布),并且令人惊讶的是,EF确实给了我我想要的东西而没有额外的负担。 最重要的是,PostgreSQL在EF方面的性能优于MySQL。因此,我认为切换到PostgreSQL将是一个更好的选择。

PS: 如果您决定使用开放源DBMS,请在使用MySQL之前先参考以下内容:

答案 2 :(得分:0)

显然您的CurrentContext是一个Dbcontext,其中至少有一个SystemAreas表和一个SystemAreaFunctionalities表。

似乎每个SystemArea都有零个或多个SystemAreaFunctionalities;每个SystemAreaFunctionality都恰好属于一个SystemArea,这是一个使用外键的直接一对多关系。

注意:可能是您有多对多关系,答案将相似

A,你忘了写课,所以我来试试看:

class SystemArea
{
    public int Id {get; set;}
    ... // other properties

    // every SystemArea has zero or more SystemAreaFunctionalities (one-to-many)
    public virtual ICollection<SystemAreaFunctionality> SystemAreaFunctionalities {get; set;}
}

class SystemAreaFunctionality
{
    public int Id {get; set;}
    ... // other properties

    // every SystemAreaFunctionality belongs to exactly one SystemArea, using foreign key
    public int SystemAreaId {get; set;}
    public virtual SystemArea SystemArea {get; set;}
}
  

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

出于完整性考虑:

class CurrentContext : DbContext
{
    public DbSet<SystemArea> SystemAreas {get; set;}
    public DbSet<SystemAreaFunctionality> SystemAreaFunctionalities {get; set;}
}

如果人们想要带有子项的项目,例如SchoolsStudentsCustomersOrders等,人们倾向于执行{{1 }}。但是,在使用实体框架时,连接很少是必需的。改为使用ICollections。实体框架知道关系并知道要执行哪个(组)联接。

我经常看到人们使用(group)Join,但是如果这样做,您将选择完整的对象,这不是很有效。假设您有一个ID为10的Include和1000 SystemArea,您知道每个SystemAreaFunctionalities都有一个值为10的外键SystemAreaFunctionality,而不是发送该值SystemAreaId仅作为SystemArea的主键一次,还将选择所有具有该值10的1000个外键。多么浪费处理能力!

  

查询数据时,请始终使用“选择”并仅选择您实际打算使用的属性。仅在计划更新包含的对象时才使用“包含”。

您写道:

  

SystemAreaFunctionality是我要在此处转换的子对象...

不清楚您真正想要什么。您是否想要所有使用过的SystemAreaCodes的集合?还是您真的想要一个仅填充一个字段的新SystemAreaFunctionalities集合:SystemAreaCode?由于使用了单个属性名称,因此似乎您不想要一个集合,而只想要一个项目。

Include

我认为空SystemAreaFunctionalities的原因是因为您忘记执行ToList()。

由于使用了ToList(),因此将自动获得所选SystemAreaFunctionalities的Count。无需单独选择此计数。

  

数据库查询的最慢部分之一是将所选数据从数据库管理系统传输到本地进程。好的做法是只选择您实际打算使用的数据

查询不是很有效,因为您选择了完整的SystemAreaFunctionalities并仅填写SystemAreaCode。所有其他字段将使用默认值填充。除了查询速度较慢之外,您还给调用者留下印象,即他们可以正确填充SystemAreaFunctionalities。改进的版本将是:

var result = currentContext.SystemAreas.Select(systemArea => new
{
     Id = systemArea.Id,
     Code = systemArea.Code,
     ...

     // if you want a collection of SystemAreaFunctionalities
     // where every SystemAreaFunctionality is filled with only SysemAreaCode
     // do the following:
     SystemAreaFunctionalities = systemArea.SystemAreaFunctionalities
          .Select(systemAreaFunctionality => new SystemAreFunctionality
          {
               SystemAreaCode = systemAreaFunctionality.SystemAreaCode,
          })
          .ToList(),   // DON'T FORGET THIS, OR YOU WON'T GET RESULTS!
    })
    .ToList()
}

当然,如果您不仅需要SystemAreaCodes,还需要几个SystemAreaFunctionalities,请选择它们:

var result = currentContext.SystemAreas.Select(systemArea => new
{
     // select only the properties you actually plan to use
     Id = systemArea.Id,
     Code = systemArea.Code,
     ...


     // if you only need the SystemAreaCodes, select only that property
     SystemAreaCodes = systemArea.SystemAreaFunctionalities
          .Select(systemAreaFunctionality => systemAreaFunctionality.SystemAreaCode)
          .ToList(),
    })
    .ToList()
};

答案 3 :(得分:0)

include应该可以为您解决问题,就像这样:

    IEnumerable<SystemArea> result = (from sa in CurrentContext.systemarea.Include("systemareafunctionality")                                 
                             select new SystemArea
                             {
                                 SystemAreaId = sa.SystemAreaId,
                                 SystemAreaCode = sa.SystemAreaCode,
                                 SystemAreaType = sa.SystemAreaType,
                                 SystemAreaDescription = sa.SystemAreaDescription,
                                 SystemAreaCreatedDate = sa.SystemAreaCreatedDate,
                                 SystemAreaUpdateDate = sa.SystemAreaUpdateDate,
                                 SystemAreaStatus = sa.SystemAreaStatus,
                                 Count = sa.systemareafunctionality.Count,
                                 SystemAreaFunctionality = sa.systemareafunctionality.Select(e => new SystemAreaFunctionality { SystemAreaCode =e.SystemAreaCode })
                             }).ToList();