Dynamic Include statements for eager loading in a query - EF 4.3.1

前端 未结 4 694
我在风中等你
我在风中等你 2020-12-09 11:01

I have this method:

public CampaignCreative GetCampaignCreativeById(int id)
        {
            using (var db = GetContext())
            {
                        


        
相关标签:
4条回答
  • 2020-12-09 11:28

    Make the query variable queryable:

    public CampaignCreative GetCampaignCreativeById(int id, string[] includes)
    {
        using (var db = GetContext())
        {
            var query = db.CampaignCreatives.AsQueryable();
            foreach (string include in includes)
            {
                query = query.Include(include);
            }
    
            return query
                .AsNoTracking()
                .Where(x => x.Id.Equals(id))
                .FirstOrDefault();                    
        }
    }
    
    0 讨论(0)
  • 2020-12-09 11:35

    Giving the compiler a hint by using IQueryable<CampaignCreative> instead of var will work too.

    IQueryable<CampaignCreative> query = db.CampaignCreatives;
    // or
    DbQuery<CampaignCreative> query = db.CampaignCreatives;
    

    When using var the compiler infers DbSet<T> for query which is more specific than the type returned by Include (which is DbQuery<T> (=base class of DbSet<T>) implementing IQueryable<T>), so you can't assign the result to the query variable anymore. Hence the compiler error on the query = query.Include(include) line.

    0 讨论(0)
  • 2020-12-09 11:51

    I wrote this method to retrieve any set of entity dynamically based on their types. I used the IDbEntity interface to provide a valid key to search the userId in all the classes. The Util.GetInverseProperties<T>() method is used to get the properties needed in the Include statement.

    public IEnumerable<T> GetItems<T>(string userId) where T : class, IDbEntity
    {
        var query = db.Set<T>().Where(l => l.UserId==userId);
    
        var props = Util.GetInverseProperties<T>();
        foreach (var include in props)
            query = query.Include(include.Name);
    
        return query
            .AsNoTracking()
            .ToList();
    }
    
    public interface IDbEntity
    {
        public string UserId { get; set; }
    }
    
    public static List<PropertyInfo> GetInverseProperties<T>()
    {
        return typeof(T)
            .GetProperties()
            .Where(p => Attribute.IsDefined(p, typeof(InversePropertyAttribute)))
            .ToList();
    }
    
    0 讨论(0)
  • 2020-12-09 11:53

    I am more fond of the non-string expressive way of defining includes. Mainly because it doesn't rely on magic strings.

    For the example code, it would look something like this:

    public CampaignCreative GetCampaignCreativeById(int id) {
        using (var db = GetContext()) {
            return db.CampaignCreatives
                .Include(cc => cc.Placement)
                .Include(cc => cc.CreativeType)                    
                .Include(cc => cc.Campaign.Select(c => 
                     c.Handshake.Select(h => h.Agency)))
                .Include(cc => cc.Campaign.Select(c => c.Product)
                .AsNoTracking()
                .Where(x => x.Id.Equals(id))
                .FirstOrDefault();
        }
    }
    

    And to make those dynamic, this is how you do that:

    public CampaignCreative GetCampaignCreativeById(
        int id, 
        params Expression<Func<T, object>>[] includes
    ) {
        using (var db = GetContext()) {
            var query = db.CampaignCreatives;
            return includes
                .Aggregate(
                    query.AsQueryable(), 
                    (current, include) => current.Include(include)
                )
                .FirstOrDefault(e => e.Id == id);
        }
    }
    

    Which is used like this:

    var c = dataService.GetCampaignCreativeById(
         1, 
         cc => cc.Placement, 
         cc => cc.CreativeType, 
         cc => cc.Campaign.Select(c => c.Handshake.Select(h => h.Agency)),
         cc => cc.Campaign.Select(c => c.Product
    );
    
    0 讨论(0)
提交回复
热议问题