我正在尝试在Entity Framework Core中映射实体,并遇到以下错误。我有两个主要实体Person
和PersonNote
,它们之间具有一对多的关系。
一个人可以有很多人的笔记。我尝试检索伪造品的方法不会返回结果,但是在尝试映射时失败。正如您在我的帖子中看到的那样,我定义了两个映射。一种是将PersonNote与Person映射,以便可以评估AuthorName。中的AuthorId 与个人ID相关的PersonNote。
我的PersonNote模型包含AuthorName,但DataModel不包含。我正在尝试在createmap函数中映射该值。我错过了什么吗?
缺少类型映射配置或不支持的映射。\ r \ n \ r \ n映射类型:\ r \ nEntityQueryable`1->
我定义了以下模型
namespace Genistar.Organisation.Models.User
{
public class PersonNote
{
public PersonNote()
{
Person = new HashSet<Person>();
}
public int Id { get; set; }
public int PersonId { get; set; }
public string Note { get; set; }
public int AuthorId { get; set; }
public string AuthorName { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
public ICollection<Person> Person { get; set; }
}
}
namespace Genistar.Organisation.Models.DataModels
{
[Table(nameof(PersonNote), Schema = "common")]
public class PersonNote
{
public int Id { get; set; }
public int PersonId { get; set; }
public string Note { get; set; }
public int AuthorId { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordStartDateTime { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordEndDateTime { get; set; }
}
}
namespace Genistar.Organisation.Models.DataModels
{
public class Person
{
public int Id { get; set; }
public int? TitleId { get; set; }
public string FirstName { get; set; }
public string FirstNamePref { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public DateTime? DateOfBirth { get; set; }
public string Gender { get; set; }
public int AddressId { get; set; }
public string TelephoneNumber { get; set; }
public string MobileNumber { get; set; }
public string Email { get; set; }
public int? PartnerId { get; set; }
public bool Enabled { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
public string ModifiedBy { get; set; }
public DateTime Modified { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordStartDateTime { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordEndDateTime { get; set; }
public Address Address { get; set; }
public Title Title { get; set; }
public Client Client { get; set; }
public List<PersonNote> PersonNotes { get; set; }
}
}
CreateMap函数
CreateMap<Genistar.Organisation.Models.DataModels.Person, Genistar.Organisation.Models.User.PersonNote>()
.ForMember(t => t.AuthorId, opt => opt.MapFrom(s => s.Id))
.ForMember(t => t.AuthorName, opt => opt.MapFrom(s => s.FirstName + " " + s.LastName));
CreateMap<Genistar.Organisation.Models.DataModels.PersonNote, Genistar.Organisation.Models.User.PersonNote>()
//.ForMember(t => t.Id, opt => opt.MapFrom(s => s.Id))
//.ForMember(t => t.PersonId, opt => opt.MapFrom(s => s.PersonId))
//.ForMember(t => t.Note, opt => opt.MapFrom(s => s.Note))
//.ForMember(t => t.AuthorId, opt => opt.MapFrom(s => s.AuthorId))
//.ForMember(t => t.CreatedBy, opt => opt.MapFrom(s => s.CreatedBy))
//.ForMember(t => t.Created, opt => opt.MapFrom(s => s.Created));
.ForMember(t => t.Id, opt => opt.Ignore())
.ForMember(t => t.PersonId, opt => opt.Ignore())
.ForMember(t => t.Note, opt => opt.Ignore())
.ForMember(t => t.AuthorId, opt => opt.Ignore())
.ForMember(t => t.CreatedBy, opt => opt.Ignore())
.ForMember(t => t.Created, opt => opt.Ignore());
查询-请注意,此处返回的PersonNote类型为Genistar.Organisation.Models.User.PersonNote
[FunctionName(nameof(GetPersonNote))]
[UsedImplicitly]
public Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "person-note/{id}")] HttpRequest req,
int id) => _helper.HandleAsync(async () =>
{
var personNotes = _organisationRepository.GetPersonNotes(id);
return new OkObjectResult(_mapper.Map<PersonNote>(personNotes));
});
public IEnumerable<PersonNote> GetPersonNotes(int personId)
{
var PersonNotes1 = _context.PersonNotes.Where(p => p.PersonId == personId);
return PersonNotes1;
}
答案 0 :(得分:1)
这里的示例没有意义,在同一名称空间中不能有2个“ PersonNote”类。看起来您拥有Entities,然后分离了ViewModels / DTO,尽管这样会使相同的命名混淆。如果需要或要求,那么我建议为命名空间起别名。即:
using Models = Genistar.Organisation.Models;
using DTOs = Genistar.Organisation.Models.DataModels;
以便使代码清楚地知道哪个是什么。
例如,此代码没有多大意义:
public Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "person-note/{id}")] HttpRequest req,
int id) => _helper.HandleAsync(async () =>
{
var personNotes = _organisationRepository.GetPersonNotes(id);
return new OkObjectResult(_mapper.Map<PersonNote>(personNotes));
});
public IEnumerable<PersonNote> GetPersonNotes(int personId)
{
var PersonNotes1 = _context.PersonNotes.Where(p => p.PersonId == personId);
return PersonNotes1;
}
我假设它们是从2个不同的类中提取的,因为第一种方法看起来应该处理DTO,而第二种方法应该是从存储库处理实体?
有些事情确实很突出。首先,存储库方法应返回IQueryable<T>
而不是IEnumerable<T>
。这样做的好处是,它将允许您进一步链接Linq表达式,包括允许Automapper将设置减少到DTO,并将该优化传递到组合的SQL。
第二件事是利用Automapper的ProjectTo
方法而不是Map
。与IQueryable
结合使用,可以在SQL级别完成映射:
因此存储库方法更改为:
public IQueryable<PersonNote> GetPersonNotes(int personId)
{
var PersonNotes1 = _context.PersonNotes.Where(p => p.PersonId == personId);
return PersonNotes1;
}
然后输入您的控制器代码:
public Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "person-note/{id}")] HttpRequest req,
int id) => _helper.HandleAsync(async () =>
{
var personNotes = _organisationRepository.GetPersonNotes(id).ProjectTo<DTO.PersonNote>(_mapper.ConfigurationProvider);
return new OkObjectResult(personNotes);
});
当您的存储库返回IEnumerable
时,映射器调用将根据急切加载的内容尝试浏览面值的属性,并处理EF插入的任何代理类型。对于不同的EF Core版本与EF6之间的区别,我不是100%的,但是您现有的代码似乎会因代理类型而被绊倒。即便如此,否则,Automapper的Map
调用会在遍历属性时延迟加载任何相关实体,从而会给数据库带来额外的打击。