问题描述
有3个实体,以这种方式表示:
**1 - entity**
class A
int id ;
int Name;
[Foreign key]
int id_B;
List C;
**2 - entity**
class B
int id ;
int Name;
List A;
**3 - entity**
class C
int id;
int Name;
[Foreign Key]
int id_A;
创建了一个实体DTO(只有外键,一切都一样)
1
class ADTO
int id ;
int Name;
List C;
2
class BDTO
int id ;
int Name;
List A;
3
class CDTO
int id;
int Name;
现在请求看起来像这样:
var quer = (await _context.A
.Include(b => b.B)
.Include(c => c.C)
.Where(u => u.Id == 1).ToListAsync())
.Select(a => new ADto
{
Id = a.Id,//How to get information about entity B here by converting to DTO
C = a.C.Select(cdto => new CDTO{ Id = cdto.Id,Name = cdto.Name}).ToList(),});
如何通过转换为DTO在此处获取有关实体B的信息?
解决方法
通常,我建议您实现一个接口,该接口在结果对象的构造函数中提供
如此:
public interface IDbOjbect{
int Id {get;set;}
string Name{get;set;}
}
然后在您的DTO对象上
public Class DtoObject {
public DtoOjbect(IDbOjbect source)
{
//Mapping done here.
}
}
因为这样您就可以在任何持久层对象上实现该接口,并且映射仍将起作用。
因为linq查询很简单:
DbOjbectList.Select(x => new DtoObject(x));
提供的DtoOjbect实现了该接口。
您的C看起来像这样:
public partial class C {
public int id {get;set;}
public string Name {get;set;}
}
public partial class C : IDbOjbect {
}
,您的CDTO如下:
public Class CDTO{
public int Id {get;set;}
public string Name {get;set;}
public CDTO(IDbOjbect source)
{
Id = source.Id;
Name = source.name;
}
}
想从B制作DTO吗?
在您的B上实施IDbOjbect
使用
public partial class B {
public int id {get;set;}
public string Name {get;set;}
}
public partial class B : IDbOjbect {
}
现在任何C或B都可以制成CDTO。
最好的部分是,您可以为B和C创建一个通用方法,在通用定义后使用“ Where”关键字,然后使用Interface作为类型,现在您可以创建一个执行相同操作的方法基于接口实现的东西,如果在A上实现接口,这对A也适用。
无需进一步修改。
现在您问的是问题,原来的问题就没有了,让我们扩展一下。
假设您有一个ResumeInfo对象,只有B可用。
然后将NullPointer模式与接口隔离原理一起使用。
因此您可以在resumeInfo类上创建一个接口
示例:
public interface IResumeInfo
{
string PlaceOfEmployment {get;set;}
DateTime StartOfEmployment {get;set;}
DateTime? EndOfEmployment {get;set;}
}
然后在您的ResumeInfo对象上:
public partial class ResumeInfo
{
string PlaceOfEmployment {get;set;}
DateTime StartOfEmployment {get;set;}
DateTime? EndOfEmployment {get;set;}
}
public partial class ResumeInfo : IResumeInfo
{
}
然后可以说您想要一个DTO对象:
public class DTOUserAndResume
{
public int id {get;set;}
public string Name {get;set;}
string PlaceOfEmployment {get;set;}
DateTime StartOfEmployment {get;set;}
DateTime? EndOfEmployment {get;set;}
public DTOUserAndResume(IDbOjbect source,IResumeInfo resumeInfo)
{
Id = source.Id;
Name = source.name;
PlaceOfEmployment = resumeInfo.PlaceOfEmployment;
StartOfEmployment = resumeInfo.StartOfEmployment ;
EndOfEmployment = resumeInfo.EndOfEmployment ;
}
}
现在在B上?我想您说您有简历数据,但没有C信息?
您在两者上都实现了IResumeInfo,但是在B上,您仅获得了任何数据,但是在C上却没有数据? NullOjbect模式。
实施接口,但使其不返回任何内容。
因此PlaceOfEmployment始终为“”或Null。 起始数据始终为1900-01-01 00:00:00或任何您希望“无”的对象都不能为空的对象,而在工作结束时为null。
因此,您只是声称数据是不存在的数据集的等同物,因为它没有要提供的数据集。
但是您不需要制作新的DTO,只需在CDTO上更新构造函数,它也可以正常工作。在命名和内容方面可能会有些混乱。
这应该导致呼叫如下:
C = a.C.Select(cdto => new CDTO{cdto,cdto.ResumeInfo}).ToList();
,
如果您要查询“ A”作为顶级实体,那么我认为您只是缺少与其关联的“ B”的导航属性。 (因为它包含B_Id FK)
1-实体
public class A
{
public int id { get; set; }
public string Name { get; set; }
[ForeignKey("B")]
public int id_B { get; set; }
public virtual B B { get; set; }
public virtual ICollection<C> Cs { get; set;} = new List<C>();
}
然后,当您使用Select
将实体投影到DTO时:
var query = (await _context.A
.Where(a => a.Id == 1)
.Select(a => new ADto
{
Id = a.Id,B = new BDTO { Id = a.B.Id /* ... */ },Cs = a.Cs.Select(c => new CDTO{ Id = c.Id,Name = c.Name}).ToList(),}).Single();
请注意,在使用.Select
时,您无需使用.Include
来引用相关实体,这仅用于急于加载要返回实体图的相关实体。 (例如,从DTO读取实体以更新 值时)。另外,在使用ToList
之前请小心使用任何Select
操作,因为这会将实体加载到内存中应用过滤器之类的内容,并否定查询的优化以仅满足Select
的需求。
});