Why can't I do ToList()? - entity-framework

I build a model as below. The relationship between Recycler and Account is 1:1.
public class MyContext : DbContext
{
public DbSet<Quoter> Quoters { get; set; }
public DbSet<Account> Accounts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Account>()
.HasRequired(a => a.RecyclerRef)
.WithRequiredDependent(r => r.AccountRef);
}
}
public class Quoter
{
public int QuoterId { get; set; }
public string Text { get; set; }
}
public class Recycler : Quoter
{
public string Description { get; set; }
public virtual Account AccountRef { get; set; }
}
public class Account
{
public int AccountId { get; set; }
public Recycler RecyclerRef { get; set; }
}
But, I get exceptions when I do the either of these queries:
var query1 = context.Quoters
.OfType<Recycler>()
.Include(r => r.AccountRef)
.Where(r => r.QuoterId == 1)
.ToList();
var query2 = context.Set<Recycler>()
.Include(r => r.AccountRef)
.Where(r => r.QuoterId == 1)
.ToList();
Exception shows that ResultType is “Transient.reference[POCOFirst.Quoter]”,but recommanded is “Transient.reference[POCOFirst.Recycler]”
If I remove the ToList(), it works well. But I need a list as the return value of method.
Why can't I do ToList()? Thanks

It looks like you have stumble upon this bug in EF. Another reference to the bug.
Workaround would be to remove the Include method.

Related

Entity Framework Core null relationship

I have created a simple EF Core to join two tables by using relationship (HasOne). But when I run it, the query only queries the master table (Employees) without joining to the second table (Contact) and it causes the model to not bind the data.
Could someone point out what I am missing in this code shown below? Thanks
public class Employees
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; }
public Contact Contact { get; set; }
}
public class Contact
{
public int Id { get; set; }
public string ContactNumber { get; set; }
public Employees Employee { get; set; }
public int EmployeeId { get; set; }
}
internal class EmployeeMap : IEntityTypeConfiguration<Employees>
{
public void Configure(EntityTypeBuilder<Employees> builder)
{
builder.HasKey(x => x.EmployeeId);
builder.Property(p => p.EmployeeId).ValueGeneratedOnAdd();
builder.HasOne(x => x.Contact).WithOne(y => y.Employee).HasForeignKey<Contact>(k => k.EmployeeId);
}
}
public class ContactMap : IEntityTypeConfiguration<Contact>
{
public void Configure(EntityTypeBuilder<Contact> builder)
{
builder.HasKey(x => x.Id);
builder.Property(p => p.Id).ValueGeneratedOnAdd();
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly);
}
private EmployeeResponse GetEmployeeResponse()
{
var emp = _context.Employees.FirstOrDefault();
return new EmployeeResponse
{
ContactNumber = emp!.Contact.ContactNumber,
EmployeeId = emp.EmployeeId,
};
}
Solutions:
1. Enable lazy loading:
DbContext.Configuration.LazyLoadingEnabled = true;
2. Or load it manually with .Include:
_context.Employees.Include(x => x.Contact).FirstOrDefault();
More information about navigation propertys in ef.

Entity Framework Core (EF 7) many-to-many results always null

