Comparing Sql Table Data on Visual - c#

I am making a basic patient record system on visual studio (windows form application, c#).
When a user tries to insert the same firstname and surname, the application should give an error like:
You can't insert the same name twice.
I just don't know how to get data directly from sql on visual . Can anyone help ?

Make Firstname and lastname as primerykey combine in your db table, that will not allow duplicate... but making names as primary key is not good practice because may two patients have same first and last names

I hope this code helps.
I have assumed that you are using Entity Framework
var newPatient = ...;
if
(
Context.Patients.Count
(
x=>
x.Name==newPatient.Name &&
x.Family==newPatient.Family
) > 0
)
MessageBox.Show("This is an existing patient");
Edit (Based on your comment):
var newPatient= new Patient();
newPatient.Name = textBox1.Text;
newPatient.Family = textBox2.Text;
if
(
Ort.Grid.Count
(
x=>
x.Name==newPatient.Name &&
x.Family==newPatient.Family
) > 0
)
MessageBox.Show("This is an existing patient");

Related

How to make sql query more dynamic in ASP.NET

I have a webpage and a gridview connected to a database table. My update queries of the columns are as followed:
if (oldName != NAME && oldCreated == DATE)
{
GeneralDbExecuterService.executeSqlNonQuery(string.Format("UPDATE EXCEPTIONAL_USE_POLICY_PARAM SET NAME = '{0}' WHERE ID = '{1}' ", NAME, ID));
}
// if date was changed alone
if (oldCreated != DATE && oldName == NAME)
{
GeneralDbExecuterService.executeSqlNonQuery(string.Format("UPDATE EXCEPTIONAL_USE_POLICY_PARAM SET CREATED_DATE = to_date('{0}', 'dd/MM/yyyy') WHERE ID = '{1}' ", DATE, ID));
}
// if both values were changed
if (oldName != NAME && oldCreated != DATE)
{
GeneralDbExecuterService.executeSqlNonQuery(string.Format("UPDATE EXCEPTIONAL_USE_POLICY_PARAM SET NAME = '{0}', CREATED_DATE = to_date('{2}', 'dd/MM/yyyy') WHERE ID = '{1}' ", NAME, ID, DATE));
}
My question is, how can I make it more modular?
For example if 2 more columns are added its going to raise my IFs by few if not dozens. What is the best way to achieve that kind of dynamic approach? And is that even possible?. Thanks
edit: my main goal is to be able to detect what/where change has happened, and query the specific columns/values . ( basically its what I did) im just asking if theres a better way because if I were to add 5 more columns, I'd end up adding 40 more if statements..
If you use Entity Framework, rather than raw SQL, then you won't need to have any if statements at all. Your method would take an entity, and your code would just get the existing entity out of the database, and set the properties from the incoming one, irrespective of whether or not they have changed (air code, assumptions made about how you set up your model, etc)...
private async Task Update(PolicyParam p) {
PolicyParam existing = await dbContext.PolicyParams.Single(pp => pp.Id == p.Id);
existing.Date = p.Date;
existing.Name = p.Name;
// Update other properties here
await dbContext.SaveChangesAsync();
}
If you add another column, you just add one more line of code above.
EF has a zillion other benefits, like cleaner code, less chance of SQL injection, etc.

Cleanest way to check if table exists - MySQL

Working with C# and MySQL here (Visual Studio 12 and MySQL workbench 6.1).
This is what I have so far.
string strCheck = "SHOW TABLES LIKE \'emp\'";
MySqlCommand cmd = new MySqlCommand(strCheck, con);
cmd.Prepare();
if (cmd.ExecuteNonQuery() > 0)
{
Console.WriteLine("exists");
}
else
{
Console.WriteLine("does not");
}
I have seen many questions here (mostly related to PHP) but they don't seem to be working for me. Also, I don't want a solution where we check if the table has any rows, because the table can be empty, and what I want to know is whether it exists.
Thanks.
Try the following SELECT statement:
SELECT EXISTS(
SELECT
`TABLE_NAME`
FROM
`INFORMATION_SCHEMA`.`TABLES`
WHERE
(`TABLE_NAME` = 'emp')
AND
(`TABLE_SCHEMA` = 'mydb')
) as `is-exists`;

SQL Query to Find relevant items

We have a system that uses Electronic Forms but the standard searching functionality of the forms is very sub par, so I have been tasked with trying to create a better approach for the users.
Ok so a little background of the current database format :
Table1
------
FormID
FormName
Creator
CreateDate
Table2
------
FormID
FormControlName
ControlData
The relationship is a 1 to Many with there being many controls on one form.
My task is to create a search that will find the relevant forms by searching the form name (changes based on data) and each of the form Controls that belong to that form.
I have managed to do this using C# coding but because there is a high number of records in the Database, and the fact that in my Current solution I am retrieving everything and iterating over it to find the relevant items, it is quite a slow solution.
My Code :
private DataTable GetForms() {
string FormName = ddForm.SelectedValue;
string SearchText = tbSearch.Text;
List<string> FormIDs = GetMatchingForms(FormName, SearchText);
DataTable dtForms = new DataTable("Forms Table");
dtForms.Columns.Add("Form Name");
dtForms.Columns.Add("Initiator");
dtForms.Columns.Add("Start Date").DataType = typeof(DateTime);
dtForms.Columns.Add("FormLink");
foreach (string FormID in FormIDs) {
DataRow nRow = dtForms.NewRow();
nRow[0] = GetData.GetString("SELECT [FormName] FROM [Table1] Where [FormID] = '" + FormID + "'", conString);
string UserID = GetData.GetString("SELECT [Creator] FROM [Table1] Where [FormID] = '" + FormID + "'", conString);
string UserName = GetData.GetString("Select [UserName] From [User] Where [UserID] = '" + UserID + "'", conString);
nRow[1] = UserName;
nRow[2] = GetData.GetString("SELECT [CreateDate] FROM [Table1] Where [FormID] = '" + FormID + "'", conString);
nRow[3] = "~/Form.aspx?formid=" + FormID;
dtForms.Rows.Add(nRow);
}
return dtForms;
}
private List<string> GetMatchingForms(string FormName, string SearchText) {
//FormName can be = % to search all forms
DataTable dtForms = GetData.GetDT("SELECT * FROM [Table1] Where [FormName] LIKE '%" + FormName + "%'", conString);
List<string> FormList = new List<string>();
foreach (DataRow row in dtForms.Rows) {
string FormName = row["FormName"].ToString();
string FormID = row["FormID"].ToString();
bool Relevant = false;
if (FormName.Contains(SearchText)) {
Relevant = true;
} else {
DataTable dtFormControls = GetData.GetDT("SELECT * FROM [Table2] Where [FormID] = '" + FormID + "'", conString);
foreach (DataRow cRow in dtFormControls.Rows) {
string ControlData = cRow["ControlData"].ToString();
if (ControlData.Contains(SearchText)) {
Relevant = true;
break;
}
}
}
if (Relevant) {
FormList.Add(FormID);
}
}
return FormList;
}
I was wondering if it would be possible to replicate the above code's functionality into a SQL Query (or a small number of queries) to hopefully try and speed up the current solution. My current knowledge of SQL Queries is not the best and I can't even begin to think of where to start with this issue.
To clarify, we currently have 300,000 forms and a total of 10.4 million data records, the database has been re indexed recently and that does seem to effect performance positively. We are planning on doing maintenance on this relatively soon but we will still be keeping the bulk of the data that is currently stored.
Edit : The Database in question is part of 3rd party software and we are limited to Read-Only access, database modifications are no possible for us.
As you can see from the number of records that the timing issue is quite a big one, as it literally takes minutes to execute the current code.
Any help will be greatly appreciated thanks.
The performance problems are because you are running four queries (3 againsts Table1 and 1 against User) for each string in your list, which is a big overhead. I'd recommend one of the following (please bear in mind I don't have access to your database, so sorry for any coding errors)
1) Use LinqToSql
If you use LinqToSql then you can extract the data from the first part of your query with something similar to the following:
var myResults = (from t in context.Table1
join u in context.User on t.UserId equals u.UserId
where formIds.Contains (t.FormId)
select new { t.FormName, t.Creator, t.CreateDate }).ToList();
The Contains method allows you to effectively join your in memory data with data from the database, removing the need to loop for each item.
2) Use Database query
The equivalent SQL statement would be:
select t.FormName, t.Creator, t.CreateDate
from Table1 t
inner join [User] u on t.UserID = u.UserId
where t.FormId in (<list of formIDs here>)
You could either create a SQL command, building this string which is not recommended because of SQL Injection concerns or alternatively you could create a parameterised query or a stored procedure which is far better from a security perspective.
All of the above only applies to the first part of your code, but can easily be replicated for the 2nd part.
A 1 to N relationship can be easily created in TSQL. The sample program below adds primary keys for both the form id and control id with a foreign key relationship.
This will return the data you want in one record set versus multiple calls you are making before.
The next question is what type of data is the control data? That is where you might be having the issues.
If it is defined as a varchar(max) or text, then you have to perform a full table scan. You can not use a regular index < 900 bytes.
A index or balanced tree search is a N LOG(N) operation at worst versus a table search which is a N operation. This is analysis of algorithms, order of magnitude, http://en.wikipedia.org/wiki/Big_O_notation, O(N LOG(N)) versus O(N).
With N = 11 M, you only have to look at 1.04 M rows max. This is assuming a binary tree. SQL server uses B+tree. http://sqlity.net/en/563/index-misconceptions-tsql-tuesday-026-second-chances/
If the control data field is text, you want to apply full text indexing. Look at my blog articles http://craftydba.com/?p=1421 and/or presentation on how to set one up. You will have to use the CONTAINS() or FREETEXT() functions for searching.
This index can be built right after a data load but provides you with superior speed versus a traditional LIKE clause. This pushes the search load (computation) onto the SQL server instead of the client (web server).
I hope this helps you out,
If you have any more questions, just ask.
Sincerely
John
--
-- Sample table 1
--
create table tempdb.dbo.forms
(
FormID int identity(1,1) primary key clustered,
FormName varchar(32),
Creator varchar(32) DEFAULT (coalesce(suser_sname(),'?')),
CreateDate smalldatetime DEFAULT (getdate())
);
go
-- Add data
insert into tempdb.dbo.forms (FormName) values ('Main');
go
-- Show the data
select * from tempdb.dbo.forms;
go
--
-- Sample table 2
--
create table tempdb.dbo.controls
(
ControlId int identity(1,1) primary key clustered,
FormID int,
FormControlName varchar(32),
ControlData varchar(32)
);
go
-- Add foreign key 2 forms table
ALTER TABLE tempdb.dbo.controls WITH CHECK
ADD CONSTRAINT fk_tbl_forms FOREIGN KEY(FormId)
REFERENCES tempdb.dbo.forms (FormID)
go
-- Add data
insert into tempdb.dbo.controls (FormId, FormControlName, ControlData)
values
(1, 'Drop Down', 'My drop down data'),
(1, 'Text Box', 'My text box');
go
-- Show the data
select * from tempdb.dbo.controls;
go
--
-- Use a join command (1 x N) relationship with where
--
-- Show data from both
select
f.FormID,
f.FormName,
f.Creator,
f.CreateDate,
c.ControlId,
c.FormControlName,
c.ControlData
from
tempdb.dbo.forms as f inner join
tempdb.dbo.controls as c
on
f.FormID = c.FormID
where
f.FormName like '%Main%' and
c.ControlData like '%box%'
go

