Search code examples
c#.netentity-framework.net-coreentity-framework-6

EntityFramework Include method is not working


Spent huge of time but do not understand why .Include(t => t.Nodes) does not return any Node entities:

public class TreeRepository : ITreeRepository
{
    private DataBaseContext dataBaseContext;

    public TreeRepository(DataBaseContext dataBaseContext)
    {
        this.dataBaseContext = dataBaseContext;
    }

    public async Task<ITree> GetTreeAsync(string name)
    {
        var tree = dataBaseContext.Tree.Include(t => t.Nodes).SingleOrDefault(t => t.Name == name);

        if (tree == null)
        {
            var t = await dataBaseContext.Tree.AddAsync(new TreeTable { Name = name });
            await dataBaseContext.SaveChangesAsync();

            tree = t.Entity;
        }

        return tree;
    }
}

The row below

var tree = dataBaseContext.Tree.Include(t => t.Nodes).SingleOrDefault(t => t.Name == name)

initialize .Include(t => t.Nodes)

Nodes are empty

Nodes filled

.Include(t => t.Nodes) should return nodes entities if they exist

Attach addititonal code

DataBaseContext.cs

using Microsoft.EntityFrameworkCore;
using FxNet.Web.Def.Api.Diagnostic.DAL.Db.Tables;

namespace FxNet.Web.Def.Api.Diagnostic.DAL.Db
{
    public class DataBaseContext : DbContext
    {
        public DataBaseContext(DbContextOptions<DataBaseContext> options) : base(options) {}

        public DbSet<JournalTable> Journal { get; set; }
        public DbSet<NodeTable> Node { get; set; }
        public DbSet<TreeTable> Tree { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<TreeTable>().ToTable("Tree"); //.Navigation(e => e.Nodes).AutoInclude();
            modelBuilder.Entity<NodeTable>().ToTable("Node");
            modelBuilder.Entity<JournalTable>().ToTable("Journal");
        }
    }
}

NodeTable.cs

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using FxNet.Web.Def.Api.Diagnostic.DAL.Infrastructure.Entity;

namespace FxNet.Web.Def.Api.Diagnostic.DAL.Db.Tables
{
    [Table("Node")]
    public class NodeTable : INode
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long Id { get; set; }

        public long TreeId { get; set; }

        [ForeignKey("TreeId")]
        public virtual TreeTable Tree { get; set; }

        public long ParentNodeId { get; set; }

        public string Name { get; set; }
    }
}

TreeTable.cs

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using FxNet.Web.Def.Api.Diagnostic.DAL.Infrastructure.Entity;

namespace FxNet.Web.Def.Api.Diagnostic.DAL.Db.Tables
{
    [Table("Tree")]
    public class TreeTable : ITree
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long Id { get; set; }

        public string Name { get; set; }

        IEnumerable<INode> ITree.Nodes => Nodes;

        public virtual List<NodeTable> Nodes { get; set; }
    }
}

INode.cs

namespace FxNet.Web.Def.Api.Diagnostic.DAL.Infrastructure.Entity
{
    public interface INode
    {
        long Id { get; set; }

        long TreeId { get; set; }

        long ParentNodeId { get; set; }

        string Name { get; set; }
    }
}

ITree.cs

namespace FxNet.Web.Def.Api.Diagnostic.DAL.Infrastructure.Entity
{
    public interface ITree
    {
        long Id { get; set; }

        string Name { get; set; }

        IEnumerable<INode> Nodes { get; }
    }
}

Startup.cs

using System.Linq;
using System.Reflection;
using System.ComponentModel;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using FxNet.Web.Def.Api.Diagnostic.DAL.Db;
using FxNet.Web.Def.Api.Diagnostic.Middleware;
using Microsoft.Extensions.DependencyInjection;
using FxNet.Web.Def.Api.Diagnostic.DAL.Repository;
using FxNet.Web.Def.Api.Diagnostic.DAL.Infrastructure.Repository;

namespace FxNet.Web.Def.Api.Diagnostic
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddTransient<GlobalExceptionHandlerMiddleware>();
            services.AddSwaggerGen(c =>
            {
                c.CustomSchemaIds(x => x.GetCustomAttributes<DisplayNameAttribute>().SingleOrDefault()?.DisplayName ?? x.FullName);
            });

            services.AddTransient<IJournalRepository, JournalRepository>();
            services.AddTransient<INodeRepository, NodeRepository>();
            services.AddTransient<ITreeRepository, TreeRepository>();

            services.AddDbContext<DataBaseContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DataBaseConnectionString")));

            //services.AddDbContext<DataBaseContext>(options => options.UseNpgsql(Configuration.GetConnectionString("PostgreSQLConnectionString")));
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "FxNet.Web.Def.Api.Diagnostic v1"));
            }

            using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
            {
                var context = serviceScope.ServiceProvider.GetRequiredService<DataBaseContext>();
                context.Database.EnsureCreated();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

Solution

  • Resolved! I used the old library System.Data.Entity. Replaced it with Microsoft.EntityFrameworkCore and Include method started working correctly.