Search code examples
c#linqdecimalcode-first

Why are signed negative numbers (decimal) Converted into unsigned in Linq/Lambda?


I have a table called Transactions with data as such:

SELECT [ID]
  ,[DateTime]
  ,[AccountID]
  ,[Type]
  ,[Amount]
FROM [TestModelDb].[dbo].[Transactions]

Outputs:

ID  DateTime    AccountID   Type    Amount
1   2015-03-17  1           0       10.00
2   2015-03-17  3           0       20.00
3   2015-03-17  1           0       100.00
4   2015-03-18  1           1       -10.00
5   2015-03-18  3           1       -5.00

I am using Code-First. When I make a simple query as the following all decimal numbers in the amount column are unsigned:

IEnumerable<decimal> test = Transactions.Select(t => t.Amount);
foreach (decimal amount in test)
{
    Debug.WriteLine("Amount: " + amount);
}

Displays as in the output box:

Amount: 10.00
Amount: 100.00
Amount: 10.00
Amount: 20.00
Amount: 5.00

Why is linq or lambda query dropping the sign?

Update #1

The Transaction Class:

public partial class Transaction : EntityBase
{
    public Transaction()
    {
        DateTime = DateTime.Now;
    }

    /// <summary>
    ///     Gets or sets the date time.
    /// </summary>
    /// <value>The date time.</value>
    public DateTime DateTime { get; set; }

    /// <summary>
    ///     Gets or sets the account identifier.
    /// </summary>
    /// <value>The account identifier.</value>
    public int AccountID { get; set; }

    /// <summary>
    ///     Class Transaction.
    /// </summary>
    /// <summary>
    ///     Gets or sets the account.
    /// </summary>
    /// <value>The account.</value>
    [ForeignKey("AccountID")]
    public Account Account { get; set; }

    /// <summary>
    ///     Gets or sets the type.
    /// </summary>
    /// <value>The type.</value>
    [Required]
    public TransactionType Type { get; set; }

    private decimal _amount;

    /// <summary>
    ///     Gets or sets the amount.
    /// </summary>
    /// <value>The amount.</value>
    public decimal Amount
    {
        get { return _amount; }
        set
        {
            decimal temp;
            if (Type == TransactionType.Withdrawal)
                temp = value*-1;
            else temp = value;
            _amount = temp;
        } 
    }
}

My DbContext:

public class TestContext : DbContext
{
    public TestContext()
        : base("name=TestContext")
    {
    }

    public DbSet<Person> People { get; set; }
    public DbSet<Account> Accounts { get; set; }
    public DbSet<Transaction> Transactions { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
    }
} 

Solution

  • Entity Framework uses the setter on each property when it hydrates the object from the database call. In other words, as it builds the object it is setting the Amount to -10, but since it's a Withdrawal, this code (as Robert pointed out) is flipping the value back to positive:

    if (Type == TransactionType.Withdrawal)
                temp = value*-1;
    

    Try changing it to:

    if (Type == TransactionType.Withdrawal && value > 0)
                temp = value*-1;
    

    Also, as Robert commented, it's very dangers that var t = new Transaction(); t.TransactionType=Withdrawl; t.Amount=50; and var t = new Transaction(); t.Amount=50;t.TransactionType=Withdrawl; give different results.

    You should probably make the Transaction type immutable, or at least require the type in the constructor. If you do that, rembmer that EF needs a parameterless constructor. Fortunately, it finds it through Reflection, so you can make that constructor private.