If condition with Entity Framework

In my asp.net application I have two pages like new students and edit students. On the new student page I am passing general details like first name, last name, mobile number, email and register number.
Here RegNo should be unique. I am using Entity Framework for database connection. I'm checking with the condition to avoid the same RegNo being entered, like:
DataObject.Entities dataEntities = new DataObject.Entities();
if (!dataEntities.Students.Any(s => s.RegNo == RegNo))
{
// my code here.
}
The same way for edit option, when try to change the RegNo. If it is allotted to some other student, it should not go into the update code.
I know if I use the same condition here, it will fail, because the RegNo is there in the database for this student (the one am trying to update), so if the RegNo is allotted for this particular student and not for other students it should be accepted, otherwise should go to else part.
I don't know how to check this using Entity Framework. Can anyone help me,please?
I've a column StudentId, it's an autoincrement column
I tried like
if (!dataEntities.Students.Any(s => s.RegNo == RegNo && s.StudentId != StudentId))
{
}
still it's not working.....
if(!dataEntities.Students.Any(s=>s.RegNo == RegNo && s != studentBeingUpdated))
Replace studentBeingUpdated with a variable containing a reference to the student that you are currently updating.
you can set in database level.. ie if you set auto increment then you dont need to edit/ reassign id to someone else and there is no need for separate management for this.
Please tell me if i understood mistakenly. :)
I just declared an object for the student table and tried like,
DataObject.Student student = dataEntities.Students.First(s => s.StudentId ==
StudentId);
if (!dataEntities.Students.Any(s => s.RegNo == RegNo &&
s.StudentId != student.StudentId))
{
}
else
{
throw new exception("RegNo already exists!");
}
and its working for me

