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;
            }
        }
    } 
Ant
  • 462
  • 1
  • 4
  • 18

5 Answers5

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;
        }
    }
Ant
  • 462
  • 1
  • 4
  • 18
  • 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. – Ryan Nigro Oct 26 '14 at 20:59
  • 1
    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()`. –  Oct 26 '14 at 21:11
  • @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... – Ant Oct 26 '14 at 21:14
  • 1
    @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. –  Oct 26 '14 at 21:19
  • @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... – Ant Oct 26 '14 at 21:23
  • It is possible to make the mapped column private or internal, depending on how you want to run queries. See http://stackoverflow.com/a/19377226/150342 – Colin Oct 27 '14 at 10:01
4

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

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.

Ryan Nigro
  • 4,389
  • 2
  • 17
  • 23
  • 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`. –  Oct 26 '14 at 21:08
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.

furkle
  • 5,019
  • 1
  • 15
  • 24
0

In your set, you need to compare against value:

if (value == 0)
Jason W
  • 13,026
  • 3
  • 31
  • 62