Entity Framework C# convert int to bool
Asked Answered
O

6

6

I'm attempting to re-write a VB.NET WebForms application in C# MVC. I'm having an issue with one of the properties when using Entity Framework to instantiate a class.

I have a column in my database "VATInclusive", which is of type 'int'. The original application implicitly converted a "1" or "0" to "true" or "false", but when trying to do this in my application, I get the following error:

The 'VATInclusive' property on 'Shop' could not be set to a 'System.Int32' value. You must set this property to a non-null value of type 'System.Boolean'.

I can't simply change the type in the database as other applications make use of the table. I've tried using the following code to convert the value, but it seems to only return false, regardless of whether the database has a "0" or a "1"... Can anybody suggest a solution to this?

    [Column("VATInclusive")]
    private int _VATInclusive { get; set; }

    [NotMapped]
    public bool VATInclusive
    {
        get
        {
            if (_VATInclusive == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        set 
        {
            if(_VATInclusive == 0)
            {
                this.VATInclusive = false;
            }
            else 
            {
                this.VATInclusive = true;
            }
        }
    } 
Ore answered 26/10, 2014 at 20:42 Comment(1)
When you say "I'm not having any luck," what exactly do you mean?Reger
O
10

Following some advice from the answers provided, I have rectified the issue. The issue lay with the setter accessor and also with the _VATIncusive property. By changing the code to the following I have managed to get the system to work as I expected.

However, I feel that this isn't the best approach, but it appears to be working correctly...

EDIT : EDIT : I've reduced the get accessor as per advice from Ryan and hvd..

EDIT : I'm not sure of the implications of having both properties set to public. But I don't think this is going to be an issue.

    [Column("VATInclusive")]
    public int _VATInclusive { get; set; }

    [NotMapped]
    public bool VATInclusive
    {
        get
        {
            return _VATInclusive != 0;
        }
        set 
        {
            _VATInclusive = value ? 1 : 0;
        }
    }
Ore answered 26/10, 2014 at 20:57 Comment(6)
Functionally, this is fine. You could get the accessor down to a single line by saying "return Convert.ToBoolean(_VATInclusive);". It's fine as-is to me, though.Shovelnose
Or get { return _VATInclusive != 0; }. Just beware that you can only use your VATInclusive property in your own code, it cannot be translated to SQL. Something like db.Shops.Where(s => s.VATInclusive).ToList() will compile but throw an exception at run-time, you'll still have to write that as db.Shops.Where(s => s._VATInclusive != 0).ToList().Ares
@hvd I guess there's no real way around this? I'm still trying to re-write this in a more elegant way, but I think the solution above is as close as it is going to get. I may just investigate the affect changing the DB type will have on the VB.NET applications...Ore
@MrBearding The way around it is to not write queries like that, and that's perfectly doable. :) If you take any shop from db.Shops.ToList(), you can inspect the VATInclusive property and even modify it without any issues. It's only when you refer to that property before you have a concrete object that you'll run into issues.Ares
@hvd Okay. I don't think this will be a massive problem. I'm now just toying with the idea of having the property as an integer type and then always do lookups on If VATInclusive == 1 as opposed to If VATInclusive. I can't think of an instance where it would need to be a boolean? - It would at least lead to a prettier model...Ore
It is possible to make the mapped column private or internal, depending on how you want to run queries. See https://mcmap.net/q/402464/-convert-value-when-mappingCoatee
L
4

If you store the column as a bit, Entity Framework automatically queries it as a Boolean for you.

Liveryman answered 19/10, 2017 at 12:1 Comment(0)
S
1

You have some typos on your setter. I think you mean for it to be:

set 
    {
        if(value == false)
        {
            _VATInclusive = 0;
        }
        else 
        {
            _VATInclusive = 1;
        }
    }

Basically, "value" represents the bool value passed in to your setter (to be converted in to an integer). _VATInclusive is the actual object that you want to be modifying under-the-hood.

Shovelnose answered 26/10, 2014 at 20:47 Comment(1)
Your idea may be right, but your details aren't. As you say, value is a bool, so it cannot be compared to zero. _VATInclusive is an int, not a bool, so it cannot be assigned false or true.Ares
R
1

You can't have a setter accessor assign to itself - this will always result in a StackOverflowException. In the below code:

set 
{
    if(_VATInclusive == 0)
    {
        this.VATInclusive = false;
    }
    else 
    {
        this.VATInclusive = true;
    }
}

every time this.VATInclusive is assigned to, the control flow returns to the beginning of the set accessor. This obviously can never complete.

Reger answered 26/10, 2014 at 20:51 Comment(0)
D
0

In your set, you need to compare against value:

if (value == 0)
Dhole answered 26/10, 2014 at 20:47 Comment(0)
E
0

In Entity Framework Core you can use Value Conversions like this:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<MyEntity>()
        .Property(e => e.VATInclusive)
        .HasConversion<int>();
}

Or:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var converter = new BoolToZeroOneConverter<int>();

    modelBuilder
        .Entity<MyEntity>()
        .Property(e => e.VATInclusive)
        .HasConversion(converter);
}

You can learn more here

Elsa answered 2/2 at 17:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.