I have followed the instructions for the workaround for many-to-many described in Issue #1368 and the Docs Here... but when I try to navigate, it always returns null.
My Models:
public class Organization
{
public Guid OrganizationID { get; set; }
//...
public ICollection<OrganizationSubscriptionPlan> OrganizationSubscriptionPlans { get; set; }
}
public class SubscriptionPlan
{
public int SubscriptionPlanID { get; set; }
//...
public ICollection<OrganizationSubscriptionPlan> OrganizationSubscriptionPlans { get; set; }
public class OrganizationSubscriptionPlan
{
[ForeignKey("Organization")]
public Guid OrganizationID { get; set; }
public Organization Organization { get; set; }
[ForeignKey("SubscriptionPlan")]
public int SubscriptionPlanID { get; set; }
public SubscriptionPlan SubscriptionPlan { get; set; }
}
ApplicationDbContext:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<OrganizationSubscriptionPlan>().HasKey(x => new { x.OrganizationID, x.SubscriptionPlanID });
builder.Entity<OrganizationSubscriptionPlan>().HasOne(x => x.Organization).WithMany(x => x.OrganizationSubscriptionPlans).HasForeignKey(x => x.OrganizationID);
builder.Entity<OrganizationSubscriptionPlan>().HasOne(x => x.SubscriptionPlan).WithMany(x => x.OrganizationSubscriptionPlans).HasForeignKey(x => x.SubscriptionPlanID);
}
And my Query:
var organizations = _context.Organizations
.Include(o => o.OrganizationSubscriptionPlans);
foreach (var organization in organizations)
{
//....
var subscriptions = organization.OrganizationSubscriptionPlans
.Select(s => s.SubscriptionPlan);
// ^^^^^^^^^^^ why is subscriptions always null?
}
The "organizations" query returns the results as expected, including the list of OrganizationSubscriptionPlans within each one, but when I try to navigate to them in the foreach loop the "subscriptions" query returns null every time. What am I doing wrong?
Turns out it's a Lazy Loading issue. You have to "Include" the joining entity and then "ThenInclude" the other entity.
var organizations = _context.Organizations
.Include(o => o.OrganizationSubscriptionPlans)
.ThenInclude(s => s.SubscriptionPlan);
ForeignKey attr is to decorate reference properties to indicate them what primitive property hold the FK value.
public class OrganizationSubscriptionPlan
{
public Guid OrganizationID { get; set; }
[ForeignKey("OrganizationID")]
public Organization Organization { get; set; }
public int SubscriptionPlanID { get; set; }
[ForeignKey("SubscriptionPlanID")]
public SubscriptionPlan SubscriptionPlan { get; set; }
}

Entity Framework 6: one-to-many doesn't update foreign key when inserting and removing in the same operation

I have these classes in my project (the names in the code are in Portuguese, if necessary I can translate) :
public class EntityWithGuid : IEntityWithId<string>
{
protected EntityWithGuid()
{
this.Id = Guid.NewGuid().ToString("N").ToLower();
}
[Key]
public string Id { get; set; }
}
public class Servico : EntityWithGuid
{
public DateTime? Data { get; set; }
public string Descricao { get; set; }
public string Cliente_Id { get; set; }
[ForeignKey("Cliente_Id")]
public Cliente Cliente { get; set; }
[Required]
public ICollection<ServicoImagem> Imagens { get; set; }
[Required]
public ICollection<Tag> Tags { get; set; }
}
public class ServicoImagem : EntityWithGuid
{
[Required]
public string Nome { get; set; }
public string Servico_Id { get; set; }
[Required]
public Servico Servico { get; set; }
}
public class Tag : EntityWithGuid
{
[Required]
public string Nome { get; set; }
public string Fonetica { get; set; }
public ICollection<Servico> Servicos { get; set; }
}
And this is the Context configuration:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ServicoConfiguration());
}
internal class ServicoConfiguration : EntityTypeConfiguration<Servico>
{
internal ServicoConfiguration()
{
this.HasMany(s => s.Tags)
.WithMany(t => t.Servicos)
.Map(mf =>
{
mf.MapLeftKey("Servico_Id");
mf.MapRightKey("Tag_Id");
mf.ToTable("ServicoTag");
});
this.HasMany(s => s.Imagens)
.WithRequired(i => i.Servico)
.HasForeignKey(f => f.Servico_Id);
}
}
After load a Servico entity the update method can do any operation with the Servico.Tags property (add and remove items), mark as modified and finally call Context.SaveChanges(). Everything works perfectly.
var servico = Context.Set<Servico>()
.Include(x => x.Cliente)
.Include(x => x.Tags)
.Include(x => x.Imagens)
.FirstOrDefault(x => x.Id == id);
...
// Remove tags
servico.Tags = servico.Tags.Except(oldTags).ToList();
// Add new tags
servico.Tags = servico.Tags.Concat(newTags).ToList();
...
Context.Entry(servico).State = EntityState.Modified;
Context.SaveChanges();
If I do the same thing with the Images property is only possible to make one type of operation at a time, add OR remove. If added and removed at the same time, the added item does not receive the value of the foreign key and error occurs in Context.SaveChanges() but if I do only one type of operation, it works perfectly.
The only solution I found was to make a loop to mark the item as deleted.
// Mark image as deleted
foreach (var imagem in imagensParaDeletar)
{
Context.Entry(imagem).State = System.Data.Entity.EntityState.Deleted;
}
I would like to understand why the problem ONLY occurs in this type of relationship and ONLY when I need to do both type of operation on the same property.

