Получить значение в отношениях 1-ко-многим (EF Core) - PullRequest
0 голосов
/ 14 декабря 2018

Я ищу эквивалент этого SQL-запроса в EF Core:

SELECT Id, Name, (Select AdminRoleId From EventAdmins Where EventId = Events.Id And AdminId = [value from cookie]) As EventRoleId From Events

Это то, что у меня есть:

public IList<Event> Events { get; set; }
public IList<EventAdmin> EventAdmins { get; set; }

public async Task<IActionResult> OnGetAsync() {

    var adminId = Guid.Parse(Request.Cookies["Adm_AdminId"]);

    Events = await _context.Events.SelectMany(e => e.EventAdmins.Where(x => x.EventId == e.Id && x.AdminId == adminId).Select(x => x.AdminRoleId)).AsNoTracking().ToListAsync();

    return Page();
}

Я не уверен, что не так, но я получаю сообщение об ошибке «Ошибка CS0452: тип« Guid »должен быть ссылочным типом, чтобы использовать его в качестве параметра« TEntity »в универсальном типе или методе».

Модель события:

public class Event {

    public Guid Id { get; set; }
    public string Name { get; set; }

    [ForeignKey("Id")]
    public IList<EventAdmin> EventAdmins { get; set; }

}

Модель EventAdmin:

public class EventAdmin {

    public Guid Id { get; set; }
    public Guid EventId { get; set; }
    public Guid AdminId { get; set; }
    public Guid AdminRoleId { get; set; }

    [ForeignKey("EventId")]
    public Event Events { get; set; }

}

Ответы [ 2 ]

0 голосов
/ 17 декабря 2018

Причина

Эта ошибка возникает из-за того, что вы пытаетесь попросить EF Core не отслеживать список GUID.Однако список Guid - это список типов значений.

Как вы знаете, EF Core может отслеживать только серию ссылочного типа, поэтому сигнатура метода для AsNoTracking<TEntity>() равна:

public static IQueryable<TEntity> AsNoTracking<TEntity> (this IQueryable<TEntity> source) 
    where TEntity : class;

Обратите внимание на ограниченияwhere TEntity : class.

Другими словами, вы никогда не сможете вызвать AsNoTracking<Guid>():

Events = await _context.Events
    .SelectMany(e => e.EventAdmins.Where(x => x.EventId == e.Id).Select(x => x.AdminRoleId))
    .AsNoTracking()    // Actually, it will invoke `AsNoTracking<Guid>()`
    .ToListAsync();

Как исправить

Ваш SQL не выглядит корректным.Я думаю, вы хотите вернуть {Id, Name, EventRoleId}.

Если вы хотите сделать это с SelectMany, вы можете просто сделать запрос, как показано ниже:

var Events = await this._context.Events
    .SelectMany( 
        e => e.EventAdmins.Where(x => x.EventId == e.Id).Select(x => x.AdminRoleId),
        (p,g) => new {
            Id = p.Id,
            Name = p.Name,
            EventRoleId = g
        }
    )
    // .AsNoTracking()   
    .ToListAsync();

Там нетнужно звонить .AsNoTracking() на все .Поскольку отслеживание не выполняется, если результирующий набор не содержит никаких типов сущностей .


В качестве примечания не следует украшать Event.EventAdmins атрибутом [ForeignKey("Id")]:

    public class Event {

        public Guid Id { get; set; }
        public string Name { get; set; }

        <strike>[ForeignKey("Id")]</strike>
        public IList EventAdmins { get; set; }

    }

Поскольку Event является главной сущностью, аEventAdmin является зависимым объектом.Только EventAdmin имеет внешний ключ, который ссылается на Event.

0 голосов
/ 14 декабря 2018

Ваш запрос LINQ, похоже, не включает adminId, поэтому я не вижу, как он может работать.Попробуйте что-то вроде этого:

var eventAdmin = _context.EventAdmin.SingleOrDefault( e => e.Id == adminId);

var events = eventAdmin.Events;

Попробуйте использовать такой инструмент, как Linqpad, для разбора ваших запросов по одному шагу за раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...