我在 Entity Framework 方面遇到问题,包括所有冗余的嵌套实体和那些实体,包括已经加载的实体,然后这些实体加载相同的嵌套实体等。
情况:我有一个客户列表,其中有很多包含也有客户列表。
问题:如何防止客户属性提取他们的客户列表?目前我已使用 Virtual 关键字设置了所有实体,但它们仍被包括在内。
public IEnumerable<Property> GetProperties()
{
return _context.Property.AsQueryable()
.Include(x => x.PropertyType).AsNoTracking()
.Include(x => x.PropertyStatus).AsNoTracking()
.Include(x => x.EngagementType).AsNoTracking()
.Include(x => x.IntInvestorClient).AsNoTracking()
.Include(x => x.PropertySizeType).AsNoTracking()
.Include(x => x.Division).AsNoTracking()
.Include(x => x.LocalMarketArea).AsNoTracking()
.Include(x => x.Country).AsNoTracking();
}
var all = _repo.GetProperties();
var result = returnAll ? all.ToList() : all.Skip(offset).Take(limit).ToList();
关闭更改跟踪。
见
Tracking behavior controls whether or not Entity Framework Core will keep information about an entity instance in its change tracker. If an entity is tracked, any changes detected in the entity will be persisted to the database during SaveChanges(). Entity Framework Core will also fix-up navigation properties between entities that are obtained from a tracking query and entities that were previously loaded into the DbContext instance.
https://learn.microsoft.com/en-us/ef/core/querying/tracking
如
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
namespace EFCore2Test
{
public class Note
{
public int Id { get; set; }
public string Value { get; set; }
}
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Part
{
public int Id { get; set; }
public ICollection<Part> ChildParts { get; } = new HashSet<Part>();
public ICollection<Note> Notes { get; } = new HashSet<Note>();
public int? ItemId { get; set; }
public Item Item { get; set; }
}
public class Db : DbContext
{
public DbSet<Part> Parts { get; set; }
public DbSet<Item> Items { get; set; }
public DbSet<Note> Notes { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=(local);Database=EfCoreTest;Trusted_Connection=True;MultipleActiveResultSets=true");
base.OnConfiguring(optionsBuilder);
}
}
class Program
{
static void Main(string[] args)
{
int partid;
using (var db = new Db())
{
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
var item = new Item();
db.Items.Add(item);
var p = new Part();
p.Item = item;
for (int i = 0; i < 10; i++)
{
var cp = new Part();
p.ChildParts.Add(cp);
db.Parts.Add(cp);
}
for (int i = 0; i < 4; i++)
{
p.Notes.Add(new Note() { Value = "Note" });
}
db.Parts.Add(p);
db.SaveChanges();
partid = p.Id;
}
using (var db = new Db())
{
Console.WriteLine("With Change Tracking");
var q = from p in db.Parts
.Include(p => p.Notes)
.Include(p => p.Item)
orderby p.Id == partid?0:1, p.Id
select p;
var parts = q.Take(5).ToList();
foreach (var p in parts)
{
Console.WriteLine($"Part {p.Id}, Child Parts {p.ChildParts.Count}");
}
Console.WriteLine();
}
using (var db = new Db())
{
Console.WriteLine("Without Change Tracking");
var q = from p in db.Parts.AsNoTracking()
.Include(p => p.Notes)
.Include(p => p.Item)
orderby p.Id == partid ? 0 : 1, p.Id
select p;
var parts = q.Take(5).ToList();
foreach (var p in parts)
{
Console.WriteLine($"Part {p.Id}, Child Parts {p.ChildParts.Count}");
}
}
Console.WriteLine("Hit any key to exit");
Console.ReadKey();
}
}
}
输出
With Change Tracking
Part 1, Child Parts 4
Part 2, Child Parts 0
Part 3, Child Parts 0
Part 4, Child Parts 0
Part 5, Child Parts 0
Without Change Tracking
Part 1, Child Parts 0
Part 2, Child Parts 0
Part 3, Child Parts 0
Part 4, Child Parts 0
Part 5, Child Parts 0
Hit any key to exit