4

I keep getting the below exception. The exception baffles me because I am not selecting UserID.

I have tried changing the select to SELECT * but this just causes a result.Count of 0 regardless if the data exists or not.

I have a dummy record in the Database called bob tob.

I have noticed that if I hover over the Users part of db.Users.SqlQuery.

The text inside is

{SELECT 
[Extent1].[userID] AS [userID], 
[Extent1].[userFirstName] AS [userFirstName], 
[Extent1].[userLastName] AS [userLastName], 
[Extent1].[userName] AS [userName], 
[Extent1].[userEmail] AS [userEmail], 
[Extent1].[userPassword] AS [userPassword], 
[Extent1].[userStatus] AS [userStatus], 
[Extent1].[userEmailVerificationStatus] AS [userEmailVerificationStatus], 
[Extent1].[userActivationCode] AS [userActivationCode]
FROM [dbo].[Users] AS [Extent1]}

I am guessing it's trying to SELECT all of the User class items regardless? If that's true Then how do I stop this? What am I missing?

This is the exception:

The data reader is incompatible with the specified 'UserRegistrationPasswordsModel.User'. A member of the type, 'userID', does not have a corresponding column in the data reader with the same name.

Below is the code that calls EmailExists. I added the ToString() falsely hoping that maybe was the issue.

#region EmailExist
// Email already exists?
if (Utilities.EmailExists(user.userEmail.ToString()))
{
    // A pretty awesome way to make a custom exception
    ModelState.AddModelError("EmailExist", "Email already exists");

    // Bounce back
    return View(user);
}
#endregion

Below is the procedure that is supposed to check if the email exists or not.

#region EmailExists
    // Confirm if the Email exists or not
    public static bool EmailExists(string Email)
    {
        bool result = false;
        Models.UserRegistrationPasswordsEntities1 db = new Models.UserRegistrationPasswordsEntities1();
        var queryResult = db.Users.SqlQuery("SELECT userEmail FROM Users WHERE userEmail = @1;", 
                                                                          new SqlParameter("@1", Email)).FirstOrDefault();

        // the ternary opertor is pretty awesome
        result = queryResult.Result.GetType() == null ? false : true;

        return result;
    }
    #endregion

This is the table structure:

CREATE TABLE [dbo].[Users]
(
    [userID]                      INT              IDENTITY (1, 1) NOT NULL,
    [userFirstName]               VARCHAR (50)     NOT NULL,
    [userLastName]                VARCHAR (50)     NOT NULL,
    [userName]                    VARCHAR (50)     NOT NULL,
    [userEmail]                   VARCHAR (50)     NOT NULL,
    [userPassword]                VARCHAR (100)    NOT NULL,
    [userStatus]                  BIT              DEFAULT ((0)) NOT NULL,
    [userEmailVerificationStatus] BIT              DEFAULT ((0)) NOT NULL,
    [userActivationCode]          UNIQUEIDENTIFIER DEFAULT (newid()) NOT NULL,
    [userDateOfBirth]             DATETIME         NOT NULL,

    PRIMARY KEY CLUSTERED ([userID] ASC)
);

And this is the User model class:

public partial class User
{
    public int userID { get; set; }

    [Display(Name = "First Name")]
    [DataType(DataType.Text)]
    [Required(AllowEmptyStrings = false, ErrorMessage ="First name required")]
    public string userFirstName { get; set; }

    [Display(Name = "Last Name")]
    [DataType(DataType.Text)]
    [Required(AllowEmptyStrings = false, ErrorMessage = "Last name required")]
    public string userLastName { get; set; }

    [Display(Name = "Username")]
    [DataType(DataType.Text)]
    [Required(AllowEmptyStrings = false, ErrorMessage = "Username required")]
    public string userName { get; set; }

    [Display(Name = "Email")]
    [DataType(DataType.EmailAddress)]
    [Required(AllowEmptyStrings = false, ErrorMessage = "email is required")]
    public string userEmail { get; set; }

    [Display(Name = "Date Of Birth")]
    [DataType(DataType.DateTime)]
    [Required(AllowEmptyStrings = false, ErrorMessage = "Date of Birth is required")]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
    public DateTime userDateOfBirth { get; set;}


    [Display(Name = "Password")]
    [DataType(DataType.Password)]
    [Required(AllowEmptyStrings = false, ErrorMessage = "Password is required")]
    [MinLength(6, ErrorMessage = "Minimum of 6 characters required")]
    public string userPassword { get; set; }

    [Display(Name = "Confirm Password")]
    [DataType(DataType.Password)]
    [Required(AllowEmptyStrings = false, ErrorMessage = "Confirm password is required")]
    [Compare("userPassword", ErrorMessage = "Confirm password and password do not match")]
    public string userConfirmPassword { get; set; }

    public bool userStatus { get; set; }
    public bool userEmailVerificationStatus { get; set; }

