Reputation: 782
I'm using entity framework in my application, and I have a one-to-many models like this:
public class Email
{
public string Id { get; set; }
public string To { get; set; }
public string From { get; set; }
public string CC { get; set; }
public string Bcc { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public ICollection<AnexoEmail> Anexos{get;set;}
}
public class AnexoEmail
{
[Key]
public string Id { get; set; }
/// <summary>
/// Full path do ficheiro
/// </summary>
public string Nome { get; set; }
public DateTime DataEnvio { get; set; }
public bool Enviado { get; set; }
public string EmailId { get; set; }
public Email Email { get; set; }
}
It represents like a Email-Attachment relation. The thing is that I have a UOW
and repository EmailRepository
and something that I can't understand happens:
On the repository:
public class EmailRepository : IEmailRepository
{
internal DbContext _context;
internal DbSet<Email> dbSet;
internal DbSet<AnexoEmail> dbSetAnexo;
public EmailRepository(DbContext context)
{
_context = context;
dbSet = context.Set<Email>();
dbSetAnexo = context.Set<AnexoEmail>();
}
(...)
public IEnumerable<Email> GetAll()
{
dbSetAnexo.ToList(); //<- I can´t understand this part
var emails = dbSet.ToList();
return email;
}
}
In this example I'm expecting emails.Anexos
to be null
, but for some reason, if I add that line the emails.Anexos
gets the correct attachments(anexos), and if I don't emails.Anexos
will be null as expected.
I don't have much experience in Ef core, if I'm missing some class or anything just tell me.
Thank you.
Upvotes: 2
Views: 1191
Reputation: 118977
This is all caused by entity tracking. The line dbSetAnexo.ToList();
causes Entity Framework to track the entire DbSet
, you can think of it as a form of caching if you like. Because EF has "cached" those AnexoEmail
objects, it will present them to you when you request the value of email.Anexos
.
You can prevent this from happening by using the AsNoTracking()
extension method, for example:
dbSetAnexo.AsNoTracking().ToList();
Now, what you should be doing instead is using the Include
function which will force EF to load up the specified related children. For example:
var emails = dbSet
.Include(e => e.Anexos)
.ToList();
Upvotes: 2
Reputation: 3326
This has to do with what .ToList()
actually does. It doesn't change the original value of the collection, it just creates a new List<>
and returns it. What you're currently doing is throwing the value out the window, and not doing anything with it. There are two ways to store it:
DbSet<AnexoEmail> dbSetAnexo; // Keep original DbSet<>
List<AnexoEmail> listAnexo; // Make new List<AnexoEmail>
listAnexo = dbSetAnexo.ToList();
Then, you would use listAnexo
instead of dbSetAnexo
. If you don't like that, and want to use only one variable, you can use the dynamic
type which is the only type that can change from one type to another during runtime.
dynamic anexoEmails = new DbSet<AnexoEmail>(); // anexoEmails is currently a dBSet<>
anexoEmails = anexoEmails.ToList(); // anexoEmails is now a List<>
The latter might behavior more like you expected it would. Just keep in mind, with dynamic
types, you're not gonna get as much compiler checking, and no IDE autocompletetion as all of that is check during runtime.
Upvotes: 0