I'm using C#, .NET (4.0) and Entity Framework to connect to SQL CE 4.0.
I query some objects with specific properties, but the query returns only objects that meet search criteria only if that data was already saved to database, which is not that problematic, bigger problem is that if data is changed, but not yet saved to database it will still meet search criteria.
Example:
var query = from location in mainDBContext.Locations
where location.InUse == true
select location;
This query returns also objects where location.InUse = false if InUse was true when loaded from DB and then changed later on in code.
This is screen capture from one of the query results objects.
I really don't understand why it does this. I would understand if this query would always query database and I would get the older version of this object (thus InUse would be true).
Thank you for your time and answers.
That is how EF works internally.
Every entity uniquely identified by its key can be tracked by the context only once - that is called identity map. So it doesn't matter how many times did you execute the query. If the query is returning tracked entities and if it is repeatedly executed on the same context instance it will always return the same instance.
If the instance was modified in the application but not saved to the database your query will be executed on the database where persisted state will be evaluated but materialization process will by default use the current data from the application instead of data retrieved from the database. You can force the query to return state from the database (by setting mainDBContext.Locations.MergeOption = MergeOption.OverwriteChagens) but because of identity map your current modifications will be lost.
I'm not really sure what exactly your problem is, but I think you have to know this:
That kind of query always return data that is submitted into DB. When you change some entities in your code but they are not submitted into database the LINQ query will query the data from database, without your in-code changes.
LINQ queries use Deferred Execution, so your 'query' variable is not a list of results, it's just a query definition that is evaluated each time results are needed. You should add .ToList() to evaluate that query and get a list of results in that certain line of code.
An example for .ToList():
var query = (from location in mainDBContext.Locations
where location.InUse == true
select location).ToList();
I just ran into the same thing myself. It's a bit messy, but another option is to examine the Local cache. You can do this, for example:
var query = from location in mainDBContext.Locations.Local
where location.InUse == true
select location;
This will only use the local cache not saved to the database. A combination of local and database queries should enable you to get what you want.
Related
I want to ask about the execution timing of a LinqToSql query.
From my understanding refer to this MSDN blog. It seems that a LinqToSql query will only execute when
IQueryable's property is accessed
IQueryable's function (which is not returning IQueryable/IEnumeration type) is called
However, I did an experiment like that:
var ents = from ent in dal.ents
select ent;
string s1 = ents.first().Value1; // I got 1 here
Console.ReadLine(); // When the system is waiting for my input. I change the same record manually in DB, I change Value2 of ent from 2 to 3 here.
string s2 = ents.first().Value2 // I got 2 here.
Why am I still getting "2" for s2?
From my understanding, ents.first().Value2 should connect to the DB again and get the new Value2. Why am I still getting the old value?
As soon as you get Value1 on this line, the call is made to the db
string s1 = ents.first().Value1;
Then it keeps the object in memory (along with Value2). It doesn't call the database again when you try to access Value2.
Finally, I think I found the working principal behind.
L2S is really working like
LinqToSql query will only CONNECTION TO DB AND EXECUTE when
IQueryable's property being accessed
IQueryable's function (which is not returning IQueryable / IEnumeration type) being called
But in additions, after L2S fetch data from DB for each record at the first time. It will cache the record by its PK.
Eventually, on each further fetch. It will check if the record has been fetched before.
yes, It will use the cached version of the record instead of the DB version.
If no, It will use the DB version.
P.S. The lifetime of the cached records will last until the DBContext being released.
I am doing a query with linq and entity framework. The database I'm using is Oracle. Here is the code :
Entities bdd = contextWrapper.GetContext();
data = (from table in bdd.COP_PRDTICSOURES
where (table.IDTTIC==ticketId && table.IDTPRD==productId)
select table).AsEnumerable();
When I look at the variable bdd.COP_PRDTIC_SOURES using a debugger, it contains an entry matching my two criteria. However, after the execution of the query, the data variable contains no result.
Is there something wrong with my syntax ?
Some additional information:
The entity i'm looking for isn't commited in the database when I perform this query. It's created before in the same transaction.
I use a foreach on the data after, so it's not a problem of lazy loading.
AsEnumerable does not load data from DB. Calling it you are not executing the actual query, just changing how it is going to be executed in its entirety.
Use ToArray or ToList instead to load data explicitly. Or call foreach on this collection.
I have a web app, and I'm connecting to a DB with entity framework.
To select all Employee records of a particular department, for example, I can quite easily write:
....Employees.Where(o => o.Department == "HR").ToList();
Works fine. But is it most optimal?
Should this Where clause be incorporated into a stored procedure or view? Or does my entity framework code do the job of converting it to SQL anyway?
We've had performance problems in our team in the past from when people pull records into memory and then do the filtering in .net instead of at a database level. I'm trying to avoid this happening again so want to be crystal clear on what I must avoid.
If Employees is provided by Entity Framework then the Where() will be translated into SQL and sent to the database. It is only the point that you materialise the objects does it take the filters you have applied before and turn them into SQL. Anything after that point is just plain LINQ to objects.
Methods that cause materialisation to happen include things like .ToList() and .ToArray() (there are more, but these two are probably the most common).
If you want to see what is happening on SQL Server, you should open up the SQL Profiler and have a look at the queries that are being sent.
We've had performance problems in our team in the past from when people pull records into memory and then do the filtering in .net instead of at a database level.
Just as an addendum to Colin's answer, and to target the quote above, the way to avoid this is to make sure your database queries are fully constructed with IQueryable<T> first, before enumerating the results with a call such as .ToList(), or .ToArray().
As an example, consider the following:
IEnumerable<Employee> employees = context.Employees;
// other code, before executing the following
var hrEmployees = employees.Where(o => o.Department == "HR").ToList();
The .ToList() will enumerate the results grabbing all of the employees from the context first, and then performing the filtering on the client. This isn't going to perform very well if you've got a lot of employees to contend with, and it's certainly not going to scale very well.
Compare that with this:
IQueryable<Employee> employees = context.Employees;
// other code, before executing the following
var hrEmployees = employees.Where(o => o.Department == "HR").ToList();
IQueryable<T> derives from IEnumerable<T>. The difference between them is that IQueryable<T> has a query provider built in, and the query you construct is represented as an expression tree. That means it's not evaluated until a call that enumerates the results of the query, such as .ToList().
In the second example above, the query provider will execute SQL to fetch only those employees that belong to the HR department, performing the filtering on the database itself.
I have this C# L2S code:
Table<ERPRaw> linqRawFile = db.GetTable<RawFile>();
var linqNameList =
from row in linqRawFile.AsEnumerable()
select row.fileName;
currentFileNameList = linqNameList.ToArray();
It's supposed to read only the fileName field, but when I check in the SQL server profiler, I see that this query triggers full record loading. The fields contain file binary data, so the full table loading takes considerable time. Retrieving just the fileName field takes only few milliseconds.
What would be the right way to retrieve only fileName field of RawFile in as an array of strings? I assume that the linq framework now loads each RawFile record in full, as it doesn't see I will retrieve only the fileName property from the list.
Perhaps I have to construct the query without referencing the linqRawFile at all? Wouldn't that be kind of ignoring the reason linq is introduced in the project, to abstract the database layer away?
It's supposed to read only the fileName field
No, it does not. Here is what is going on: your query execution happens in two places - in RDBMS and in memory. The db.GetTable<RawFile>() happens in RDBMS; everything after it happens in memory, because you use AsEnumerable().
The portion of the query where the projection happens (i.e. row.fileName column is extracted from the whole row) is happening in memory. The RDBMS part of the query does not know about this projection. db.GetTable<RawFile>() is all the SQL-generating LINQ provider sees, so naturally it returns the entire row.
If you write a combined query against your SQL source, the projection will happen in SQL:
var linqNameList =
from row in db.GetTable<RawFile>()
select row.fileName;
You should be able to replace the whole thing with this:
var currentFileNameList = db.GetTable<RawFile>().Select(r => r.fileName).ToArray();
I have a simple query that deletes an entry from a table
CB_User_Schedule deleted = (from x in db.CB_User_Schedules
where x.ScheduleID == CurrentScheduleID
select x).Single();
db.CB_User_Schedules.DeleteOnSubmit(deleted);
db.SubmitChanges();
However, the first statement returns Sequence contains no elements. I can see that when it executes the value of CurrentScheduleID is in fact a number and when I directly execute select * from CB_UserSchedules where ScheduleID = 3 it does return a row. So why is my statement not finding that row in the database?
Check the emitted SQL with the built-in LINQ-to-SQL logging (hook up a TextWriter to the Log property on your DataContext) or SQL profiler. More than likely you've got a datatype mismatch or key issue in your DBML (ie, something doesn't match reality in the DB and the mapper is barfing on it). We run a very large and complex site almost exclusively on L2S, and these kinds of issues are almost always related to broken DBML.