10

I have a POCO model class and an existing DB table, neither of which I am able to change I am using Entity Framework 6 and the Fluent API.

The model class has a CountryId of 'int'. However, in the database table, the CtryId is a 'tinyint'.

I tried to set the type using

modelBuilder.Entity<Event>().Property(e => e.CountryId).HasColumnName("CtryId").HasColumnType("tinyint");

in the OnModelCreating method but get the following error:

error 2019: Member Mapping specified is not valid. The type 'Edm.Int32[Nullable=False,DefaultValue=]' of member 'CountryId' in type 'RA.Data.Event' is not compatible with 'SqlServer.tinyint[Nullable=False,DefaultValue=]' of member 'CtryId' in type 'CodeFirstDatabaseSchema.Event'.

How do I map a C# int to a SqlServer tinyint using Entity Framework Code First?

4
  • Why aren't you using Byte in C#? Commented Mar 28, 2014 at 13:19
  • " neither of which I am able to change" - Can you find the person who can change your model to match the DB, or vice versa? Commented Mar 28, 2014 at 13:20
  • 1
    Is your "core" POCO model a partial class? Commented Mar 28, 2014 at 13:35
  • 3
    I'm a little confused as to why you are not able to change either the DB or the POCO. Could you expand on that restriction? It seems to me you've been put between a rock and a hard place by being told, "Make this work, but don't change anything." I'm wondering if perhaps the "unable to change" is arbitrary and a good argument could win out. As far as why it won't work, .NET is trying to prevent you from losing data because the .NET int holds a larger range of values than the DB tinyint. Commented Mar 28, 2014 at 13:42

3 Answers 3

14

Short answer : You can't.

The mappings "line up" like below.

The property on the POCO should be "byte".

    public byte CountryId{ get; set; }

and the Mapping:

        this.Property(t => t.CountryId).HasColumnName("CtryId");

You gotta play by the rules of EF.

However, the good news is that you can make it work with a little magic.

Since you don't want to break the contract..... you can do a workaround.

public byte JustForMappingCtryId{ get; set; }

[NotMapped]
public int CountryId
{ 
    get
    { 
        return Convert.ToInt32(this.JustForMappingCtryId);
    } 
    set
    {
        if(value > 8 || value < 0 )
        {
              throw new ArgumentOutOfRangeException("Must be 8 or less, and greater or equal to zero.");
        }
        //this.JustForMappingCtryId = value;  /* Uncomment this code.. to put back the setter... you'll have to do the conversion here (from the input int to the byte) of course..but the edited out code shows the intention */      
    }
}

and the mapping:

   this.Property(t => t.JustForMappingCtryId).HasColumnName("CtryId");

And put an entity framework "ignore" attribute on CountryId. (above seen as [NotMapped]) .. OR use the Fluent way to specify the ignore (not shown in the code above) but below is a breadcrumb:

 modelBuilder.Entity<MyEntity>().Ignore(c => c.MyPocoProperty);

There ya go. It is a workaround, but should fit your need.

....

And finally: a not-sure-it-would-work-but-maybe-try-it:

Maybe try to change this:

public byte JustForMappingCtryId{ get; set; }

to

internal byte JustForMappingCtryId{ get; set; }

But I'm not sure EF would like that.

The idea here is to "hide" from other assemblies this property.

Sign up to request clarification or add additional context in comments.

1 Comment

Still it's an unnecessary limitation. I should have been able to map a tinyint even to a long if I wanted to. There are many, many other invalid mappings that are not being statically enforced and you have to write business logic for anyway. Like the length of a string. The problem with mapping to a byte is that now I need to recast to an int everywhere in my code - because a lot of things do work with ints, not with bytes. or I have to write an unnecessary wrapper. Bad call from the EF designers.
4

In EF, int32 maps to int in the db. In this case, tinyint maps to byte in the .NET framework. You should change your CountryId to the type of byte in the POCO model.

Comments

-1

You could create a new POCO class with byte column and use it instead of the old POCO class.

You could use AutoMapper to copy the values between old POCO class used in higher layers and new POCO class used in your repository layer for storing purposes.

4 Comments

Wouldn't replacing one model class with another be considered a "change"?
No, if the old class is in a referenced assembly you cannot change. OP is clear they cannot change that class, not that they cannot write more code...
Yes, but the other answers that were posted earlier and downvoted are just as useful as this suggestion. For example, the answer from @Zafar doesn't preclude replacing the class with a new class.
I don't think OP is clear at all that they can't modify the original model, but are free to replace it with a different model. It seems more likely that they are stuck using the model they were given.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.