Search code examples
sqlentityderived

Derived Class Properties Getting Passed to SQL Server via Entity Framework


When retrieving a list of objects from SQL Server , I am getting the following error:

System.Data.SqlClient.SqlException
Invalid column name 'AccountName'
Invalid column name 'AccountNumber'

I understand that the database does not contain those columns, but I don't believe my code should be passing those columns for retrieval.

I have a class that is being derived from and Entity Framework code-first class that has a few extra properties added to it.

For some reason, when I make the database call, it passes the extra properties created by the TransactionHistoryGrid class to SQL Server, when it should only be passing the TransactionHistory properties.

Here is the code:

Entity Framework code-first class:

public partial class TransactionHistory : Transaction
{
    public string BillingAddressCity { get; set; }
    public string BillingAddressCompany { get; set; }
    public string BillingAddressCountry { get; set; }
    public string BillingAddressFax { get; set; }
    public string BillingAddressFirst { get; set; }
    public string BillingAddressLast { get; set; }
    public string BillingAddressPhone { get; set; }
    public string BillingAddressState { get; set; }
    public string BillingAddressStreet { get; set; }
    public string BillingAddressZip { get; set; }

    [System.ComponentModel.DataAnnotations.Schema.NotMapped]
    public Address BillingAddress { get; set; }

    [System.ComponentModel.DataAnnotations.Schema.NotMapped]
    public Address ShippingAddress { get; set; }

    public System.Guid ID { get; set; }
    public virtual Account Account { get; set; }
}

Class to populate Kendo Grid:

public class TransactionHistoryGrid : TransactionHistory
{
    public string AccountName { get; set; }
    public string AccountNumber { get; set; }

    public static List<TransactionHistoryGrid> GetTransactionHistoryGrid()
    {
        List<TransactionHistoryGrid> grids = new List<TransactionHistoryGrid>();

        // This is where the trouble begins:
        foreach (TransactionHistory t in GetAllTransactionHistories())
        {
            // It doesn't make it this far.
            var grid = new TransactionHistoryGrid()
            {
                Account = t.Account;
                AccountName = t.Account.AccountName;
                AccountNumber = t.Account.AccountNumber;
            };
            grids.Add(grid);
        }
        return grids;
    }
}

Method to retrieve data:

    public static List<TransactionHistory> GetAllTransactionHistories()
    {
        using (DatabaseContext context = new DatabaseContext())
        {
            // Error gets thrown here... Why are the extra properties being read??
            return context.Set<TransactionHistory>().ToList();
        }
    }

Usage from controller:

public ActionResult TransactionHistory_Read([DataSourceRequest]DataSourceRequest request = null)
{
    List<TransactionHistoryGrid> transactionHistory = TransactionHistoryGrid.GetTransactionHistoryGrid();            

    DataSourceResult result = transactionHistory.ToDataSourceResult(request);
    return Json(result, JsonRequestBehavior.AllowGet);
}

Thoughts? Suggestions?

This is what SQL Server Profiler returns:

(AccountName, AccountNumber, and TransactionHistoryGrid should never be sent to SQL. Why is it?)

SELECT 
    1 AS [C1], 
    [Extent1].[Discriminator] AS [Discriminator], 
    ...
    [Extent1].[AccountName] AS [AccountName], 
    [Extent1].[AccountNumber] AS [AccountNumber], 
    [Extent1].[Account_ID] AS [Account_ID], 
    [Extent1].[BillingStatement_ID] AS [BillingStatement_ID]
    FROM [dbo].[TransactionHistories] AS [Extent1]
WHERE [Extent1].[Discriminator] IN (N'TransactionHistoryGrid',N'TransactionHistory')

Solution

  • Reposting from the comment thread:

    Type Discovery as described here is probably at play. The [NotMapped] attribute has the AttributeTargets.Class, AttributeTargets.Property and AttributeTargets.Field flags, so unless you ever intend to manipulate the TransactionHistoryGrid properties directly via the DatabaseContext, you could just put the attribute on the entire class.

    [NotMapped]
    public class TransactionHistoryGrid : TransactionHistory
    {
        ...
    }
    

    The alternative would be to move the TransactionHistoryGrid class into another assembly.