Entity Framework Core v3: устранение повторяющихся данных - PullRequest
0 голосов
/ 09 января 2020

Я использую Entity Framework Core v3. В настоящее время я пытаюсь получить данные из таблиц, которые содержат отношение один ко многим.

Таблицы здесь PersonNote и PersonNoteAttachment.

Один PersonNote может иметь много PersonNoteAttachments. Данные в настоящее время повторяются. Так что, если вы видите раздел результатов, у него Имя появляется дважды. Это всего лишь пример. Я не уверен, что мне нужно изменить запрос или изменить структуру модели и т. Д. c. Может ли кто-нибудь помочь

PersonNote

Id   Name
-------------
113  TestNote

PersonNoteAttachment

Id  PersonNoteId   Note 
---------------------------------
101 113            Attachment1
102 113            Attachment2

Результат

TestNote Attachment1
TestNote Attachment2

Я смотрю на

TestNote Attachment1
          Attachment2

Запрос

public IQueryable<PersonNote> GetPersonNotes(int personId)
{
    var personNotes = _context.PersonNotes
             .Include(x => x.Person)
             .Include(x => x.Author)
             .Include(x => x.PersonNoteAttachment)
             .Where(p => p.PersonId == personId)
             .OrderByDescending(d => d.Created);

    return personNotes;
}

Модель

namespace Organisation.Models.DataModels
{
    [Table(nameof(PersonNote), Schema = "common")]
    public class PersonNote
    {
        public int Id { get; set; }
        public int PersonId { get; set; }
        [ForeignKey("PersonId")]
        public Person Person { get; set; }
        public string Note { get; set; }
        public int AuthorId { get; set; }
        public PersonNoteAttachment PersonNoteAttachment { get; set; }
        [ForeignKey("AuthorId")]
        public Person Author { 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; }
}

public class PersonNoteAttachment
{
        public int Id { get; set; }

        public int PersonNoteId { get; set; }

        [ForeignKey("PersonNoteId")]
        public PersonNote PersonNote { get; set; }

        public string Alias { get; set; }
        public string FileName { get; set; }
        public string MimeType { get; set; }
        public int Deleted { 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; }
}

Отображение

 CreateMap<Organisation.Models.DataModels.PersonNote, 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.AuthorName, opt => opt.MapFrom(s => s.Author.FirstName + " " + s.Author.LastName))
                  .ForMember(t => t.FileName, opt => opt.MapFrom(s => s.PersonNoteAttachment.FileName))
                  .ForMember(t => t.MimeType, opt => opt.MapFrom(s => s.PersonNoteAttachment.MimeType))
                  .ForMember(t => t.Alias, opt => opt.MapFrom(s => s.PersonNoteAttachment.Alias))
                  .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));

Если вы заметили, PersonNoteAttachment не является массивом. Если я сделаю его массивом, то потребуется внести следующие изменения:

 public PersonNoteAttachment[] PersonNoteAttachment { get; set; }

и в отображении, чтобы избежать ошибок компиляции

.ForMember(t => t.FileName, opt => opt.MapFrom(s => s.PersonNoteAttachment[0].FileName))

API

[FunctionName(nameof(GetPersonNote))]
[UsedImplicitly]
public Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "person-note/{id}")] HttpRequest req,
            int id) => _helper.HandleAsync(async () =>
{
    // await _helper.ValidateRequestAsync(req,  SecurityPolicies.ViewNotes);
    var personNotes = await _organisationRepository.GetPersonNotes(id).ProjectTo<PersonNote>(_mapper.ConfigurationProvider).ToListAsync();
    return new OkObjectResult(personNotes);
});

ViewModel

namespace Organisation.Models.User
{
    [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 Alias { get; set; }
        public string FileName { get; set; }
        public string MimeType { get; set; }
        public string AuthorName { get; set; }
        public string CreatedBy { get; set; }
        public DateTime Created { get; set; }
    }
}

Решение 1 - Но с внутренним исключением

Unable to cast object of type 'System.Boolean' to type 'System.Int32'.

Попробовал следующее, что дает желаемые результаты. Почтальон возвращает 200к. Хотя отладка кода выдает внутреннее исключение.

Добавлено

Модель данных

  namespace Organisation.Models.DataModels
    {
    public class PersonNote
        {
          public IEnumerable<PersonNoteAttachment> PersonNoteAttachment { get; set; }
        }
    }

Модель представления

namespace Organisation.Models.User
{
    [Table(nameof(PersonNote), Schema = "common")]
    public class PersonNote
    {

