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

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.

Related

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();

EAV - Get value using Linq to entities

In a data model like this (http://alanstorm.com/2009/img/magento-book/eav.png) I want to get the value from an EAV_Attribute using Linq to SQL.
Assuming that an EAV_Attribute only exists in one inherited table (varchar, decimal, int, etc.) how can I get it in a linq query?
I know that I can use the Inheritance for this, but I want to execute it in the SQL Database side...
Is it possible to do a kind of Coalesce in Linq, considering that the elements have different types?
EAV and linq is not a happy marriage. I think your best shot is to create an unmapped property in eav_attribute that resolves the value (as object) from it's typed attribute child. With entity framework, you won't be able to use this property in an expression (i.e. not in a Where or Select), You must convert to IEnumerable first to access it. (Linq-to-sql may allow it because it can switch to linq-to-objects below the hood).
Another option is to create a calculated column of type sql_variant that does the same, but now in t-sql code. But... EF does not suport sql_variant. You've got to use some trickery to read it.
That's the reading part.
For setting/modifying/deleting values I don't see any shortcuts. You just have to handle the objects as any object graph with parents and children. In sql server you can't use cascaded delete because it can only be defined for one foreign key. (This may tackle that, but I never tried).
So, not really good news, I'm afraid. Maybe good to know that in one project I also work with a database that has an inevitable EAV part. We do it with EF too, but it's not without friction.
First of all, I recommend using TPH and not TPT for EAV tables. (One table with multiple nullable value columns (one per type) + discriminator vs. one table per type.)
Either way, if you modelled the value entity as an abstract class (containing the two IDs) with an inheriting entity per value data type that adds the value property, then your LINQ should look like this:
var valueEntity = context.ProductAttributes.Where(pa =>
pa.ProductId == selectedProductId
&& pa.AttributeTypeId == selectedAttributeTypeId)
.SingleOrDefault() as ProductAttributeOfDouble;
if valueEntity != null
return valueEntity.Value;
return null;
Where the entity types are: Product, AttributeType, ProductAttribute, ProductAttributeOfDouble, ... ProductAttributeOfString.

LINQ Query result makes no sense

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.

binding to a linq query, silverlight 4

I would like to know if binding a control in Silverlight, to linq expression is same as binding to an observable collection ? I have a treeview which as of now I'm binding to an observable collection. Then I learned about linq expressions and it seemed by using the linq query i can totally get rid of this collection and generate it using the query but i'm not sure if this generated result from the linq query will get updated on the fly and pass the updates to the UI?
for example i have a list of employees, i created an observable collection of "employees who were managers" and used that as the itemsource for the tree. Whenever new employees were added and if they were managers they would get added to the manager collection and the tree would update. Now using linq i can generate a list of employees who are managers using a query but i don't have means to test if this will also get updated when new employees who are managers are added to the employees collection.
class EmployeeCollection : IEnumerable<Employee>, INotifyCollectionChanged
{
private List<Employee> empColl;
// private ObservableCollection<Employee> managerCollection; Not needed now
}
managerTreeView.ItemsSource = from Employee in EmployeeCollection where Employee.isManager select Employee;
Thanks
LINQ results aren't live collections, so updates to the source (in the linq query) won't trigger the query results to reevaluate. Hence, you won't have your desired behavior.
Hope this helps :)

Using LINQ with stored procedure that returns multiple instances of the same entity per row