combining values from two sql query result rows into one for a datagrid in c#

I have a employee table which contains employee information and a Contact details table which contains the phone numbers of the employees. the employees have more than 2 phone numbers.
now, to display the employee information, i have a datagrid. what i want to do is display the first 2 numbers along with the employee information in the datagrid.
i use the following method to fill the data grid
public static void SignUpControllerDay(DateTime Date, System.Windows.Forms.DataGridView PassedGrid)
{
string sql_SignUp = String.Format(#"SELECT e.Emp_ID as Emp_ID,
e.First_Name+ ' ' +e.Last_Name as Name,
sum(o.Quantity) as Sum
FROM Employee e,OT_hours o,Position p,Signup_Sheet s
WHERE e.Emp_ID=o.Emp_ID
and e.Emp_ID = s.Employee_ID
and s.Day_Shift = 1
and e.Position_ID = p.Position_ID
and p.Position_Name = 'Controller'
and o.Quantity NOT IN(0.3)
and s.Date = '{0}'
and o.Date <= CONVERT(VARCHAR,'{0}',101) AND o.Date > CONVERT(VARCHAR,DATEADD(YYYY,-1,'{0}'),101)
GROUP BY e.Emp_ID,e.First_Name+' '+e.Last_Name,p.Position_Name
ORDER BY Sum", Date);
SqlConnection sqlConn = null;
SqlCommand cmd_SignUp;
SqlDataReader dr_SignUp;
try
{
sqlConn = new SqlConnection(databaseConnectionString);
sqlConn.Open();
cmd_SignUp = new SqlCommand(sql_SignUp, sqlConn);
dr_SignUp = cmd_SignUp.ExecuteReader();
while (dr_SignUp.Read())
{
PassedGrid.Rows.Add(dr_SignUp["Emp_ID"].ToString(), dr_SignUp["Name"].ToString(), dr_SignUp["Sum"].ToString());
}
}
catch (Exception e)
{
MessageBox.Show("Error found in SignUpControllerDay..." + Environment.NewLine + e.ToString());
}
finally
{
if (sqlConn != null)
{
sqlConn.Close();
}
}
}
the above method displays the empid,name,sum of the employees. all i want to do is display any 2 phone numbers from the contact_details table. i tried using a data reader to get the phone numbers based on the employee id, but it did not work.
please help....
I think I know what reggie wants to do but before I give you any help reggie lets take a look at a couple of things that you may want to look at:
As mentioned do not use String.Format or Dynamic SQL, if you are on SQL Server make use of stored procedures with parameterized SQL Command objects
You are having the client (web app or windows app) doing too much work for something that is really data intensive (SQL work rather then C# work)
You do not need to loop at all or even use a datareader as it is just bloating your code and unnecessary
In your finally clause you close the connection but you never set your connection or the actual sql command object to null. I know C# garbage collects but it is a good point of practice to do so.
SQL Server 2005 and up brings to us the PIVOT key word, look it up in BOL
In regards to your question if you are using SQL Server 2005+ you can use PIVOT. Given that you mentioned there can be 2 contact numbers let us assume one is work and one is home.
You could do this:
SELECT
FullName,
[Work],
[Home]
FROM
(SELECT
l.FullName,
p.PhoneType,
p.PhoneNumber
FROM
Login l
INNER JOIN
Phone p
ON p.LoginID = l.LoginID) ps
PIVOT
(
MAX(ps.PhoneNumber)
FOR
ps.PhoneType IN ([Home], [Work])
) AS pvt
Login is simply your Employees table and Phone is your contacts table with the phone number. I assume an employee id can be found in the contacts table (that is Login.LoginID = Phone.LoginID) or in your case Employee.EmpID=Contacts.EmpID.
So this:
alt text http://img513.imageshack.us/img513/6126/onetime.jpg
With a standard query not using pivot then becomes this...:
alt text http://img513.imageshack.us/img513/7395/2time.jpg
When using pivot.
You don't reference the contact_details table anywhere in the SQL. You need to join the Employee and contact_details tables to include the phone numbers.

Categories