Fluent Mapping gone wrong on EF 4.1 with Code First

Here a simple model:
public class Product1
{
public int Id { get; set; }
public double Price { get; set; }
public int CurrencyID { get; set; }
public Currency Currency { get; set; }
}
public class Product2
{
public int Id { get; set; }
public double Price { get; set; }
public int CurrencyID { get; set; }
public Currency Currency { get; set; }
}
public class Currency
{
public int Id { get; set; }
public string Name { get; set; }
public string ISO4217 { get; set; }
public string Symbol { get; set; }
}
As you can see, Currency is just a list that will be used by two different entities, but If I try to run this, it gives me an error saying that this is not valid as could lead to multiple cascade paths.
Now I'm trying to figure how to model this on OnModelCreating
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product1>().HasRequired(p => p.Currency).WithMany().WillCascadeOnDelete(false);
modelBuilder.Entity<Product2>().HasRequired(p => p.Currency).WithMany().WillCascadeOnDelete(false);
}
But for some reason, although the product is correctly created, whenever I try to load it, Currency comes null.
What am I doing something wrong in this modelling?
Thanks!
I figured it out and I will explain here for future reference: After better looking the base created, I realized that it was creating a FK for the wrong field: P1:ID -> Currency:ID, when the correct should be P1:CurrencyID -> Currency:ID
So I found a way to force the correct FK:
modelBuilder.Entity<Product1>().HasRequired(p => p.Currency).WithMany().HasForeignKey(p => p.CurrencyId);
And that's all!
Map you classes like this:
public class Product1Mapping : EntityTypeConfiguration<Product1>
{
public Product1Mapping ()
{
ToTable("Product1");
HasKey(p => p.Id);
HasRequired(p => p.Tag).WithMany().HasForeignKey(t => t.CurrencyID);
}
}
public class Product2Mapping : EntityTypeConfiguration<Product2>
{
public Product2Mapping ()
{
ToTable("Product2");
HasKey(p => p.Id);
HasRequired(p => p.Tag).WithMany().HasForeignKey(t => t.CurrencyID);
//other properties
}
}
and change you OnModelCreating creating method like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new AccountMapping());
// Add other mapping classes
}
public DbSet<Product1> Product1{ get; set; }
public DbSet<Product2> Product2{ get; set; }
see these links for more information:
http://msdn.microsoft.com/en-us/data/jj591617.aspx
http://entityframework.codeplex.com/workitem/1049

Oracle ODP.Net and EF CodeFirst - edm.decimal error

I have the following simple entity:
public class Something{
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public int ID { get; set; }
public string NAME { get; set; }
public int STATUS { get; set; }
}
As you can see, I do not want the ID is generated from the database but I'm going to enter manually. This my DbContext class:
public class MyCEContext : DbContext {
...
public DbSet<Something> Somethings { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
string dbsch = "myce";
modelBuilder.Entity<Something>().ToTable("SOMETHING", dbsch);
}
}
There is nothing special here. But this code fails:
using (MyCEContext ctx = new MyCEContext()) {
Something t = new Something();
t.ID= 1;
t.NAME = "TEST";
t.STATUS = 100;
ctx.Somethings.Add(t);
ctx.SaveChanges();
}
This is the error:
The specified value is not an instance of type 'Edm.Decimal'
In general, allways EF try to send a value to an int primary key field, I get the edm.decimal error.
Any help?
As I commented on previous answer, I've found better solution, it is strange, but it works
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<TestEntity>().ToTable("TESTENTITY", "SCHEMENAME");
modelBuilder.Entity<TestEntity>().Property(p => p.Id).HasColumnName("ID").HasColumnType("INT");
modelBuilder.Entity<TestEntity>().Property(p => p.TestDateTime).HasColumnName("TESTDATETIME");
modelBuilder.Entity<TestEntity>().Property(p => p.TestFloat).HasColumnName("TESTFLOAT");
modelBuilder.Entity<TestEntity>().Property(p => p.TestInt).HasColumnName("TESTINT");
modelBuilder.Entity<TestEntity>().Property(p => p.TestString).HasColumnName("TESTSTRING");
}
and TestEntity looks like this
public class TestEntity
{
public int Id{ get; set; }
public string TestString { get; set; }
public int TestInt { get; set; }
public float TestFloat { get; set; }
public DateTime TestDateTime { get; set; }
}