EF Core 2.0 รวมเอนทิตีที่ซ้อนกันพร้อมแบบสอบถามแบบไดนามิก

ฉันใช้ System.Linq.Dynamic.Core; และวิธีการขยายต่อไปนี้เพื่อเข้าถึง DbSet แบบไดนามิกตามชื่อและสร้างแบบสอบถามจากสตริง

นี่คือวิธีการขยาย:

namespace Microsoft.EntityFrameworkCore
{
    public static partial class CustomExtensions
    {
        public static IQueryable Query(this DbContext context, string entityName) =>
            context.Query(context.Model.FindEntityType(entityName).ClrType);

        public static IQueryable Query(this DbContext context, Type entityType) =>
            (IQueryable)((IDbSetCache)context).GetOrAddSet(context.GetDependencies().SetSource, entityType);
    }
}

นี่คือวิธีที่ฉันเข้าถึง DbSet:

IQueryable<T> dbSet = (IQueryable<T>)_db.Query(entityName);

วิธีนี้ใช้ได้ผลดี ฉันสามารถสร้างแบบสอบถามแล้วสร้างรายการได้ แต่ไม่มีเอนทิตีที่ซ้อนอยู่โหลดเลย ดูเหมือนว่า IQueryable ไม่มีคำจำกัดความสำหรับ Include() ฉันสามารถดูวิธีการรวมได้หากฉันเข้าถึงบริบท db โดยตรงในลักษณะปกติ แต่ไม่ได้ใช้วิธีการแบบไดนามิกนี้

ฉันจะรวมเอนทิตีที่ซ้อนกันโดยใช้วิธีไดนามิกได้อย่างไร


person Guerrilla    schedule 01.01.2018    source แหล่งที่มา


คำตอบ (2)


ก่อนอื่น คุณกำลังใช้ GetOrAddSet จาก IDbSetCache

public interface IDbSetCache

// // สรุป: // API นี้รองรับโครงสร้างพื้นฐาน Entity Framework Core และไม่ได้ตั้งใจ // เพื่อใช้โดยตรงจากโค้ดของคุณ API นี้อาจเปลี่ยนแปลงหรือถูกลบออกในอนาคต

Include เป็นวิธีการของ IQueryable<TEntity> ในคลาส EntityFrameworkQueryableExtensions ของ Microsoft.EntityFrameworkCore ไม่ใช่สำหรับ IQueryable ฟังก์ชันของคุณส่งคืน IQueryable

ฉันอยากจะแนะนำให้คุณสร้างวิธีการขยายดังนี้

        public static IQueryable<T> MyQuery<T>(this DbContext context)
            where T : class
        {
            return context.Set<T>().AsQueryable();
        }

และคุณสามารถบริโภคได้โดย

  var result = _dbContext.MyQuery<Employee>().Include("Department");

สำหรับไดนามิกรวมถึง

    /// <summary>
    /// Query with dynamic Include
    /// </summary>
    /// <typeparam name="T">Entity</typeparam>
    /// <param name="context">dbContext</param>
    /// <param name="includeProperties">includeProperties with ; delimiters</param>
    /// <returns>Constructed query with include properties</returns>
    public static IQueryable<T> MyQueryWithDynamicInclude<T>(this DbContext context, string includeProperties)
       where T : class
    {            
        string[] includes = includeProperties.Split(';');
        var query = context.Set<T>().AsQueryable();

        foreach (string include in includes)
            query = query.Include(include);

        return query;
    }
person programtreasures    schedule 01.01.2018
comment
สิ่งนี้มีประโยชน์จริงๆ ขอบคุณ! การเปลี่ยนแปลงที่เป็นไปได้ประการหนึ่ง แทนที่จะรวมชื่อคุณสมบัติหลายชื่อไว้ในสตริงเดียวกันและแยกออกภายในวิธีการ คุณสามารถใช้ params string[] includeProperties เป็นพารามิเตอร์สุดท้ายในวิธีการของคุณแทน - person Klicker; 21.04.2020
comment
จะเกิดอะไรขึ้นหากฉันต้องการรวมเอนทิตีย่อยด้วย พารามิเตอร์อินพุตคือ params string[] includeProperties ดังนั้นฉันจะผ่าน new[] { nameof(SomeClass.MyProperty), nameof(...) ... } แต่หาก MyProperty เป็น List และฉันต้องการรวมคุณสมบัติย่อย แสดงว่าเกิดปัญหา... - person kkamil4sz; 01.09.2020

ฉันมีรหัสชิ้นส่วนสำหรับปัญหานี้ ฉันใช้ต้นไม้นิพจน์

โมเดลเอนทิตีของฉันเหมือนด้านล่าง:

public class PortfolioTechnology
{
    public int PortfolioId { get; set; }
    public Portfolio Portfolio { get; set; }

    public int TechnologyId { get; set; }
    public Technology Technology { get; set; }
}

รหัสหลักของฉันดังนี้:

public SharpListResponse<PortfolioTechnology> GetAll(
    Expression<Func<PortfolioTechnology, bool>> predicate,
    params Expression<Func<PortfolioTechnology,object>>[] includes)
{
    var query = _dbContext.PortfolioTechnology.AsQueryable();

    foreach (var include in includes)
    {
        var memberExpression = include.Body as MemberExpression;

        if (memberExpression != null)
            query = query.Include(memberExpression.Member.Name);
    }

    var result = query.Where(predicate).ToList();

    return new SharpListResponse<PortfolioTechnology>(result);
}

และใช้วิธีการนี้ดังนี้:

var list = _unitOfWork.PortfolioTechnologyRepository.GetAll(x => x.PortfolioId == id, 
                                                            y => y.Technology);

หากคุณต้องการรวมเอนทิตีหลายรายการ เช่น รวมเอนทิตีพอร์ตโฟลิโอและเทคโนโลยี รหัสของคุณจะเป็นดังนี้:

 var list = _unitOfWork.PortfolioTechnologyRepository.GetAll(x => x.PortfolioId == id, 
                                                             y => y.Technology,
                                                             x => x.Portfolio);

หมายเหตุ: SharpListResponse เป็นคลาส wrapper โค้ดทำงานได้โดยไม่ต้องใช้มัน

รายละเอียดเพิ่มเติมสำหรับ SharpListResponse: https://www.nuget.org/packages/SharpRequestResponseWrapper/

person Ramil Aliyev    schedule 22.03.2020
comment
ทางออกที่ยอดเยี่ยม เรียบร้อยกว่าการใช้เชือกมาก - person D2TheC; 11.11.2020