[英]Entity Framework core .Include() issue
一直在玩 ef core 並且對 include 語句有問題。 對於此代碼,我得到了 2 家公司,這正是我所期望的。
public IEnumerable<Company> GetAllCompanies(HsDbContext db)
{
var c = db.Company;
return c;
}
這返回
[
{
"id":1,
"companyName":"new",
"admins":null,
"employees":null,
"courses":null
},
{
"id":2,
"companyName":"Test Company",
"admins":null,
"employees":null,
"courses":null
}
]
正如您所看到的,有 2 家公司,所有相關屬性都為空,因為我沒有使用任何包含,這正是我所期望的。 現在,當我將方法更新為:
public IEnumerable<Company> GetAllCompanies(HsDbContext db)
{
var c = db.Company
.Include(t => t.Employees)
.Include(t => t.Admins)
.ToList();
return c;
}
這是它返回的內容:
[
{
"id":1,
"companyName":"new",
"admins":[
{
"id":2,
"forename":"User",
"surname":"1",
"companyId":1
}
]
}
]
它只返回一家公司並且只包括管理員。 為什么不包括這兩家公司及其員工?
public class Company
{
public int Id { get; set; }
public string CompanyName { get; set; }
public List<Admin> Admins { get; set; }
public List<Employee> Employees { get; set; }
public List<Course> Courses { get; set; }
public string GetFullName()
{
return CompanyName;
}
}
public class Employee
{
public int Id { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public int CompanyId { get; set; }
[ForeignKey("CompanyId")]
public Company company { get; set; }
public ICollection<EmployeeCourse> Employeecourses { get; set; }
}
public class Admin
{
public int Id { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public int CompanyId { get; set; }
[ForeignKey("CompanyId")]
public Company Company { get; set; }
}
我不確定您是否已經看到了這個問題的公認答案,但問題在於 JSON Serializer 如何處理循環引用。 可以在上面的鏈接中找到更多參考的完整詳細信息和鏈接,我建議深入研究這些,但簡而言之,將以下內容添加到startup.cs
將配置序列化程序以忽略循環引用:
services.AddMvc()
.AddJsonOptions(options => {
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
EF Core 尚無法進行延遲加載。 請參閱此處。
或者,您可以使用預先加載。
閱讀這篇文章
下面是我為實現急切加載而創建的擴展方法。
擴展方法:
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();
}
存儲庫調用:
public async Task<TEntity> FindOne(ISpecification<TEntity> spec)
{
return await Task.Run(() => Context.Set<TEntity>().AsQueryable().IncludeMultiple(spec.IncludeExpression()).Where(spec.IsSatisfiedBy).FirstOrDefault());
}
用法:
List<object> nestedObjects = new List<object> {new Rules()};
ISpecification<Blog> blogSpec = new BlogSpec(blogId, nestedObjects);
var challenge = await this._blogRepository.FindOne(blogSpec);
依賴項:
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;
}
}
如果有幫助會很高興。 請注意,這不是生產就緒代碼。
我測試你的代碼,這個問題存在於我的測試中。 在這篇文章中LINK建議使用數據投影。 對於您的問題 類似以下的內容是有效的。
[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;
}
我知道這是一個老問題,但它是谷歌的最高結果,所以我把我的解決方案放在了這里。 對於 Core 3.1 web 項目,有一個快速修復。 添加 nuget 包Microsoft.EntityFrameworkCore.Proxies 。 然后,您只需要在配置服務時在選項構建器中指定即可。 文檔: 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"));
});
}
現在您的延遲加載應該像在以前的 EF 版本中一樣工作。 如果您不將它用於 Web 項目,則可以在 DbContext 本身的 OnConfiguringMethod 內部進行。
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
optionsBuilder.UseLazyLoadingProxies();
}
我的 EF 內容保存在一個單獨的類庫中,因此我可以通過多個公司應用程序重新使用它。 因此,能夠在特定應用程序不需要時不延遲加載是很有用的。 所以我更喜歡傳遞構建選項,用於重用能力的目的。 但兩者都會起作用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.