簡體   English   中英

實體框架核心 .Include() 問題

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM