Entity Framework core .Include() issue

后端 未结 4 1074
长发绾君心
长发绾君心 2021-02-18 22:05

Been having a play about with ef core and been having an issue with the include statement. For this code I get 2 companies which is what i expected.



        
相关标签:
4条回答
  • 2021-02-18 22:43

    I'm not sure if you've seen the accepted answer to this question, but the problem is to do with how the JSON Serializer deals with circular references. Full details and links to more references can be found at the above link, and I'd suggest digging into those, but in short, adding the following to startup.cs will configure the serializer to ignore circular references:

    services.AddMvc()
        .AddJsonOptions(options => {
            options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        });
    
    0 讨论(0)
  • 2021-02-18 22:52

    Lazy loading is not yet possible with EF Core. Refer here.

    Alternatively you can use eager loading.

    Read this article

    Below is the extension method i have created to achieve the eager loading.

    Extension Method:

    public static IQueryable<TEntity> IncludeMultiple<TEntity, TProperty>(
        this IQueryable<TEntity> source,
        List<Expression<Func<TEntity, TProperty>>> navigationPropertyPath) where TEntity : class
    {
        foreach (var navExpression in navigationPropertyPath)
        {
            source= source.Include(navExpression);
        }
        return source.AsQueryable();
    }
    

    Repository Call:

    public async Task<TEntity> FindOne(ISpecification<TEntity> spec)
    {
        return await Task.Run(() => Context.Set<TEntity>().AsQueryable().IncludeMultiple(spec.IncludeExpression()).Where(spec.IsSatisfiedBy).FirstOrDefault());
    }
    

    Usage:

    List<object> nestedObjects = new List<object> {new Rules()};
    
    ISpecification<Blog> blogSpec = new BlogSpec(blogId, nestedObjects); 
    
    var challenge = await this._blogRepository.FindOne(blogSpec);
    

    Dependencies:

    public class BlogSpec : SpecificationBase<Blog>
    {
        readonly int _blogId;
        private readonly List<object> _nestedObjects;
    
        public ChallengeSpec(int blogid, List<object> nestedObjects)
        {
            this._blogId = blogid;
            _nestedObjects = nestedObjects;
        }
    
        public override Expression<Func<Challenge, bool>> SpecExpression
        {
            get { return blogSpec => blogSpec.Id == this._blogId; }
        }
    
        public override List<Expression<Func<Blog, object>>> IncludeExpression()
        {
            List<Expression<Func<Blog, object>>> tobeIncluded = new List<Expression<Func<Blog, object>>>();
            if (_nestedObjects != null)
                foreach (var nestedObject in _nestedObjects)
                {
                    if (nestedObject is Rules)
                    {
                        Expression<Func<Blog, object>> expr = blog => blog.Rules;
                        tobeIncluded.Add(expr);
                    }
                    
                }
    
            return tobeIncluded;
        }
    }
    

    Will be glad if it helps. Please note this is not a production ready code.

    0 讨论(0)
  • 2021-02-18 22:59

    I test your code, this problem exist in my test. in this post LINK Proposed that use data projection. for your problem Something like the following, is work.

    [HttpGet]
    public dynamic Get()
    {
        var dbContext = new ApplicationContext();
    
        var result = dbContext.Companies
            .Select(e => new { e.CompanyName, e.Id, e.Employees, e.Admins })
            .ToList();
    
        return result;
    }
    
    0 讨论(0)
  • 2021-02-18 23:02

    I know this is an old issue, but its the top result in google, so im putting my solution i I found here. For a Core 3.1 web project there is a quick fix. Add nuget package Microsoft.EntityFrameworkCore.Proxies. Then you simply just need to specify in your options builder when configuring your services. Docs: https://docs.microsoft.com/en-us/ef/core/querying/related-data

    public void ConfigureServices(IServiceCollection services) {    
        services.AddDbContextPool<YourDbContext>(options => {
            options.UseLazyLoadingProxies();
            options.UseSqlServer(this.Configuration.GetConnectionString("MyCon"));
        });
    }
    

    Now your lazy loading should work as it did in previous EF versions. If you not using it for a web project, you can do it right inside of the OnConfiguringMethod inside of your DbContext itself.

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
        optionsBuilder.UseLazyLoadingProxies();
    }
    

    My EF stuff is kept in a separate class library so i can re-use it through multiple company applications. So having the ability to not lazy load when not needed for a particular application is useful. So i prefer passing in the build options, for reuse-ability purposes. But both will work.

    0 讨论(0)
提交回复
热议问题