I have ASP.Net MVC 5 Web API project.
I cant use asp.net web API 2 web service in android
my web service is under mvc5, Then I have created mobile app in Eclipse Juno and i use Android sdk 21
below is my edited code
namespace AppServices.Models
{
public class AdvertisingRepository
{
private List<Advertising> Advertising = new List<Advertising>();
private int _nextId = 1;
public AdvertisingRepository()
{
}
public List<Advertising> GetAll()
{
Advertising.Clear();
SqlDataReader reader = null;
SqlConnection myConnection = new SqlConnection();
myConnection.ConnectionString = #"Server=.;Database=AppServices;User ID=sa;Password=123;";
SqlCommand sqlCmd = new SqlCommand();
sqlCmd.CommandType = CommandType.Text;
sqlCmd.CommandText = "SELECT * FROM tblAdvertising";
sqlCmd.Connection = myConnection;
myConnection.Open();
reader = sqlCmd.ExecuteReader();
Advertising emp = null;
while (reader.Read())
{
emp = new Advertising();
emp.Id = Convert.ToInt32(reader.GetValue(0));
emp.SearchString = reader.GetValue(1).ToString();
emp.OstanID = Convert.ToInt32(reader.GetValue(2));
emp.AdsGroupID = Convert.ToInt32(reader.GetValue(3));
Advertising.Add(emp);
}
myConnection.Close();
return Advertising;
}
public Advertising Get(int id)
{
Advertising.Clear();
SqlDataReader reader = null;
SqlConnection myConnection = new SqlConnection();
myConnection.ConnectionString = #"Server=.;Database=AppServices;User ID=sa;Password=123;";
SqlCommand sqlCmd = new SqlCommand();
sqlCmd.CommandType = CommandType.Text;
sqlCmd.CommandText = "SELECT * FROM tblAdvertising WHERE Id=" + id + "";
sqlCmd.Connection = myConnection;
myConnection.Open();
reader = sqlCmd.ExecuteReader();
Advertising emp = null;
while (reader.Read())
{
emp = new Advertising();
emp.Id = Convert.ToInt32(reader.GetValue(0));
emp.SearchString = reader.GetValue(1).ToString();
emp.OstanID = Convert.ToInt32(reader.GetValue(2));
emp.AdsGroupID = Convert.ToInt32(reader.GetValue(3));
Advertising.Add(emp);
}
myConnection.Close();
return Advertising.Find(p => p.Id == id);
}
public Advertising Add(Advertising item)
{
SqlConnection myConnection = new SqlConnection();
myConnection.ConnectionString = #"Server=.;Database=AppServices;User ID=sa;Password=123;";
SqlCommand sqlCmd = new SqlCommand();
sqlCmd.CommandType = CommandType.Text;
sqlCmd.CommandText = "INSERT INTO tblAdvertising (SearchString, OstanID, AdsGroupID) VALUES (#SearchString, #OstanID, #AdsGroupID)";
sqlCmd.Connection = myConnection;
sqlCmd.Parameters.AddWithValue("#SearchString", item.SearchString);
sqlCmd.Parameters.AddWithValue("#OstanID", item.OstanID);
sqlCmd.Parameters.AddWithValue("#AdsGroupID", item.AdsGroupID);
myConnection.Open();
int rowInserted = sqlCmd.ExecuteNonQuery();
// Get new record id
sqlCmd.CommandText = "SELECT TOP (1) Id FROM tblAdvertising ORDER BY Id DESC";
if (sqlCmd.ExecuteScalar() != DBNull.Value)
_nextId = (int)sqlCmd.ExecuteScalar();
////////////////////
myConnection.Close();
// old code
if (item == null)
{
throw new ArgumentNullException("item");
}
item.Id = _nextId;
Advertising.Add(item);
return item;
}
public void Remove(int id)
{
Advertising.RemoveAll(p => p.Id == id);
}
public bool Update(Advertising item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
int index = Advertising.FindIndex(p => p.Id == item.Id);
if (index == -1)
{
return false;
}
Advertising.RemoveAt(index);
Advertising.Add(item);
return true;
}
}
}
I have ASP.Net MVC 5 Web API project. I cant use asp.net web API 2 web service in android my web service is under mvc5, Then I have created mobile app in Eclipse Juno and i use Android sdk 21 below is my edited code
There are many issues.
It starts with what looks a little careless "SELECT * FROM tblAdvertising"
That is three sins against the rules of SQL.
First there is no table called tblAdvertising. There is one called dbo.tblAdvertising. So lacking the real name SQL assumes that you mean dbo, but that might be something else as well. This will dump your performance. Best always use fully qualified names.
The second issue is that you use * as items to select. I have been a long in SQL development and can tell from own experience how often tables are changed. The person doing so might not even be aware of your application so a simple add will cause your code to break. Always use fully qualified SQL column names as well.
The final issue with your SQL is that you use a command and yet poke in text strings, even those that are unprotected against SQL injection. What if someone adds this as string "'',0,0; truncate table tblAdvertising; --". You might be surprised how often, certainly in the past i could log in websites simply with some variation of "'' or 1=1 --". Best avoid unprotected strings that go to MSSQL or MySQL or any SQL for that matter. Also your SQLstring needs to be compiled taking a further performance hit. There is also no protection against wrong parameters or proper feedback if the result does not exist.
Besides you really do not want to select an entire table. There should be like a top 100 or you could implement some paging.
So the solution is that you use a proper stored procedure, check the parameter input and provide limited and properly formatted output.
Also your
INSERT INTO tblAdvertising (SearchString, OstanID, AdsGroupID) VALUES (#SearchString, #OstanID, #AdsGroupID)
can be much improved.
If you update or insert there is an output statement in SQL that is massive faster than querying the max number
create type dbo.IntTable as table(i int)
go
create proc dbo.AdvertisementInsert
#SearchString varchar
, #OstanID int
, #AdsGroupID int
, #NewID int = 0 output
as
set nocount on -- important to avoid second roundtrip over the network
declare #i as dbo.IntTable -- use predefined table variable
-- always check quality of input first
if #SearchString is null return 50001
-- also avoid rollback transaction since that is costly.
-- Better to ask first if this not already exist
if exists(select 42 from dbo.tblAdvertising where SearchString = #SearchString) return 50002
INSERT INTO tblAdvertising (SearchString, OstanID, AdsGroupID)
output inserted.Id into #i -- catch new id directly into table variable
VALUES (#SearchString, #OstanID, #AdsGroupID)
-- report the result
select #NewID = i from #i -- convert table variable to single int
go
So now your proc can be called just using the parameters and will tell you back either 0 .. in which case the result code will tell you why it failed, or some other number matching the new identity
Enjoy
Related
The project I am working is 'University Management System' and it's a big one. Right now, I am implementing the student registration section that works fine (A small portion of the project). I've used 'Three-Tier Architecture' and 'ORM - EF' in ASP.NET MVC template. In the project, I need to do some validations for registering students depending upon their year, department etc. So there are sections like DAL, BLL, finally controller and view. I've done the validations in the controller and getting the data from BLL that again retrieves data from DAL (This is the simple condition of 'Three-Tier Architecture'). So my questions are:
1) Is it OK to do the validations in the controller?
2) If not and need to do it in the BLL, will it be just fine and why or I can
continue doing it in the controller?
Note: To me, doing the validations in the controller or BLL seems OK and the same. Does it have any effect?
Right now, I've done the following:
DAL:
public List<Student> Add(int studentID, string studentName, string email, DateTime regDate)
{
List<Student> lst = null;
Student aStudent = new Student();
aStudent.StudentID = studentID;
aStudent.StudentName = studentName;
aStudent.Email = email;
aStudent.RegDate = regDate;
try
{
db.Students.Add(aStudent);
db.SaveChanges();
}
catch (Exception ex)
{
ex.ToString();
}
return lst;
}
BLL:
public List<Student> Add(int studentID, string studentName, string email, DateTime regDate)
{
return aStudentGateway.Add(studentID, studentName, email, regDate);
}
Controller:
/**Student Registration - Starts**/
[HttpPost]
public ActionResult AddStudent(Student aStudent)
{
List<Department> departments = aDepartmentManager.GetAllDepartments();
List<DepartmentViewModel> departmentsViewModel = aDepartmentManager.GetAllDepartmentViewModel();
DateTime yearInDateTime = Convert.ToDateTime(Request.Form["RegDate"]);
string extractYear = yearInDateTime.ToString();
var year = DateTime.Parse(extractYear).Year;
int department = Convert.ToInt32(Request.Form["Department"]);
List<Student> studentList = aStudentManager.GetAllStudents();
int count = 1;
var query = (from c in studentList
where c.Department == department && c.Year == year
select c).ToList();
foreach (var c in query)
{
if (query.Count() > 0)
{
int m = Convert.ToInt32(c.StudentID);
count = m + 1; //Incrementing the numbers by one with the table column
}
else
{
int m = 1;
count = m + 1; //Incrementing the numbers by one with the variable assigned one
}
}
Student student = new Student();
student.StudentName = Request.Form["StudentName"];
student.Email = Request.Form["Email"];
student.RegDate = Convert.ToDateTime(Request.Form["RegDate"]);
student.StudentID = count;
if (aStudentManager.ExistEmailAny(student.Email))
{
ViewBag.ErrorMessage = "Email already exists";
}
else
{
aStudentManager.Add(aStudent.StudentID, aStudent.StudentName, aStudent.Email, aStudent.RegDate);
ViewBag.Message = "Registration successful. See below to verify.";
/**This section used to show student details after registration**/
var result = (from c in departments
join d in departmentsViewModel on c.DepartmentID equals d.DepartmentId
where d.DepartmentId == department
select c);
foreach (var items in result)
{
if (count.ToString().Length > 1)
{
ViewBag.StudentID = items.Code + "-" + year + "-" + "0" + count;
}
else
{
ViewBag.StudentID = items.Code + "-" + year + "-" + "00" + count;
}
StudentViewModel.StudentID = student.StudentID;
StudentViewModel.StudentName = student.StudentName;
StudentViewModel.Email = student.Email;
StudentViewModel.RegDate = student.RegDate;
}
/**This section used to show student details after registration**/
}
return View();
}
/**Student Registration - Ends**/
I would provide multiple steps of validation in the different layers, depending on the context and the meaning of the layer.
First, it's a best practice to provide validation both on client and server side.
For the client side you should provide field checks for required fields and other simple validations. If you are using MVC you can use data annotations.
The same validation should be replicated in the controller. Here you should fail fast applying some kind of contract to the parameters that have been passed. One good practice is using Code Contracts that provide preconditions that need to be satisfied to go on in your pipeline of execution.
In the business layer provide the check that needs to be done in the business logic.
Finally in the data access layer provide all the checks that are needed to persist your data. If you are using EF a good practice is implementing the IValidatableObject for your entity classes. Here in Scott Gu's blog you can find a post that explains this technique.
Even though this approach look like it will introduce repetitions, it will provide consistency in your data and separate concerns between your layers.
1) Is it OK to do the validations in the controller?
No at all, it would be more better to use Data Annotation Validator Attributes, and to do validation in your model class.
Second thing, you're doing some stuff of DAL in your controller, like
List<Department> departments = aDepartmentManager.GetAllDepartments();
List<DepartmentViewModel> departmentsViewModel = aDepartmentManager.GetAllDepartmentViewModel();
var query = (from c in studentList
where c.Department == department && c.Year == year
select c).ToList();
These all queries should be in DAL, which is exact use of DAL to interact with the database, and keep your controller clean.
Third thing,
If you pass Student to the controller, then not need to get each attribute using Request.Form.
Hope this make sense!
I have the following linq query
internal List<ZipCodeInfo> GetInfoFromZipCode(string zipCode)
{
using (DbContext context = new DbContext())
{
IQueryable<ZipCodeInfo> results;
results = (from a in context.Address
where a.ZipCode.Equals(zipCode)
select new ZipCodeInfo
{
Field1 = a.Field1,
Field2 = a.Field2,
Field3 = a.Field3
});
return results.ToList();
}
}
But the query itself takes around 5-6 seconds to be completed. I've executed the counterpart query on SQL and it takes almost nothing to complete. Why is it taking that long? The query at the end just returns 4 matches so there is not that much to do here..
This query is part of a Controller class and I am using ASP.NET Core and EntityFramework Core.
The SQL query looks like this, btw.
SELECT *
FROM Address
WHERE ZipCode = '29130'
You can rewrite above query as shown below.Please let us know about the performance now.
internal List<ZipCodeInfo> GetInfoFromZipCode(string zipCode)
{
using (DbContext context = new DbContext())
{
//disabled tracking
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
IQueryable<ZipCodeInfo> results;
results = (from a in context.Address
where a.ZipCode.Equals(zipCode)
select new ZipCodeInfo
{
Field1 = a.Field1,
Field2 = a.Field2,
Field3 = a.Field3
});
return results.ToList();
}
}
I don't know what version of .Net and entity frameworks are you using, but I found an interesting article here on MSDN. You can go through it. But code can be used as below:
static readonly Func<DbEntities, IQueryable<ZipCodeInfo>> s_compiledQuery2 =
CompiledQuery.Compile<DbEntities, IQueryable<ZipCodeInfo>>(
(ctx, total) => from a in context.Address
where a != null and a != ""
a.ZipCode.ToUpper().Equals(zipCode.ToUpper())
select new ZipCodeInfo
{
Field1 = a.Field1,
Field2 = a.Field2,
Field3 = a.Field3
});
internal List<ZipCodeInfo> GetInfoFromZipCode(string zipCode)
{
using (DbEntities context = new DbEntities())
{
IQueryable<ZipCodeInfo> zipCodes = s_compiledQuery2.Invoke(context, zipCode);
return zipCodes.ToList();
}
}
At this point I don't have any remote database to test but again delay to fetch the result of these kind of query will also depends on N\W and number of records being fetched. You can try this solution.
i wonder how to implement M-V-C ADO without using EF.
just like a pure ADO implementation. any suggestions and sample are appreciated Thanks guys.
Basic ADO.NET connections haven't really changed at all with MVC coming around. They still rely on things like SqlConnection objects and their associated commands.
If you wanted to build a simply query, it might look like the following :
// Build your connection
using(var connection = new SqlConnection("{your-connection-string-here"}))
{
// Build your query
var query = "SELECT * FROM YourTable WHERE foo = #bar";
// Create a command to execute your query
using(var command = new SqlCommand(query,connection))
{
// Open the connection
connection.Open();
// Add any parameters if necessary
command.Parameters.AddWithValue("#bar", 42);
// Execute your query here (in this case using a data reader)
using(var reader = command.ExecuteReader())
{
// Iterate through your results
while(reader.Read())
{
// The current reader object will contain each row here, so you
// can access the values as expected
}
}
}
}
You can use the type of ADO commands and paramaterized SQL seen here to retrieve data:
conn.Open();
cmd.CommandText = "SELECT id, desc FROM mytable WHERE id = #id";
cmd.Parameters.AddWithValue("#id", myid);
using (var reader = cmd.ExecuteReader())
{
if (!reader.Read())
{
return null;
}
return new myItem
{
Id = reader.GetInt32(reader.GetOrdinal("id")),
Desc = reader.GetString(reader.GetOrdinal("desc")),
}
}
There are lot of examples on MSDN for CRUD.
The model of my project is database first, and uses remote access to database on another server.
I need to use raw SQL query because my query is very complex and I feel more comfortable in SQl not LINQ.
This is how I do:
string query = "select * from Inquiry_TBL where ...";
using (educationEntities db = new educationEntities())
{
var list = db.Database.SqlQuery<Inquiry_TBL>(query);
ViewData["total"] = list.Count();
}
The problem is sometimes I get the query result within a second, sometimes it just keep loading for a long time and gives me an error that 'Calling 'Read' when the data reader is closed is not a valid operation.'
Why is that? Is there something wrong with my code, or because I'm using remote access to another server? Will switching to local server solve the problem?
The Entity Framework Code First API includes methods that enable you to pass SQL commands directly to the database. You have the following options:
• Use the DbSet.SqlQuery method for queries that return entity types. The returned objects must be of the type expected by the DbSet object, and they are automatically tracked by the database context unless you turn tracking off. (See the following section about the AsNoTracking method.)
• Use the Database.SqlQuery method for queries that return types that aren't entities. The returned data isn't tracked by the database context, even if you use this method to retrieve entity types.
• Use the Database.ExecuteSqlCommand for non-query commands.
Calling a Query that Returns Entities:
public async Task<ActionResult> Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
// Commenting out original code to show how to use a raw SQL query.
//Department department = await db.Departments.FindAsync(id);
// Create and execute raw SQL query.
string query = "SELECT * FROM Department WHERE DepartmentID = #p0";
Department department = await db.Departments.SqlQuery(query, id).SingleOrDefaultAsync();
if (department == null)
{
return HttpNotFound();
}
return View(department);
}
Calling a Query that Returns Other Types of Objects:
public ActionResult About()
{
//Commenting out LINQ to show how to do the same thing in SQL.
//IQueryable<EnrollmentDateGroup> = from student in db.Students
// group student by student.EnrollmentDate into dateGroup
// select new EnrollmentDateGroup()
// {
// EnrollmentDate = dateGroup.Key,
// StudentCount = dateGroup.Count()
// };
// SQL version of the above LINQ code.
string query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
+ "FROM Person "
+ "WHERE Discriminator = 'Student' "
+ "GROUP BY EnrollmentDate";
IEnumerable<EnrollmentDateGroup> data = db.Database.SqlQuery<EnrollmentDateGroup>(query);
return View(data.ToList());
}
Calling an Update Query:
[HttpPost]
public ActionResult UpdateCourseCredits(int? credit)
{
if (credit != null)
{
ViewBag.RowsAffected = db.Database.ExecuteSqlCommand(
"UPDATE Course SET Credits = Credits * {0}", credit);
}
return View();
}
For more information have a look at Advanced Entity Framework 6 Scenarios for an MVC 5 Web Application (12 of 12).
Problem
Need to convert int to string using EF4 + SQL CE4. The recommended option of using SqlFunctions.StringConvert(double) still gives me errors.
Option 1 (original). This gives me error:
public static IEnumerable<SelectListItem> xxGetCustomerList()
{
using (DatabaseEntities db = new DatabaseEntities())
{
var list = from l in db.Customers
orderby l.CompanyName
select new SelectListItem { Value = l.CustomerID.ToString(), Text = l.CompanyName };
return list.ToList();
}
}
Option 2 (most suggested). Then as many posts suggests, I used the SqlFunctions.StringConvert() function from the library System.Data.Objects.SqlClient:
public static IEnumerable<SelectListItem> GetCustomerList()
{
using (DatabaseEntities db = new DatabaseEntities())
{
var list = from l in db.Customers
orderby l.CompanyName
select new SelectListItem { Value = SqlFunctions.StringConvert((double)l.CustomerID), Text = l.CompanyName };
return list.ToList();
}
}
Which now shows below error:
The specified method 'System.String StringConvert(System.Nullable`1[System.Double])' on the type 'System.Data.Objects.SqlClient.SqlFunctions' cannot be translated into a LINQ to Entities store expression.
Option 3 (for very specific case). Then anoter post shows a smart solution using Dictionary, which finally works:
public static IEnumerable<SelectListItem> xGetCustomerList()
{
using (DatabaseEntities db = new DatabaseEntities())
{
var customers = db.Customers.ToDictionary(k => k.CustomerID, k => k.CompanyName);
var list = from l in customers
orderby l.Value
select new SelectListItem { Value = l.Key.ToString(), Text = l.Value };
return list.ToList();
}
}
But only work for simple pair values (key, value). Can someone help me with another solution or what I'm doing wrong with option 2?
And I hope Microsoft will soon make EF right before pushing us to move from L2S which is already stable and much more mature. I actually using EF4 just because want to use SQL CE, otherwise I stay with L2S.
EF is database independent at upper layers but the part dealing with conversion of linq query to SQL is always database dependent and SqlFunctions are dependent on SQL Server Provider but you are using SQL Server CE provider which is not able to translate functions from SqlFunctions class.
Btw. third option is also not a solution because it will select whole customer table to memory and use linq-to-objects after that. You should use this:
public static IEnumerable<SelectListItem> xxGetCustomerList()
{
using (DatabaseEntities db = new DatabaseEntities())
{
// Linq to entities query
var query = from l in db.Customers
orderby l.CompanyName
select new { l.CustomerID, l.CompanyName };
// Result of linq to entities transformed by linq to objects
return query.AsEnumerable()
.Select(x => new SelectListItem
{
Value = x.CustomerID.ToString(),
Test = x.CompanyName
}).ToList();
}
}
Here is a simplified version I'm using now (specific for SQL CE):
public static IEnumerable<SelectListItem> GetBlogCategoryList()
{
using (SiteDataContext db = new SiteDataContext())
{
var list = from l in db.BlogCategories.AsEnumerable()
orderby l.CategoryName
select new SelectListItem { Value = l.CategoryID.ToString(), Text = l.CategoryName };
return list.ToList();
}
}
Note the db.BlogCategories.AsEnumerable() part