Our development policy dictates that all database accesses are made via stored procedures, and this is creating an issue when using LINQ.
The scenario discussed below has been somewhat simplified, in order to make the explanation easier.
Consider a database that has 2 tables.
Orders (OrderID (PK), InvoiceAddressID (FK), DeliveryAddressID (FK) )
Addresses (AddresID (PK), Street, ZipCode)
The resultset returned by the stored procedure has to rename the address related columns, so that the invoice and delivery addresses are distinct from each other.
OrderID InvAddrID DelAddrID InvStreet DelStreet InvZipCode DelZipCode
1 27 46 Main St Back St abc123 xyz789
This, however, means that LINQ has no idea what to do with these columns in the resultset, as they no longer match the property names in the Address entity.
The frustrating thing about this is that there seems to be no way to define which resultset columns map to which Entity properties, even though it is possible (to a certain extent) to map entity properties to stored procedure parameters for the insert/update operations.
Has anybody else had the same issue?
I'd imagine that this would be a relatively common scenarios, from a schema point of view, but the stored procedure seems to be the key factor here.
Have you considered creating a view like the below for the stored procedure to select from? It would add complexity, but allow LINQ to see the Entity the way you wanted.
Create view OrderAddress as
Select o.OrderID
,i.AddressID as InvID
,d.AddressID as DelID
...
from Orders o
left join Addresses i
on o.InvAddressID= i.AddressID
left join Addresses d
on o.DelAddressID = i.AddressID
LINQ is a bit fussy about querying data; it wants the schema to match. I suspect you're going to have to bring that back into an automatically generated type, and do the mapping to you entity type afterwards in LINQ to objects (i.e. after AsEnumerable() or similar) - as it doesn't like you creating instances of the mapped entities manually inside a query.
Actually, I would recommend challenging the requirement in one respect: rather than SPs, consider using UDFs to query data; they work similarly in terms of being owned by the database, but they are composable at the server (paging, sorting, joinable, etc).
(this bit a bit random - take with a pinch of salt)
UDFs can be associated with entity types if the schema matches, so another option (I haven't tried it) would be to have a GetAddress(id) udf, and a "main" udf, and join them:
var qry = from row in ctx.MainUdf(id)
select new {
Order = ctx.GetOrder(row.OrderId),
InvoiceAddress = ctx.GetAddress(row.InvoiceAddressId),
DeliveryAddress = ctx.GetAddress(row.DeliveryAddressId)) };
(where the udf just returns the ids - actually, you might have the join to the other udfs, making it even worse).
or something - might be too messy for serious consideration, though.
If you know exactly what columns your result set will include, you should be able to create a new entity type that has properties for each column in the result set. Rather than trying to pack the data into an Order, for example, you can pack it into an OrderWithAddresses, which has exactly the structure your stored procedure would expect. If you're using LINQ to Entities, you should even be able to indicate in your .edmx file that an OrderWithAddresses is an Order with two additional properties. In LINQ to SQL you will have to specify all of the columns as if it were an entirely unrelated data type.
If your columns get generated dynamically by the stored procedure, you will need to try a different approach: Create a new stored procedure that only pulls data from the Orders table, and one that only pulls data from the addresses table. Set up your LINQ mapping to use these stored procedures instead. (Of course, the only reason you're using stored procs is to comply with your company policy). Then, use LINQ to join these data. It should be only slightly less efficient, but it will more appropriately reflect the actual structure of your data, which I think is better programming practice.
I think I understand what you're after, but I could wildy off...
If you mock up classes in a DBML (right-click -> new -> class) that are the same structure as your source tables, you could simply create new objects based on what is read from the stored procedure. Using LINQ to objects, you could still query your selection. It's more code, but it's not that hard to do. For example, mock up your DBML like this:
Pay attention to the associations http://geeksharp.com/screens/orders-dbml.png
Make sure you pay attention to the associations I added. You can expand "Parent Property" and change the name of those associations to "InvoiceAddress" and "DeliveryAddress." I also changed the child property names to "InvoiceOrders" and "DeliveryOrders" respectively. Notice the stored procedure up top called "usp_GetOrders." Now, with a bit of code, you can map the columns manually. I know it's not ideal, especially if the stored proc doesn't expose every member of each table, but it can get you close:
public List<Order> GetOrders()
{
// our DBML classes
List<Order> dbOrders = new List<Order>();
using (OrderSystemDataContext db = new OrderSystemDataContext())
{
// call stored proc
var spOrders = db.usp_GetOrders();
foreach (var spOrder in spOrders)
{
Order ord = new Order();
Address invAddr = new Address();
Address delAddr = new Address();
// set all the properties
ord.OrderID = spOrder.OrderID;
// add the invoice address
invAddr.AddressID = spOrder.InvAddrID;
invAddr.Street = spOrder.InvStreet;
invAddr.ZipCode = spOrder.InvZipCode;
ord.InvoiceAddress = invAddr;
// add the delivery address
delAddr.AddressID = spOrder.DelAddrID;
delAddr.Street = spOrder.DelStreet;
delAddr.ZipCode = spOrder.DelZipCode;
ord.DeliveryAddress = delAddr;
// add to the collection
dbOrders.Add(ord);
}
}
// at this point I have a List of orders I can query...
return dbOrders;
}
Again, I realize this seems cumbersome, but I think the end result is worth a few extra lines of code.
this it isn't very efficient at all, but if all else fails, you could try making two procedure calls from the application one to get the invoice address and then another one to get the delivery address.

Resources