Search code examples
c#entity-frameworkef-model-first

Entity Framework issues - appends a "1" to my table name?


I have the following model-first (is that what it's called?) diagram that I have made. I use T4 to generate the classes.

enter image description here

Now, I have a problem that causes Entity Framework to somehow append a "1" to the table name of the DatabaseSupporter entity. The database has been generated from this very model, and nothing has been modified.

I am trying to execute the following line:

_entities.DatabaseSupporters.SingleOrDefault(s => s.Id == myId);

The error I receive when executing that line (along with its inner exception below) is:

An exception of type 'System.Data.Entity.Core.EntityCommandExecutionException' occurred in mscorlib.dll but was not handled in user code.

Invalid object name 'dbo.DatabaseSupporter1'.

I tried fixing the problem with the following Fluent API code (notice the second line in the function that names the table explicitly to "DatabaseSupporter"), but with no luck.

protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{

    modelBuilder
        .Entity<DatabaseSupporter>()
        .HasOptional(f => f.DatabaseChatSession)
        .WithOptionalPrincipal(s => s.DatabaseSupporter);

    modelBuilder
        .Entity<DatabaseSupporter>()
        .Map(m =>
        {
            m.Property(s => s.Id)
                .HasColumnName("Id");
            m.ToTable("DatabaseSupporter");
        });

    modelBuilder
        .Entity<DatabaseSupporter>()
        .HasMany(s => s.DatabaseGroups)
        .WithMany(g => g.DatabaseSupporters)
        .Map(m =>
        {
            m.ToTable("DatabaseSupporterDatabaseGroup");
            m.MapLeftKey("DatabaseGroups_Id");
            m.MapRightKey("DatabaseSupporters_Id");
        });

    modelBuilder
        .Entity<DatabaseGroup>()
        .HasRequired(g => g.DatabaseChatProgram)
        .WithMany(c => c.DatabaseGroups);

    modelBuilder
        .Entity<DatabaseGroup>()
        .HasRequired(g => g.DatabaseOwner)
        .WithMany(o => o.DatabaseGroups);

    modelBuilder
        .Entity<DatabaseOwner>()
        .HasMany(o => o.DatabaseChatSessions)
        .WithRequired(o => o.DatabaseOwner);

    base.OnModelCreating(modelBuilder);
}

It should be mentioned that the Id property for every entity actually is a Guid.

I am using Entity Framework 6.0.2.

Any ideas?

Edit 1 Here's the generated DatabaseSupporter.cs file containing my DatabaseSupporter entity as requested in the comments.

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace Coengage.Data.Entities
{
    using System;
    using System.Collections.Generic;

    public partial class DatabaseSupporter
    {
        public DatabaseSupporter()
        {
            this.DatabaseGroups = new HashSet<DatabaseGroup>();
        }

        public bool IsActive { get; set; }
        public string Username { get; set; }
        public System.Guid Id { get; set; }

        public virtual DatabaseChatSession DatabaseChatSession { get; set; }
        public virtual ICollection<DatabaseGroup> DatabaseGroups { get; set; }
    }
}

Edit 2 The errors started occuring after I added the many-to-many link between DatabaseSupporter and DatabaseGroup. Before that link, the Fluent code wasn't needed either.


Solution

  • This mapping is incorrect:

    modelBuilder
        .Entity<DatabaseSupporter>()
        .Map(m =>
        {
            m.Property(s => s.Id)
                .HasColumnName("Id");
            m.ToTable("DatabaseSupporter");
        });
    

    It is kind of 50 percent of a mapping for Entity Splitting - a mapping that stores properties of a single entity in two (or even more) separate tables that are linked by one-to-one relationships in the database. Because the mapping is not complete you even don't get a correct mapping for Entity Splitting. Especially EF seems to assume that the second table that contains the other properties (that are not explicitly configured in the mapping fragment) should have the name DatabaseSupporter1. I could reproduce that with EF 6 (which by the way has added a Property method to configure single properties in a mapping fragment. In earlier versions that method didn't exist (only the Properties method).) Also the one-to-one constraints are not created correctly in the database. In my opinion EF should throw an exception about an incorrect mapping here rather than silently mapping the model to nonsense without exception.

    Anyway, you probably don't want to split your entity properties over multiple tables but map it to a single table. You must then replace the code block above by:

    modelBuilder.Entity<DatabaseSupporter>()
        .Property(s => s.Id)
        .HasColumnName("Id");
    
    modelBuilder.Entity<DatabaseSupporter>()
        .ToTable("DatabaseSupporter");
    

    The first mapping seems redundant because the property Id will be mapped by default to a column with the same name. The second mapping is possibly also redundant (depending on if table name pluralization is turned on or not). You can try it without this mapping. In any case you shouldn't get an exception anymore that complains about a missing dbo.DatabaseSupporter1.