Entity framework 在紧急加载时,是否可以排除EF中的反向导航属性?
在EF6中使用.Include语法时,始终会加载反向导航属性。有没有办法把它关掉?下面是一个示例查询Entity framework 在紧急加载时,是否可以排除EF中的反向导航属性?,entity-framework,navigation-properties,Entity Framework,Navigation Properties,在EF6中使用.Include语法时,始终会加载反向导航属性。有没有办法把它关掉?下面是一个示例查询 private static IQueryable<Account> GetAccountsEager(this IRepository<Account> repository) { return repository .Queryable() .Include(e => e.AccountLocations
private static IQueryable<Account> GetAccountsEager(this IRepository<Account> repository)
{
return repository
.Queryable()
.Include(e => e.AccountLocations
.Select(l => l.Address.City.State.Country));
}
但是,如果我添加这样一个include:
return repository.Queryable()
.Include(e => e.BillToAddress.AddressType)
.Include(e => e.BillToAddress.City.State.Country);
.Include(e => e.AccountLocations.Select(a => a.Address.City.State.Country));
然后为e.BillToAddress.City和每个AccountLocation的Address.City加载反向导航地址。为什么在第三个包含中添加.Select会影响第二个包含
下面是SQL:
其他信息:
以下是DbContextConfiguration:
public DataContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
_instanceId = Guid.NewGuid();
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
}
以下是执行查询的方法(使用.FirstOrDefault()):
公共静态帐户(
这个IRepository存储库,
int id)
{
var query=repository.GetQueryableEager();
返回query.FirstOrDefault(e=>e.AccountId==id);
}
这是一座城市:
public partial class City: Entity, IDatabaseMetaData
{
public int CityId { get; set; } // CityId (Primary key)
public string CityName { get; set; } // CityName
public int StateId { get; set; } // StateId
public DateTime InsertDatetime { get; set; } // InsertDatetime
public int InsertSystemUserId { get; set; } // InsertSystemUserId
public DateTime? UpdateDatetime { get; set; } // UpdateDatetime
public int? UpdateSystemUserId { get; set; } // UpdateSystemUserId
public int? CountyId { get; set; } // CountyId
// Reverse navigation
public virtual ICollection<Address> Addresses { get; set; } // Address.FK_Address_CityId
// Foreign keys
public virtual County County { get; set; } // FK_City_CountyId
public virtual State State { get; set; } // FK_City_StateId
public City()
{
InsertDatetime = System.DateTime.Now;
Addresses = new List<Address>();
InitializePartial();
}
partial void InitializePartial();
}
公共部分类城市:实体,IDatabaseMetaData
{
public int CityId{get;set;}//CityId(主键)
公共字符串CityName{get;set;}//CityName
public int StateId{get;set;}//StateId
公共日期时间InsertDatetime{get;set;}//InsertDatetime
public int InsertSystemUserId{get;set;}//InsertSystemUserId
公共日期时间?UpdateDatetime{get;set;}//UpdateDatetime
public int?UpdateSystemUserId{get;set;}//UpdateSystemUserId
公共int?CountyId{get;set;}//CountyId
//反向导航
公共虚拟ICollection地址{get;set;}//Address.FK_Address_CityId
//外键
公共虚拟县{get;set;}//FK_City_CountyId
公共虚拟状态状态{get;set;}//FK_City_StateId
公共城市()
{
InsertDatetime=System.DateTime.Now;
地址=新列表();
初始化部分();
}
部分无效初始化部分();
}
我认为你看到的是“关系修复”的结果:
关系修复可确保在第二个实体进入ObjectContext时自动链接相关对象
在您的情况下,由于您包括
AccountLocation.Address.City
,EF正在加载您请求的相关Address
实体和相关City
实体,并作为“修复”的一部分它将加载的地址
实体添加到城市导航集合中,这些实体将是城市
->地址
一对多关系的一部分
你可以在上找到另一个例子。与您的情况一样,延迟加载和代理创建也被禁用——但是,该链接不包括禁用此行为的方法
在紧急加载时,是否可以排除EF中的反向导航属性
没有
正如在另一个答案中所解释的,EF有一个关系修复过程,将它加载到上下文中的所有实体编织在一起。你不能以任何方式停止这个过程。因此,如果您不亲自处理事情,您将永远拥有这个臃肿的Json字符串。(我无法解释或再现您似乎发现的负载差异,但这应该是一个新问题的主题。我不会指望它们总是发生,希望它们能解决您当前的问题)
这就是关键所在:控制局面。这取决于你的情况,什么是最好的策略,但有几个选择
将查询投影到匿名类型并将其序列化为JSON。这只是一个简单的例子:
repository.Queryable()
.Select(e => new
{
Account = e.Name,
AccountLocations =
e.AccountLocations
.Select(l => new
{
Address = new { l.Address.Street, l.Address.Number },
City = l.Address.City.Name,
Country = l.Address.City.Country.Name,
})
});
有些人会反对从方法返回匿名类型,即使它是JSON格式的,但对我来说,它只是一个以某种所需格式返回JSON的方法。它只会让非类型化JavaScript世界更近一步
对命名类型(DTO,或视图模型,类型)的结构执行相同的操作
创建一个没有双向关联的专用上下文。这是一个经常被遗忘的选项,但为什么总是要有一个上下文来访问数据?只需确保上下文使用(或生成)的类与属于主上下文的类具有不同的名称
顺便说一句,通过这样做,您还可以根据需要对从数据库中获取的数据量进行定制。您说:因此,它会重新加载所有反向导航地址,以提供比查询中所需数据多得多的数据。我是否可以以某种方式关闭反向导航?您确定生成的SQL正在返回更多数据吗可能SQL查询很好,EF只填充反向导航属性,这应该不会有问题。是的,查询提取的数据比我想要的要多。如果我得到一个城市为达拉斯的帐户,它会返回城市的反向导航属性(地址),因此包含达拉斯的每个地址都会返回“后加载”。您可以发布由第二条语句生成的sql查询。如果有剩余的连接来获取地址,或者只有内部连接。我按照建议编辑了帖子,以包含EF为第二条查询生成的sql。为什么您需要这些导航属性来保持不被填充?
public DataContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
_instanceId = Guid.NewGuid();
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
}
public static Account GetEager(
this IRepository<Account> repository,
int id)
{
var query = repository.GetQueryableEager();
return query.FirstOrDefault(e => e.AccountId == id);
}
public partial class City: Entity, IDatabaseMetaData
{
public int CityId { get; set; } // CityId (Primary key)
public string CityName { get; set; } // CityName
public int StateId { get; set; } // StateId
public DateTime InsertDatetime { get; set; } // InsertDatetime
public int InsertSystemUserId { get; set; } // InsertSystemUserId
public DateTime? UpdateDatetime { get; set; } // UpdateDatetime
public int? UpdateSystemUserId { get; set; } // UpdateSystemUserId
public int? CountyId { get; set; } // CountyId
// Reverse navigation
public virtual ICollection<Address> Addresses { get; set; } // Address.FK_Address_CityId
// Foreign keys
public virtual County County { get; set; } // FK_City_CountyId
public virtual State State { get; set; } // FK_City_StateId
public City()
{
InsertDatetime = System.DateTime.Now;
Addresses = new List<Address>();
InitializePartial();
}
partial void InitializePartial();
}
repository.Queryable()
.Select(e => new
{
Account = e.Name,
AccountLocations =
e.AccountLocations
.Select(l => new
{
Address = new { l.Address.Street, l.Address.Number },
City = l.Address.City.Name,
Country = l.Address.City.Country.Name,
})
});