以一对多关系获得价值(EF核心)

时间:2018-12-14 14:00:38

标签: asp.net-core entity-framework-core

我在EF Core中寻求与此SQL查询等效的内容:

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'”。 / p>

事件模型:

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 :(得分:1)

原因

发生此错误是因为您试图让EF Core不跟踪GUID的列表。但是,Guid列表是值类型的列表。

您知道,EF Core只能跟踪一系列引用类型,因此method signature of 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; }

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

    }

因为Event是主体实体,EventAdmin是从属实体。仅EventAdmin具有引用Event的外键。

答案 1 :(得分:0)

您的LINQ查询似乎未包含adminId,因此我看不到它如何工作。尝试这样的事情:

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

var events = eventAdmin.Events;

尝试使用类似Linqpad的工具一次将查询分解。