1

I have two entities:

public class Asset
    {
        public int Id { get; set; }
        public string Name { get; set; }

        [ForeignKey("Type")]
        public short TypeId { get; set; }
        public AssetType Type { get; set; }
    }

public class AssetType
    {
        public short Id { get; set; }
        public string Name { get; set; }
        public ICollection<Asset> Assets { get; set; }
    }

And my DbContext:

public class ApplicationDbContext : DbContext
    {
        public DbSet<Asset> Assets { get; set; }
        public DbSet<AssetAccess> AssetAccesses { get; set; }

        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        { }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        { }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            builder.Entity<AssetType>().HasIndex(entity => entity.Name).IsUnique();
        }
    }

When I try to select Assets from database like this:

var assets = _dbContext.Assets
    .Include(asset => asset.Type)
    .ToList();

I receive the list of Asset with theirs Types but in Type object there are list of associated Asset objects so it repeats endlessly.

[
    {
        "id": 12,
        "name": "asset",
        "type": {
            "id": 1,
            "name": "type",
            "assets": [
                {
                    "id": 12,
                    "name": "asset",
                    "type": {
                        ... and so on ...
                    }
                },
                {
                    "id": 13,
                    "name": "asset",
                    "type": {
                        ... and so on ...
                    }
                }
            ]
        },
    },
    ...
]

I just wanna receive list of Asset with inner Type that's all. So how can I get rid of this cycling? In startup I define this:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
    .AddJsonOptions(option => option.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);

But it doesn't work.

Artyom
  • 654
  • 2
  • 7
  • 16
  • 1
    You should return view models instead of your entities. – CodeNotFound Jul 31 '19 at 08:33
  • @CodeNotFound , yeah, I do so. But I use AutoMapper that converts my domain models to view models. And when domain model has circular references AutoMapper return more objects then it has to and I don't want to return additional useless data – Artyom Jul 31 '19 at 10:08
  • @Artyom The whole idea of DTOs/View Models is that *they* should not have circular references - you create only the properties you need. Circular references in EF (storage) entity model are not problem - EF is handling them properly, and AM (especially with projection) does that as well. – Ivan Stoev Jul 31 '19 at 10:29
  • What is your current ViewModel? – Edward Aug 01 '19 at 01:59

2 Answers2

1

For returning ViewModel without additionl looping objects, try follow steps below:

  1. ViewModel

    public class AssetVM
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public AssetTypeVM Type { get; set; }
    }
    
    public class AssetTypeVM
    {
        public short Id { get; set; }
        public string Name { get; set; }
    }
    
  2. Profile

    public class ModelProfile: Profile
    {
        public ModelProfile()
        {
            CreateMap<AssetType, AssetTypeVM>();
            CreateMap<Asset, AssetVM>();
        }
    }
    
  3. Use

    var assets = _context.Assets
                .Include(asset => asset.Type)
                .ToList();
    var assetsVM = _mapper.Map<List<AssetVM>>(assets);
    
Edward
  • 28,296
  • 11
  • 76
  • 121
-1

Can you try to add virtual keyword to Type and Assets properties? This should enable them to be lazy loaded, so you should not get circular references?

You can read more about it here: navigation property should be virtual - not required in ef core

You can also try to add this setting:

services.AddMvc().AddJsonOptions(options => {
            options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        });
Nemanja Todorovic
  • 2,521
  • 2
  • 19
  • 30
  • If you have just a small sample code where this doesn't work, can you make it available so I can test it? – Nemanja Todorovic Aug 01 '19 at 08:44
  • sorry, but it's my work project and I can't share it. But I can provide more info about that. I use asp core 2.2, Mysql 8.0 database, EF Core with `Pomelo.EntityFrameworkCore.MySql` nuget package, `AutoMapper.Extensions.Microsoft.DependencyInjection`. By the way, I need either to get rid of circular references during select request to the database or during autoMapper models map – Artyom Aug 02 '19 at 08:38
  • Yeah, I already tried configure Json options, it prevents mapper from return exceptions but anyway it provides more inner objects than it must be – Artyom Aug 06 '19 at 14:45