        public IEnumerable<string> Alias { get; set; }
        public IEnumerable<string> FileName { get; set; }
        public IEnumerable<string> MimeType { get; set; }

    }
}

Отображение

.ForMember(t => t.FileName, opt => opt.MapFrom(s => s.PersonNoteAttachment.Select(x=> x.FileName)))
                  .ForMember(t => t.MimeType, opt => opt.MapFrom(s => s.PersonNoteAttachment.Select(x => x.MimeType)))
                  .ForMember(t => t.Alias, opt => opt.MapFrom(s => s.PersonNoteAttachment.Select(x => x.Alias)))

Решение Абдулса

    API



  [FunctionName(nameof(GetPersonNote))]
        [UsedImplicitly]
        public Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "person-note/{id}")] HttpRequest req,
            int id) => _helper.HandleAsync(async () =>
        {
            await _helper.ValidateRequestAsync(req,  SecurityPolicies.ViewNotes);
            var personNotes =  _organisationRepository.GetPersonNotes(id);
            //IEnumerable<PersonNote> personNotes =  groupedNotes.Select(Profiles.GenistarUserProfile.MapGroupToPersonNote);

            return new OkObjectResult(personNotes.ToList());
        });

Хранилище

public IQueryable<Genistar.Organisation.Models.User.PersonNote> GetPersonNotes(int personId)
    {
        var personNotes = _context.PersonNotes
            .Include(x => x.Person)
            .Include(x => x.Author)
            .Where(p => p.PersonId == personId).Select(x => new Genistar.Organisation.Models.User.PersonNote
            {
                //assign all properties
                Attachments = _context.PersonNotesAttachments.Where(y => y.PersonNoteId == x.Id).Select(y => new Genistar.Organisation.Models.User.PersonNoteAttachment
                {
                    FileName = y.FileName,
                    Alias = y.Alias,
                    MimeType = y.MimeType

                }),
                PersonId = x.PersonId,
                AuthorName = x.Person.FirstName + " " + x.Person.LastName,
                Note = x.Note,
                Id = x.Id,
                Created = x.Created
            }).OrderByDescending(x=> x.Created).AsNoTracking();
        return personNotes; 
    }

1 Ответ

0 голосов
/ 10 января 2020

Следующий код позволит вам использовать трехуровневую архитектуру в вашем приложении и попытаться уменьшить связь между вашими слоями при сохранении существующей структуры.

Для начала измените запрос:

public IQueryable<DataModel.PersonNote> GetPersonNotes(int personId)
{
    var personNotes = _context.PersonNotes
         .Include(x => x.Person)
         .Include(x => x.Author)
         .Where(p => p.PersonId == personId);

    return personNotes;
}

И добавьте еще один запрос репо:

public IQueryable<DataModel.PersonNoteAttachment> GetAttachments(int personNoteId)
{
    var attachments = _context.PersonNotesAttachments.Where(x => x.Id == personNoteId);

    return attachments ;
}

Используйте следующие модели, PersonNote - ваша модель представления:

namespace Organisation.Models.User
{
    public class PersonNoteAttachment
    {
        public string Alias { get; set; }
        public string FileName { get; set; }
        public string MimeType { get; set; }
    }

    public class PersonNote
    {
        public int Id { get; set; }
        public int PersonId { get; set; }
        public string Note { get; set; }
        public int AuthorId { get; set; }
        public IEnumerable<PersonNoteAttachment> Attachments { get; set; }
        public string AuthorName { get; set; }
        public string CreatedBy { get; set; }
        public DateTime Created { get; set; }
    }
}

Теперь мы создадим новую функцию в BL слой, который будет возвращать ваши данные для ViewModel:

public IEnumerable<User.PersonNote> GetPersonNotesAndAttachments(int personID)
{
    var personNotes = _organisationRepository.GetPersonNotes(id).Select(x => 
        new User.PersonNote
        {
            //assign all properties
            Attachments = _organisationRepository.GetAttachments(x.PersonNoteID).Select(y => 
            new User.PersonNoteAttachment
            {
                FileName = y.FileName,
                Alias = y.Alias,
                MimeType = y.MimeType
            }).AsEnumerable(),
        PersonId = x.PersonId,
        AuthorName = x.Person.FirstName + " " + x.Person.LastName,
        Note = x.Note,
        Id = x.Id,
        Created = x.Created
        });

    return personNotes;
}

IEnumerable<PersonNote> «То, на что я смотрю», может быть доступно следующим образом:

IEnumerable<User.PersonNote> personNotes = new BlClass().GetPersonNotesAndAttachments(id);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...