Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HasKey() throws confusing exception about redefining key if no inheritance was intended #3863

Closed
divega opened this issue Nov 23, 2015 · 5 comments
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@divega
Copy link
Contributor

divega commented Nov 23, 2015

Work item is to add info about how you an get into this case.


From #3727 (comment) by @miroslavsiska: the following throws

InvalidOperationException: The derived type 'CashDesk.Models.AllergenQuantityMaterial' cannot have keys other than those declared on the root type.

Note that this is still a negative scenario, e.g. there cannot be a navigation property of the base type if the base type does not define the key. But the exception isn't very helpful if the type wasn't intended as an entity type in the first place.

Repro code:

public class AllergenQuantity
{              
    public Guid UnitId { get; set; }
    public virtual Unit Unit { get; set; }         

    [Display(Name = "Množství obsahu")]
    public decimal Quantity { get; set; }
}


 public class Unit 
{
    public Unit()
    {
        this.Id = Guid.NewGuid();
    }
    public virtual ICollection<AllergenQuantity> AllergenQuantity { get; set; }

    [Key]
    public Guid Id { get; set; }     

    [Display(Name = "Jednotka")]
    public string Name { get; set; }

    [Display(Name = "Typ Jednotky")]
    public string UnitType { get; set; }

    [Display(Name = "Použité v kulturách")]
    public string Cultures { get; set; }
}


  public class TenantDbContext : IdentityDbContext<TenantUser, TenantRole, Guid>
{
    private string _connectionString { get; set; }

    public TenantDbContext(DbContextOptions<TenantDbContext> options) : base(options) 
    {
        this._connectionString = "CON STRING";
    }

    public TenantDbContext()       
    {
    }   
    public TenantDbContext(string ConnectionString)
    {
        this._connectionString = ConnectionString;
    }
    public static TenantDbContext Create(string ConnectionString)
    {
        return new TenantDbContext(ConnectionString);
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    { 
        optionsBuilder.UseSqlServer(_connectionString);  
    }

    //  BASE
    public DbSet<Unit> Unit { get; set; }

    //  Stock
    public DbSet<Allergen> Allergen { get; set; }  
    public DbSet<AllergenQuantityMaterial> AllergenQuantityMaterial { get; set; }        
        //Inherited from AllergenQuantity
    public DbSet<Material> Material { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {      
        base.OnModelCreating(builder);

        // Throws
        builder.Entity<AllergenQuantityMaterial>().HasKey(l => new { l.MaterialId, l.AllergenId });  
    }
}
@divega
Copy link
Contributor Author

divega commented Nov 23, 2015

@smitpatel feel free to start looking at this. Although it isn't triaged @ajcvickers @AndriySvyryd @rowanmiller and I already discussed it.

@divega divega changed the title HasKey throws confusing exception about redifinging key when no inheritance was intended HasKey throws confusing exception about redefining key when no inheritance was intended Nov 23, 2015
@divega divega changed the title HasKey throws confusing exception about redefining key when no inheritance was intended HasKey() throws confusing exception about redefining key when no inheritance was intended Nov 23, 2015
@miroslavsiska
Copy link

@divega Please check your E-mail - I sended you complete solution with this bug...

@divega divega changed the title HasKey() throws confusing exception about redefining key when no inheritance was intended HasKey() throws confusing exception about redefining key if no inheritance was intended Nov 23, 2015
@maumar
Copy link
Contributor

maumar commented Nov 23, 2015

I think this is applicable to this discussion, I have a model with two types:

public abstract class Person 
{ 
public int Id {get; set; }
}

and

public class Donor : Person
{
}

in OnModelCreating I have the following snippet:

            modelBuilder.Entity<Person>().HasKey(p => p.PersonId);
            modelBuilder.Entity<Donor>().HasKey(d => d.PersonId);

this throws the following exception:

Unhandled Exception: System.InvalidOperationException: The derived type 'Donor' cannot have keys other than those declared on the root type 'Person'.

This is confusing to me, because both entities have the same key.

@rowanmiller rowanmiller added this to the 7.0.0 milestone Nov 24, 2015
@rowanmiller rowanmiller self-assigned this Nov 24, 2015
@rowanmiller rowanmiller modified the milestones: 7.0.0-rc2, 7.0.0 Dec 2, 2015
rowanmiller added a commit that referenced this issue Jan 22, 2016
Resolve #3863

A common cause of this exception is unintentionally including a base
type in the model. Adding info about how to stop this happening to the
exception message.

**Old Message:** The derived type 'Address' cannot have keys other than
those declared on the root type 'AddressBase'.

**New Message:** A key cannot be configured on 'Address' because it is a
derived type. The key must be configured on the root type 'AddressBase'.
If you did not intend for 'AddressBase' to be included in the model,
ensure that it is not included in a DbSet property on your context,
referenced in a configuration call to ModelBuilder, or referenced from a
navigation property on a type that is included in the model.
@mii9000
Copy link

mii9000 commented Mar 18, 2017

@maumar What was your solution to this?
@rowanmiller Why is it required for the Id property to be on the root type?
I am making my entity classes by inheriting from domain model classes which are just POCOs without annotations or db related properties. How am I suppose to make this scenario work?

@AndriySvyryd
Copy link
Member

@ibrahim-islam The key must be defined on the base type because EF allows assigning derived entities to navigations configured with the base entity type.
If you don't need to track the base entity type you can just ignore it in 'OnModelCreating'

@ajcvickers ajcvickers removed this from the 1.0.0-rc2 milestone Oct 15, 2022
@ajcvickers ajcvickers added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Oct 15, 2022
@ajcvickers ajcvickers added this to the 1.0.0 milestone Oct 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

7 participants