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).
Related
I have to use COLLATE in entity framework query. How to write SQL query equivalent in Entity Framework as show below code?
SQL query:
select * from AspNetUsers order by Email COLLATE Latin1_General_bin
Entity Framework:
using (var db = new testEntities())
{
var appUsers = await db.Users.OrderBy(x => x.Email).ToListAsync();
}
It's possible to use Entity Framework's interception hooks.
The first step it to define an interface:
interface ISortInterceptable
{
IEnumerable<string> AdaptableSortFieldNames { get; set; }
}
Then make your context implement it:
class TestEntities : DbContext, ISortInterceptable
{
...
public IEnumerable<string> AdaptableSortFieldNames { get; set; }
...
}
Next, create a command interceptor:
class SortCommandInterceptor : DbCommandInterceptor
{
public override void ReaderExecuting(DbCommand command,
DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
if (interceptionContext.DbContexts.First() is ISortInterceptable interceptable
&& interceptable.AdaptableSortFieldNames != null)
{
var query = command.CommandText;
foreach (var fieldName in interceptable.AdaptableSortFieldNames)
{
var pattern = $#"(.*\s*ORDER BY\s*.*\.)(\[{fieldName}\])(.*)";
query = Regex.Replace(query, pattern, "$1$2 COLLATE Latin1_General_bin $3");
}
command.CommandText = query;
}
base.ReaderExecuting(command, interceptionContext);
}
}
This is where all the magic happens.
The interceptor first checks if it has to do with a ISortInterceptable (maybe this check can be refined by getting all ISortInterceptables from interceptionContext.DbContexts).
The command text in the command to be executed is analyzed on any occurence of strings like ORDER BY [Alias].[fieldName] where fieldName is a variable. This search pattern is in keeping with the pattern EF always follows to generates queries.
The field name part of the ORDER BY clause, which is in the third group ($2) of the regex match, is extended by the collation phrase.
The replacement is repeated for all field names.
Finally, an example of how to use this interceptor:
DbInterception.Add(new SortCommandInterceptor());
using (var db = new TestEntities())
{
db.AdaptableSortFieldNames = new[] { "LastName", "Email" };
var users = db.AspNetUsers
.OrderBy(u => u.LastName)
.ThenBy(u => U.Email)
.ToList();
}
As always with string manipulation, one caveat: this works in a couple of my own tests, but I can't guarantee it to be rock solid. For one, the sorting fields should be text fields, of course.
One last note. EF core 3 also offers interception hooks that can be used in a similar way.
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.
I'm trying to use a Kendo UI grid in MVC and remote data. I want to only grab and display data from the DbSet, onload, where one of the fields, "Status", equals '1'. I thought this should be able to be accomplished in the controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Read([DataSourceRequest] DataSourceRequest request)
{
using (var db = new MyData(false))
{
var data = db.Training.Where(d => d.Status == '1').Select(d => new Training {
Id = d.Id,
Name = d.Name,
Status = d.Status
}).ToDataSourceResult(request);
return Json(data, JsonRequestBehavior.AllowGet);
}
}
The above code gives me the error that "The entity or complex type 'Training' cannot be constructed in a LINQ to Entities query". Any suggestions on how to rewrite the Linq statement so it'll work, or maybe a way to do it within the grid to suppress any that do not have a Status of '1'?
Your code is trying to project to a mapped entity which is not allowed. Additionally it's redundant to do that as you already have your entities. Remember that .Select() is for mapping one type to another but the .Where() method is already returning a list of your entities (Training).
Remove the .Select() and the query should work:
var data = db.Training.Where(d => d.Status == '1').ToDataSourceResult(request);
Is there a way to use simple sql queries on ASP MVC without using LINQ thing?
any link is welcome :)
Of course, you can always drop down to use regular ol' ADO.NET :-)
The Data Access Application Block is also commonly used to simplify the execution of raw sql and stored procedures.
Sure, you can embed plain ADO.NET objects within your controller's action methods or in a custom business logic library. A bit of an example. WARNING: DEMONSTRATION CODE ONLY. DO NOT ATTEMPT TO USE IN PRODUCTION SCENARIO.
public ActionResult Index()
{
using(SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["CNTax"].ConnectionString))
{
using(SqlCommand command = conn.CreateCommand())
{
command.CommandText = "select * from Names";
command.CommandType = CommandType.Text;
conn.Open();
var table = new DataTable();
table.load(command.ExecuteReader());
return View("Index", table);
}
}
}
A simple code snippet to select all names from the database and return the index view with the model set as a DataTable.
You sure can. And it is done the same way as you normally would in an ASP.NET application just like the other answers here have indicated.
....HOWEVER, I prefer to use a tool to generate my data access layer. Some of the top choices right now are nHibernate, and LLBLGen Pro, or even Microsoft's Entity Framework
I personally would go with nHibernate or LLBLGen Pro, depending on if you want to have your data access layer driven by "domain driven design" (nHibernate) or "data driven design" (LLBLGen Pro)
Building off of #user102220's answer:
Set up a data access layer (just a separate class or series of classes), then call these from your controller. Apply ADO.NET as necessary.
If you are using Entity Framework you can use SqlQuery like this:
using(var db = new DbContext())
{
var result = db.Database.SqlQuery<your object>("Your Query",params));
}
Your object : your expected result Type (object or class Type) and
Your query and params : sql command with params you should pass to query or not
try this solution:
var results = DynamicCall.DynamicListFromSql(_entities, "select * from users", null).ToList();
public static IEnumerable<dynamic> DynamicListFromSql(this DbContext db, string Sql, Dictionary<string, object> Params)
{
using (var cmd = db.Database.Connection.CreateCommand())
{
cmd.CommandText = Sql;
if (cmd.Connection.State != ConnectionState.Open) { cmd.Connection.Open(); }
using (var dataReader = cmd.ExecuteReader())
{
while (dataReader.Read())
{
var row = new ExpandoObject() as IDictionary<string, object>;
for (var fieldCount = 0; fieldCount < dataReader.FieldCount; fieldCount++)
{
row.Add(dataReader.GetName(fieldCount), dataReader[fieldCount]);
}
yield return row;
}
}
}
}