Ядро базы данных Entity Framework.Include()
У вас была игра с 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 компании, и все связанные с ними свойства являются нулевыми, поскольку я havnt использовал какие-либо включения, что я и ожидал. Теперь, когда я обновляю метод до этого:
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}]
}]
Он возвращает только одну компанию и включает только администраторов. Почему в него не вошли 2 компании и их сотрудники?
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; }
}
Ответы
Ответ 1
Я не уверен, что вы видели принятый ответ на этот question, но проблема связана с тем, как JSON Serializer имеет дело с круговыми Рекомендации. Полную информацию и ссылки на дополнительные ссылки можно найти по приведенной выше ссылке, и я бы предложил ее копать, но, короче говоря, добавление следующего в startup.cs
будет настраивать сериализатор для игнорирования циклических ссылок:
services.AddMvc()
.AddJsonOptions(options => {
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
Ответ 2
Я тестирую ваш код, эта проблема существует в моем тесте. в этом сообщении 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;
}
Ответ 3
В 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;
}
Будет рад, если это поможет. Обратите внимание, что это не готовый код производства.