    public System.Guid userActivationCode { get; set; }
}

I have spent the better part of 2 hours trying to figure this out.

Below are resources I have accessed trying to find a solution.

Any and all help is appreciated.

https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/advanced-entity-framework-scenarios-for-an-mvc-web-application

https://forums.asp.net/t/1991176.aspx?The+data+reader+is+incompatible+with+the+specified+model

Incompatible Data Reader Exception From EF Mapped Objects

The data reader is incompatible with the specified Entity Framework

https://forums.asp.net/t/1980259.aspx?I+get+this+error+The+data+reader+is+incompatible+with+the+specified+DBLaxmiTatkalModel+TblAttendence+A+member+of+the+type+AttendenceId+does+not+have+a+corresponding+column+in+the+data+reader+with+the+same+name+

What can cause an EntityCommandExecutionException in EntityCommandDefinition.ExecuteStoreCommands?

Adam Schneider
  • 275
  • 1
  • 5
  • 18
  • Possible duplicate of [Incompatible Data Reader Exception From EF Mapped Objects](https://stackoverflow.com/questions/14235783/incompatible-data-reader-exception-from-ef-mapped-objects) – Michael Freidgeim Dec 20 '18 at 02:03
  • This is almost a year old, what are you doing? – Adam Schneider Dec 20 '18 at 02:04
  • "Possible duplicate" is a way to clean-up - to close similar questions and keep one with the best answers. The date is not essential. See http://meta.stackexchange.com/questions/147643/should-i-vote-to-close-a-duplicate-question-even-though-its-much-newer-and-ha If you agree that it requires clarification please vote on http://meta.stackexchange.com/questions/281980/add-clarification-link-to-possible-duplicate-automated-comment . If you see multiple duplicates, you should choose one as canonical and vote to close others. – Michael Freidgeim Jan 19 '19 at 23:55

1 Answers1

6

Error says:

A member of the type, 'userID', does not have a corresponding column in the data reader with the same name.

That means results returned by your query do not match type of your entity (User). And indeed they do not - your query return single column userEmail, while type User has much more columns (including userID mentioned in error message). Why results should match type User? Because you are querying this entity by doing db.Users.SqlQuery.

Your query is also wrong (because '@1' is not parameter but literal string), but that doesn't matter, because you don't need to use raw sql query here anyway. Just do:

public static bool EmailExists(string Email)
{        
    using (var db = new Models.UserRegistrationPasswordsEntities1()) {
        return db.Users.Any(c => c.userEmail == Email);
    }       
}

If you want to issue arbitrary sql queries (though I should say once again that in this case there is absolutely no reason to do this) - use db.Database.SqlQuery:

using (var db = new Models.UserRegistrationPasswordsEntities1()) {
    var email = db.Database.SqlQuery<string>(
        "SELECT userEmail FROM Users WHERE userEmail = @email",
        new SqlParameter("email", Email))
    .FirstOrDefault();
    ...
}
Evk
  • 98,527
  • 8
  • 141
  • 191
  • sorry forgot to mention I rapped that in single quotes seeing if it was a quirk of Entity. I appreciate your response, but I would really like to do this with a parameterized query so I can have some security from Sql Injection. – Adam Schneider Apr 02 '18 at 05:50
  • 1
    @user3119737 Entity Framework queries are already parametrized. So query shown in my example is already sql-injection safe. – Evk Apr 02 '18 at 05:54
  • really? Not that I don't believe you, but do you have any supporting documentation on that? I just did a quick google search and came up with this https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/ef/security-considerations. It specifically states that Entity Queries are not safe from Sql Injection attacks and you should build queries with Parameters. – Adam Schneider Apr 02 '18 at 06:02
  • 1
    Well sure they are, who would have used Entity Framework at all if that were not the case? `db.Users.Any(c => c.userEmail == Email)` will be converted to parameterized query similar to yours (but better). – Evk Apr 02 '18 at 06:04
  • 1
    That article says about Entity SQL. That's different thing from what is shown in answer. Entity SQL is entity framework specific sql-like language which you almost never need to use in practice. – Evk Apr 02 '18 at 06:06
  • Like this? http://www.entityframeworktutorial.net/querying-with-edm.aspx . See below Linq Query Syntax. – Adam Schneider Apr 02 '18 at 06:12
  • 1
    That's not Entity SQL if you ask that. That's LINQ query, which is sql-injection-safe in entity framework (same as I use in my answer). – Evk Apr 02 '18 at 06:13
  • 2
    If you are still in doubt, do `db.Database.Log = Console.WriteLine` and observe queries generated by EF in console while you are making LINQ queries. – Evk Apr 02 '18 at 06:17
  • Punch me in the face. it was @1. :facepalm:. I will do what you said and look at the db.Database.log. Thank you very much. I spent so much time on such a stupid typo. – Adam Schneider Apr 02 '18 at 06:20