LINQ Query result makes no sense - linq

I am running a simple LINQ query that connects to a view and returns all of the data with the id that I send in.
My simple query is:
var data = db.ViewDataAlls.Where(x => x.guidRequirementId == guidRequirementId);
if I run this query in the database:
select * from viewDataAll where guidrequiremendid = '{Guid Id Sent In Here}'
I get 2 rows back, however the LINQ query is returning 2 rows, but the rows are a duplicate of the first row, not 2 unique rows.
Any ideas?
EDIT: if I run this LINQ Query:
List<string> nums = db.ViewDataAlls
.Where(x => x.guidRequirementId == guidRequirementId)
.Select(x=>x.strNumber).ToList();
I get the individual row numbers, but if I just try to pull the entire row I get a duplicate of the first row multiple times...

I had the same problem. I was ready to conclude that this was a bug in Linq-to-SQL. Direct SQL queries against the view worked, Linqpad queries worked, etc... but for some reason querying against a view sometimes (and not even very often mind you, but when I'd find a particular value that failed, it appeared to always do so) failed. I verified that the query being passed by Linq to the SQL Server was correct (from the SQLServer logs), so it appeared the results were being mangled when they were received by Linq. Querying directly against the view or accessing the contents of the view via a defined association gave the same bad results.
Realizing that the problem lay on the receiving side of the query (after the results were passed back to Linq), I finally tracked it down to the way I had added the view to the dbml. Originally I had dragged the view onto the dbml designer surface, and added an association to the table I wanted to link it to, a basic one-to-many association (using an basic fkid == id relationship). However I couldn't access the view from the table in code. I discovered that I needed to add a primary key to the child (view), so I set the id property as the PK. This seemed to work until I got an unexpected exception when doing a .SingleOrDefault() against the view through the association. Knowing that it should be impossible for my data to have more that one hit for the property I was filtering with, I ran it through the debugger, and sure enough I was getting the right number of results (2 in my case), but the second result was just a copy of the first. The same thing the OP saw.
The solution it turns out is to set all the fields of the view as part of the primary key (in the dbml; I only had 3). Somehow, having the id field as the lone PK was not sufficient for Linq. Once I did this I had no further problems. (It may not be necessary to designate every field as part of the PK, so you may wish to experiment, but just the one id is insufficient apparently).
Note that I did have the view set as "not unique" in the dbml, which one would think would keep this from happening. Apparently not so.

Is ViewDataAlls a view or a table. If it's a view, maybe the sql statement generating that view produces duplicates.

Thanks JHurdlow, you save my day. Looks like LINQ does not use the groupby or order-by in the views. In my case, the SQL Statement in the view was correct and data was presented very well, but for any reason when use LINQ on my MVC3 is different and duplicates rows. In my case I had a view with 5 tables and I had to put all fields as PK on the view at ___DataModel.edmx. Now works fine.
This solution implies that all fields must be not-null, otherwise has to use CASE NULL-THEN END on the View schema.

Related

Entity Framework returns different result with AsNoTracking

I use Entity Framework in combination with an Oracle database. If I create a query like
myLinqStatement.ToListAsync()
I get wrong data returned as a result. If I change the statement to
myLinqStatement.AsNoTracking.ToListAsync()
I get the correct data.
I also checked the native SQL query, which is generated by myLinqStatement.ToListAsync(). The generated SQL query is correct, because I get the correct data.
So is there a problem in the mapping? And why is it working with AsNoTracking?
Thanks!
What AsNoTracking does is to retrieve the data without attaching it to the context, hence any changes you apply over the data do not take effect unless you attach it again so that EF knows it should track its changes.
The code snippets you've provided do not show the whole picture, from the moment a context is created, but is it possible that other parts of your code mutate data before you call myLinqStatement.ToListAsync()?
As you mention that myLinqStatement.AsNoTracking.ToListAsync() returns expected data, makes me assume that there are some side effects in your code that AsNoTracking simply is not aware so just returns whatever it finds in your db
I came across this question because I had a similar issue with Entity Framework Core querying a DB view, the issue was cause because view didn't have a key defined, after defining a key for the entity that map to that DB view, the query returned the same result in both cases (using AsNoTracking or without using it).
In T-SQL a key for a DB view can be defined this way:
CREATE UNIQUE CLUSTERED INDEX UQ_MyDBViewName_ColumnKey
ON dbo.MyDBViewName (ColumnKey);
And in code, you can map the key using the [Key] attribute in the corresponding property of the entity or using the EF fluent API. It will depend of what the project is using.
Either way, using AsNoTracking on a query that goes directly to a DB view makes a lot of sense. Also, if for some reason the query of the view does not allow us to define a key for that view, then the option is to use AsNoTracking.
Hope it helps anyone else having the same issue.

Database.SqlQuery with ViewModel and Include results in blank FK values

I am trying to display a grid of Orders from the Northwind sample database, which has FK references to the Customers and Employees tables. I want to use raw SQL (variable "query") and project to a ViewModel "Order_VM". The ViewModel includes the references to the Customers and Employees entities.
I have tried the following statement, which works fine, but only with the original model "Order" and the DbSet version of SqlQuery:
IQueryable<Order> orders = db.Orders.SqlQuery(query).AsQueryable().Include(o => o.Customer).Include(o => o.Employee);
However, I want it to work with the ViewModel "Order_VM" instead (code below) using the Database version of SqlQuery (I assume this is the only way), but the CompanyName (from Customers table) and LastName (from Employees table) display blank in the View (grid).
IQueryable<Order_VM> orders = db.Database.SqlQuery<Order_VM>(query).AsQueryable().Include(o => o.Customer).Include(o => o.Employee);
I have tried with/without the "virtual" keyword for the Customer and Employee entity references in the ViewModel to see if eager vs lazy loading was a factor. However still get blanks. Thanks for any help as I am still learning.
I have tried the following statement, which works fine
No, it doesn't, because the Include doesn't do anything. It compiles and runs, but the returned type, DbSqlQuery<Order> doesn't have an implementation of Include, so the method is ignored. You tried to fix that with the AsQueryable call, but that only "re-activates" the extension method Include, but it doesn't magically inject an Include implementation.
DbSqlQuery (and DbRawSqlQuery, the return type of db.Database.SqlQuery) don't implement IQueryable<T>, so original EF query provider is out of scope and won't return.
To execute the Include statement it should be possible to modify the executed SQL statement and put some JOINs in there. But EF can only do that when Include is called on an object that contains an expression tree, so it can add expressions to this tree. A raw SQL query will never be parsed into an expression tree, but simply be executed as is.
So, these raw SQL queries are only capable of populating flat objects from the column list in the SELECT statement. Nested objects (references of collections) will never be materialized. If your view model has a CompanyName property, you should have a select statement like SELECT ..., Company.CompanyName, ..., so the raw SQL should contain the JOIN.

LINQ update statement using generic table and column names

OK, I've seen a lot of posts on creating generic LINQ statements, but these are usually based on select queries. What I need is a LINQ UPDATE statement that takes a generic parameter for the table to update and a generic parameter for the column to update.
The data model I'm working with has dozens of tables, and each table has potentially dozens of columns. What I'm really driving toward is a single Update statement that allows me to tell it at runtime which table and which column to update.
Dealing with data typing of these dynamically supplied fields will also be an issue since obviously I can't update a DateTime column with a decimal value for example.
So, can anyone point me at some code that shows a LINQ update process using generic parameters for table and column names.
Any help would be greatly appreciated!
You didn't specify Entity Framework with DbContext but if that is what you are using, this is pretty easy. The following code is written to work within the NerdDinner sample which can be downloaded from http://nerddinner.codeplex.com/
This code locates a dinner based on the id and sets the address property to "New Value"
Dinner dinner = db.Set<Dinner>().Find(id);
var entry = db.Entry(dinner);
entry.Property("Address").CurrentValue = "New Value";
db.SaveChanges();

LINQ to Entities - How best to obtain the IDENTITY value after calling SaveChanges()

There have been numerous questions posed on this site relating to the retrieval of the IDENTITY after an insert is performed. The way we have been getting the identity is to make the call below, immediately after calling SaveChanges();
context.MyClass.OrderByDescending(c => c.Id).FirstOrDefault();
This seems to work consistently may be completely adequate; however, it has the appearence of opening up a potential for error, should another record be added in between the calls. So the first question is, given that EF performs withing a transacional context, is this method sound?
Secondly, the answer provided to the following question suggests there may be a better way.
Linq to SQL - How to find the the value of the IDENTITY column after InsertOnSubmit()
In that answer, after calling SubmitChanges(), the following call (where "tst" represents the user's class) retrieves the value.
Response.Write("id:" + tst.id.ToString)
This appears to work exactly the same way in LINQ to Entities, where after the call to save changes the instance of the class now includes the id.
context.MyClass.Add(myClass);
context.SaveChanges();
int myNewIdentity = myClass.Id;
Since we are asking for the the actual ID of the class instance (actual record) it would appear to be failsafe. And, it seems logical that the designers of EF should make such basic functionality available. Can anyone confirm that this is proper way to get the identity or at least a best practice?
Yes, LINQ-to-Entities (and LINQ-to-SQL for that matter) will set the generated identity column back in the entity for you after SaveChanges is called. It will also do so for any foreign keys that couldn't be set ahead of time (for instance, a new parent row + a new child row are saved together, and after SaveChanges you'll have the right value in the child row's FK value).
Your particular concern is documented in the 'Working with Entity Keys' page:
http://msdn.microsoft.com/en-us/library/dd283139.aspx
The particular section is 'Entity Keys and Added Objects' and the particular steps are:
4 - If the INSERT operation succeeds, server-generated values are written back to the ObjectStateEntry.
5 - The ObjectStateEntry updates the object with the server-generated value.

Linq To SQL Without Explicit Foreign Key Relationships

I am working with a few legacy tables that have relationships, but those relationships haven't been explicitly set as primary/foreign keys. I created a .dbml file using "Linq To Sql Classes" and established the proper Case.CaseID = CaseInfo.CaseID association. My resulting class is CasesDataContext.
My Tables (One to many):
Case
------------------
CaseID (int not null)
MetaColumn1 (varchar)
MetaColumn2 (varchar)
MetaColumn3 (varchar)
...
CaseInfo
------------------
CaseInfoID (int)
CaseID (int nulls allowed)
CaseInfoMeta (varchar)
...
I'm new to LinqToSQL and am having trouble doing..
CasesDataContext db = new CasesDataContext();
var Cases = from c in db.Cases
where c.CaseInfo.CaseInfoMeta == "some value"
select c;
(Edit) My problem being that CaseInfo or CaseInfos
is not available as a member of Cases.
I heard from a colleague that I might try ADO.Net Entity Data Model to create my Data Context class, but haven't tried that yet and wanted to see if I'd be wasting my time or should I go another route. Any tips, links, help would be most appreciated.
Go back to the designer and check the relation is set up correctly. Here is one real life example, with BillStateMasters have "CustomerMasters1" property (customers for the state):
Ps. naming is being cleaned up ...
Update 1: You also need to make sure both tables have a primary defined. If the primary key isn't defined on the database (and can't be defined for whatever reason), make sure to define them in the designer. Open the column's properties, and set it as primary key. That said, entity tracking also won't work if you haven't a primary key for the entity, which for deletes means it silently doesn't updates the entity. So, make sure to review all entities and to have them all with a primary key (as I said, if it can't be on the db, then on the designer).
CasesDataContext db = new CasesDataContext();
var Cases = from c in db.Cases
join ci in db.CaseInfo on
ci.ID equals c.InfoID
where ci.CaseInfoMeta == "some value"
select new {CASE=c, INFO=ci};
my "join" linq is a bit rusty, but the above should get close to what you're after.
Is the association set to One to One or One to Many? If you have the association set to One to Many, then what you have is an EntitySet, not an EntityRef and you'll need to use a where clause on the dependent set to get the correct value. I suspect that you want a One to One relationship, which is not the default. Try changing it to One to One and see if you can construct the query.
Note: I'm just guessing because you haven't actually told us what the "trouble" actually is.
Your query looks correct and should return a query result set of Case objects.
So... what's the problem?
(Edit) My problem being that CaseInfo
is not available under Cases... i.e.
c.CaseInfo doesn't exist where I'm
assuming it would be if there were
explicit primary/foreign key
relationships.
What do you mean by "not available"? If you created the association in the designer as you say you did, then the query should generate SQL something along the lines of
SELECT [columns]
FROM Case INNER JOIN CaseInfo
ON Case.CaseID = CaseInfo.CaseID
WHERE CaseInfo.CaseInfoMeta = 'some value'
Have you debugged your linq query to get the SQL generated yet? What does it return?
Couple of things you might want to try:
Check the properties of the association. Make sure that the Parent property was created as Public. It does this by default, but something may have changed.
Since you're not getting CaseInfo on C, try typing it the other direction to see if you get ci.Case with intellisense.
Delete and recreate the association all together.
There's something very basic going wrong if the child members are not showing up. It might be best to delete the dbml and recreate the whole thing.
If all else fails, switch to NHibernate. :)
After a few tests, I'm pretty sure the FK relationships are required in the DB regardless of whatever associations are created in Linq-to-SQL. i.e. if you don't have them explicitly set in the DB, then you will have to do a join manually.
Is this c#? I think you need == instead of = on this line:
where c.CaseInfo.CaseInfoMeta = "some value"
should read
where c.CaseInfo.CaseInfoMeta == "some value"

Resources