Проверьте, существует ли имя пользователя/пароль в нескольких таблицах

Я работаю над страницей входа. Я хотел бы проверить, существует ли имя пользователя и пароль в базе данных. У меня есть три таблицы базы данных: команды, организаторы, администраторы с полем имени пользователя и пароля в каждой таблице соответственно. Я реализую вход в трехуровневую архитектуру.

Я полагаю, что у меня проблема с приведенным ниже оператором SQL. Я протестировал свой sql-запрос с отличным/действительным именем пользователя и паролем команды. Запрос COUNT возвращает более одной строки, что неверно.

Это мои коды для уровня доступа к данным:

 public int getExistingAccount(string username, string password)
    {
        string queryStr = "SELECT COUNT(*) FROM Teams t,Organizers o,Admins a WHERE (t.teamUsername=@username AND t.teamPassword=@password) OR (o.organizerUsername=@username AND o.organizerPassword=@password) OR (a.adminUsername=@username AND a.adminPassword=@password)";

        SqlConnection conn = new SqlConnection(_connStr);
        SqlCommand cmd = new SqlCommand(queryStr, conn);
        cmd.Parameters.AddWithValue("@username", username);
        cmd.Parameters.AddWithValue("@password", password);

        int returnValue = 0;

        conn.Open();
        returnValue = (int)cmd.ExecuteScalar();

        conn.Close();
        return returnValue;

    }

Что касается кодов уровня бизнес-логики:

public string getAccount(string username, string password)
    {
        string returnMessage = "";

        if (username.Length == 0)
            returnMessage += "Username cannot empty</br>";

        if (password.Length == 0)
            returnMessage += "Password cannot be empty</br>";

        if (username.Equals(password))
        {
            returnMessage += "Duplicate value. Please try again</br>";
        }

        //Invoke validateInput() method to validate data
        if (returnMessage.Length == 0)
        {
            int noOfRows = 0;

            LogAccounts logInd = new LogAccounts();
            noOfRows = logInd.getExistingAccount(username, password);

            if (noOfRows > 0)
                returnMessage += "Account found";
            else
                returnMessage += "Invalid username/password.";
        }

        return returnMessage;
    }

person Enovyne    schedule 31.01.2015    source источник
comment
Что произойдет, если вы замените count(*) на *, вы получите ожидаемые строки или нет?   -  person jarlh    schedule 31.01.2015
comment
Нет. Он не возвращает ожидаемые строки   -  person Enovyne    schedule 31.01.2015
comment
SELECT COUNT(*) FROM ( SELECT t.teamUsername как имя пользователя FROM Teams t WHERE t.teamUsername=@username AND t.teamPassword=@password UNION SELECT o.organizerUsername как имя пользователя FROM Organizers o WHERE o.organizerUsername=@username AND o. OrganizerPassword=@password UNION SELECT a.adminUsername в качестве имени пользователя FROM Admins a WHERE a.adminUsername=@username AND a.adminPassword=@password )   -  person Khanh TO    schedule 31.01.2015
comment
Предоставьте некоторые образцы данных и ожидаемый результат. Вам действительно стоит подумать о редизайне. Вы должны использовать одну таблицу Users, где находятся все пользователи, а затем ссылаться на нее из таблиц Teams/Organizers/admin. Вы должны следовать соглашениям об именовании C# и использовать CamelCase, а не соглашение Java с более низким CamelCase.   -  person scheien    schedule 31.01.2015
comment
В качестве примечания вы должны хешировать и солить пароли, хранящиеся в БД, используя надежный алгоритм, такой как bcrypt< /а>.   -  person SilverlightFox    schedule 01.02.2015


Ответы (3)


Ваш дизайн действительно плохой, вы должны иметь всех пользователей в одной таблице. После этого, если вы хотите взять пользователя по идентификатору, вы должны проверить 3 таблицы различий. В любом случае проблема в запросе, вы должны написать его так:

string queryStr = @"
SELECT 
    COUNT(*) AS TeamsCount,
    (SELECT COUNT(*) Organizers WHERE organizerUsername=@username AND organizerPassword=@password) AS OrgCount,
    (SELECT Count(*) Admins WHERE adminUsername=@username AND adminPassword=@password) AS AdminCount
FROM 
   Teams 
WHERE 
   teamUsername=@username AND 
   teamPassword=@password";

Запрос должен выглядеть примерно так. После этого вам нужно вернуть это в DataSet. Тебе нужно:

DataSet dst = new DataSet();
using(SqlAdapter adapter = new SqlAdapter(cmd))
{
    adapter.Fill(dst);
}

В этом случае у вас будет dst с 3 столбцами. Проверка существующего пользователя должна быть:

if(dst.Tables[0].Rows[0]["TeamsCount"] > 0 || 
     dst.Tables[0].Rows[0]["OrgCount"] > 0 ||
     dst.Tables[0].Rows[0]["AdminCount"] > 0)
{
    //user already exist !
}
person mybirthname    schedule 31.01.2015

Попробуйте это, выберите из каждой таблицы и ОБЪЕДИНИТЕ ВСЕ результаты, затем подсчитайте строки.

select count(*) from
(
SELECT 1 as dummyname FROM Teams t
WHERE (t.teamUsername=@username AND t.teamPassword=@password)
union all
SELECT 1 FROM Organizers o
WHERE (o.organizerUsername=@username AND o.organizerPassword=@password)
UNION ALL
select 1 from Admnis
WHERE (a.adminUsername=@username AND a.adminPassword=@password)
)
person jarlh    schedule 31.01.2015

Мне кажется, у вас действительно неудобный дизайн базы данных, где для получения одного пользователя требуется неестественно большой/длинный sql-запрос.

Почти в каждом случае использования у вас будет одна таблица пользователей, и если вам нужно связать пользователя с некоторой дополнительной информацией, у вас будет ссылка на пользовательскую таблицу с помощью UserId. Вы также должны прочитать о внешних ключах.

Быстрый образец:

Users:

- UserId (int or guid) (primary key)

- .... (additional fields removed for brewity)

Другие таблицы будут ссылаться на столбец UserId и использовать его для извлечения информации о пользователе с присоединением.

E.g.: SELECT T.*, U.* FROM Teams T INNER JOIN Users U ON U.UserId = T.UserId WHERE U.Username = "AwesomeCoach";

Простой запрос на проверку будет выглядеть примерно так:

SELECT COUNT(*) FROM Users WHERE Username = xx AND Password = xx

Это вернет integer, указывающее, сколько строк соответствует заданной комбинации имени пользователя и пароля. Это должно быть либо 1, либо 0. Поместите ограничение Unique в столбец Username, чтобы убедиться, что каждое Username встречается только один раз.

Сноска: Я вижу, что у вас есть ответ, решающий проблему, с которой вы столкнулись, но я бы порекомендовал вам ознакомиться с проектом базы данных и постараться сделать его максимально простым. Управление несколькими пользователями в нескольких таблицах может и будет создавать проблемы по мере роста приложения.

person scheien    schedule 31.01.2015