This project has moved. For the latest updates, please go here.
4

Closed

System.Collections.Generic.KeyNotFoundException in MapperBase.BindForeignKeys

description

Hi,

First of all, thank you for this really good library!

Second, there is an issue when you try to get mapping in MapperBase.BindForeignKeys:
Exception: The given key was not present in the dictionary.
StackTrace: at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at EntityFramework.MappingAPI.Mappers.MapperBase.BindForeignKeys() in c:\dev\
EntityFramework.MappingAPI\trunk\src\EntityFramework.MappingAPI\Mappers\MapperBa
se.cs:line 603
at EntityFramework.MappingAPI.Mappings.DbMapping..ctor(DbContext context) in
c:\dev\EntityFramework.MappingAPI\trunk\src\EntityFramework.MappingAPI\Mappings\
DbMapping.cs:line 101
at EntityFramework.MappingAPI.EfMap.Get(DbContext context) in c:\dev\EntityFr
amework.MappingAPI\trunk\src\EntityFramework.MappingAPI\EfMap.cs:line 60
at EntityFramework.MappingAPI.EfMap.Get[T](DbContext context) in c:\dev\Entit
yFramework.MappingAPI\trunk\src\EntityFramework.MappingAPI\EfMap.cs:line 26
at EntityFramework.MappingAPI.Extensions.MappingApiExtensions.Db[T](DbContext
ctx) in c:\dev\EntityFramework.MappingAPI\trunk\src\EntityFramework.MappingAPI\
Extensions\MappingApiExtensions.cs:line 27

The use case: you need to have foreign keys and primary keys which are mapped to the different column names than the property names.
I have found that a column name is added in MapperBase.MapEntity(string typeFullName, EdmType edmItem):
line 346: _pks[tableName] = storageEntitySet.ElementType.KeyMembers.Select(x => x.Name).ToArray();

But then in method private void MapProperty(EntityMap entityMap, EdmProperty edmProperty, ref int i, ref string prefix) on line 535 a property name is checked:
        if (_pks[entityMap.TableName].Contains(propName))
So if the property name is not equal to column name then the property won't be marked as a primary key.
I didn't check, but maybe the same applies to the foreign keys.

Can you please take a look and fix it?

Best Regards,
Igor
Closed Jan 20, 2015 at 8:46 PM by maxlego

comments

vsitman451 wrote Jun 12, 2014 at 8:38 AM

I faced the same issue. And yes the reason is in the MapProperty method where
this line fails to determine that property is primary key.

if (_pks[entityMap.TableName].Contains(propName))
{
            propertyMap.IsPk = true;
            entityMap.AddPk(propertyMap);
}

the problem is that property name and columnname can differ (different case or even name, e.g. this.Property(t => t.Id).HasColumnName("ID"))

It is easily reproducable.

Argel wrote Jul 3, 2014 at 8:19 PM

i faced the same issue, when i was trying to use your BulkInsert extension. I get the sources and change the following statement in MapperBase.cs

_pks[tableName] = storageEntitySet.ElementType.KeyMembers.Select(x => x.Name).ToArray();

to

_pks[tableName] = ((ReadOnlyMetadataCollection<EdmMember>) edmItem.MetadataProperties["KeyMembers"].Value).Select(x => x.Name).ToArray();

for what I learned, that issue is produced because the CodeFirstMapper uses the SSpace dataSpace and the KeyMembers property returns the Database names for keys in this case, not the properties Name that can be different.
With the line replaced I get the KeyMembers as Properties not database columns.

Here is a simple test case that


** The test
        [Test]
        public void Entity_With_CustomMapping()
        {
            using (var ctx = new TestContext())
            {
                var map = ctx.Db<EntityWithMapping>();
                Console.WriteLine("{0}:{1}", map.Type, map.TableName);

                map.Prop(x => x.BancoId)
                    .HasColumnName("BancoID")
                    .IsPk(true)
                    .IsFk(false)
                    .IsRequired(true)
                    .IsIdentity(false)
                    .IsNavigationProperty(false);
            }
        }
** The Class and Mappings
    public class EntityWithMapping
    {
        public int BancoId { get; set; }
        public string Nombre { get; set; }
    }

    public class EntityWithMappingMap : EntityTypeConfiguration<EntityWithMapping>
    {
        public EntityWithMappingMap()
        {
            this.HasKey(k => k.BancoId);

            this.Property(p => p.BancoId).HasColumnName("BancoID").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
            this.Property(p => p.Nombre).HasColumnName("Nombre").IsRequired();

            this.ToTable("EntityWithMapping");
        }
    }
** The TestContext
mb.Configurations.Add(new EntityWithMappingMap());

wrote Jul 3, 2014 at 8:19 PM

wrote Jul 29, 2014 at 8:36 PM

PierreLucB wrote Sep 1, 2014 at 1:09 PM

Hi,

I have this too. (bindingForeignKeys error)


I found a solution, DO NOT rename pocos. BulkInsert is base on the database structure to make the mapping before insert.

It uses the SSPace option of the DataSpace enumeration => http://msdn.microsoft.com/fr-fr/library/system.data.metadata.edm.dataspace(v=vs.110).aspx

So, the mappings not worked, and fall at binding foreign keys. It's a bug.

So, in order to makes working BulkInsert, you have to NOT rename pocos and properties..

I hope the author will correct that, I lost two days to find why we get this error.

wrote Sep 2, 2014 at 1:26 PM

Vokail wrote Sep 9, 2014 at 6:45 AM

see this issue for a fix on this item
TEXT

wrote Nov 13, 2014 at 7:16 PM

wrote Jan 20, 2015 at 8:46 PM