Attributes of an entity not available in LINQ to Entities - visual-studio-2010

Here is my problem with simplified example.
I have two entities modeled from SQL Server database:
Orders (columns available = OrderID, PackageCount,ManufactureDate, ShipDate, StatusID) Primary Key = OrderID)
OrderRecipients (columns available = RecipientID, FirstName, LastName, Address, City, Zip, Country, OrderID; Foreign Key = OrderID)
There is a [1 to many] relationship between Orders and OrderRecipients. One order can have several recipients.
I'm trying to extract the recipients of orders via the following code.
var allmyrecipients = from o in mycontext.Orders
where (o.SiteID.Equals("NYC") || o.SiteID.Equals("SFO"))
select o.OrderRecipients;
However when I try to get the names of the recipients with the following code:
foreach (var recipient in allmyrecipients)
{
Console.WriteLine(recipient.FirstName);
}
the FirstName and other attributes of the recipient are not available in the Intellisense drop-down. I get "does not contain a definition of FirstName" error.
Why is this and what is the remedy? What am I doing wrong here? I'm working with VS 2010, Entity Framework 4.
Thank you for taking time to help.

EDIT: I refactored this into somthing that should work using SelectMany. Give this a shot:
var orders = from o in mycontext.Orders
where (o.SiteID.Equals("NYC") || o.SiteID.Equals("SFO"))
select o;
foreach (var recipient in orders.SelectMany(r => r.OrderRecipients))
{
Console.WriteLine(recipient.FirstName);
}

Related

Entity Framework LINQ - dynamically select properties

Is it possible to create a dynamic selector like the below one in a simple way, and how?
Func<Company, string> companyName = x.CompanyName;
Func<Company, int> companyId = x.CompanyId;
var result = datacontext.Select(x => new
{
CompanyName = companyName,
CompanyId = companyId
});
The above code throws exception: "Unable to create a constant value of type 'System.Func`2... ...Only primitive types or enumeration types are supported in this context."
The problem is that I need to dynamically select up to 8 fields out of possible 50 from approximately 10 different tables, and these fields can be of types string, int, datetime nullable and not nullable. It is quiet difficult to dynamically construct a selector with Expressions. What is the best way to tackle this?
var result = datacontext.Select(x => new
{
CompanyName = mcname(x),
CompanyId = companyId(x)
});
But where is the reason?
Your Funcs should look like this:
Func<Company, string> companyName = (company => company.CompanyName);
Func<Company, int> companyId = (company => company.CompanyId);
To use your func:
var result = datacontext.Select(x => new
{
CompanyName = companyName(x),
CompanyId = companyId(x)
});
I don't know of a way to dynamically create a query for specific fields. You can dynamically chain filters with a single execution though... Unless you're storing a significant amount of information on each row or are loading hundreds of thousands of rows I wouldn't worry about it.
P.S. You'll want to be careful using custom functions in your primary database filters. LINQ can't translate all commands to a native SQL query so it may end up pulling an entire table and filtering in within your code. Just pay attention.
I'm not exactly sure what you are trying to accomplish, but could what you want be done simply like this?
var result = datacontext.Select(x => new
{
CompanyName = x.companyName,
CompanyId = x.companyId
});

Retrieve all rows from a Windows Azure table using WPF and WP7

I've set up a local service and a Windows Azure database. I can access the Azure database and retrieve data from all rows but only from one column at at time.
The database has a table called People with each 'record' treated as a Person. One of the columns in the table is 'Name' and I can retrieve all of the names using:
public List<string> GetAllPeople()
{
string query = #"SELECT value Person.Name FROM DataEntities.People AS Person";
List<string> resultsAsStrings = new List<string>();
using (var context = new DataEntities())
{
ObjectQuery<string> results = context.CreateQuery<string>(query);
foreach (string result in results)
{
if (result != null)
{
resultsAsStrings.Add(result);
}
}
}
return resultsAsStrings;
}
How would I go about changing the query so that I could retrieve a list of ALL of the Person records with ALL columns in the table as opposed to just the name field?
Is there a better way to read data from an Azure table?
Cheers!
Edit:
When I change the query to:
#"SELECT value Person FROM DataEntities.People AS Person";
It returns null and my WP7 app crashes. (I also adjusted the code so that it accepted Person instead of string. E.G ObjectQuery
Try changing the call to CreateQuery:
From: CreateQuery<string>
To: CreateQuery<Person>
This is required because if you select a Person this won't be a string, but a Person.
Now, could you try not using the type (Person) as alias? Try something like this:
SELECT VALUE pers FROM DataEntities.People AS pers
And why don't you simply use context.People?

How to declare the result of query in LINQ to Entities

I just started using MS entity framework and have the following problem with LINQ. I will simplify my problem to make it clearer; let's say that I have three tables in SQL Server database:
CustomerData (PK is CustomerId, the table also has some twenty columns to hold customer data).
CustomerData1 (holds some data for the customer in one to one relationship).
CustomerData2 (also holds some data for the customer in one to one relationship).
I know the data with one to one relationship should better be in the same table, but this is some corporate db and it is not possible to alter the original table (so all our data should be in the separate tables).
Now I want to display a list of customer with their data from CustomerData table and add some data columns from CustomerData1 via join.
On the other hand, I want to display a list of customers and add some data from the other table CustomerData2 via join.
So the data is basically the same both times except that in the first case the result includes some columns from CustomerData1 and in the second case some data from CustomerData2 table.
So I created the class Customer with properties for all relevant columns in CustomerData table and added properties for columns that should be included from CustomerData1 and properties that should be included from CustomerData2.
All columns should be included each time, except that when first call will be made the properties that map to CustomerData2 table will be empty and during the second call the properties that map to CustomerData1 table will be empty.
For this I wanted to create one function so I tried to create it like this:
Input parameter in function is whether data from CustomerData1 or CustomerData2 is included.
if (firstList)
{
var query1 = from obj in CustomerData
join rel in CustomerData1
on obj.CustomerId equals rel.CustomerId
select new { obj, rel };
}
if (secondList)
{
var query2 = from obj in CustomerData
join rel in CustomerData2
on obj.CustomerId equals rel.CustomerId
select new { obj, rel };
}
So this code gives me the anonymous type based on the input parameter. Now I want to create Customer objects and order it (order is always the same, it does not depend on input parameter). So I want to create a list of ordered customers and include additional data based on the input parameter.
var query3 = <previous_query_variable>.Select(f => new Customer {
Id = f.obj.CustomerId,
Name = f.obj.CustomerName,
... other columns from Customer table (a lot of them)
//and then add some additional columns based on the input parameter
Data1 = f.rel.someDataFromCustomer1, //only when firstList == true, otherwise empty
Data2 = f.rel.someDataFromCustomer2 //only when secondList == true, otherwise empty
}).OrderBy(f => f.Name); //order by customer name
Of course this does not compile, since both vars are inside if statements. I know I could copy this last statement (var query3 = ...) inside both if statements and include only relevant assignments (Data1 or Data2), but I don't want to assign properties that map to CustomerData table twice (once in both if statements) nor I want to order twice.
How can I solve this problem? I am using .NET 4.
You cannot declare a variable for an anonymous type up-front, i.e. before your two if statements. (Something like var query = null is not supported.) You will have to create a helper type and project into it, like so:
public class ProjectedCustomerData
{
public CustomerData CustomerData { get; set; }
public CustomerData1 CustomerData1 { get; set; }
public CustomerData2 CustomerData2 { get; set; }
}
And then the projection:
IQueryable<ProjectedCustomerData> resultQuery = null;
if (firstList)
{
resultQuery = from obj in CustomerData
join rel in CustomerData1
on obj.CustomerId equals rel.CustomerId
select new ProjectedCustomerData
{
CustomerData = obj,
CustomerData1 = rel
};
}
if (secondList)
{
resultQuery = from obj in CustomerData
join rel in CustomerData2
on obj.CustomerId equals rel.CustomerId
select new ProjectedCustomerData
{
CustomerData = obj,
CustomerData2 = rel
};
}
var query3 = resultQuery.Select(f => new Customer {
Id = f.CustomerData.CustomerId,
Name = f.CustomerData.CustomerName,
// ...
Data1 = f.CustomerData1.someDataFromCustomer1,
Data2 = f.CustomerData2.someDataFromCustomer2
}).OrderBy(f => f.Name);
I am not sure if Customer is an entity in your model or only a class you are using for your projection. If it's an entity you have to change the last code because you cannot project into an entity (basically you would need another helper type for your projection).

LINQ to Entities many to many relationship

I am new to LINQ and the Entity Framework and am having trouble coming up with a suitable query.
I have the following entities. I have included primary keys and some other relevant fields.
Contact
Int ContactId(PK),
String Name,
String EMailAddress
Project
Int ProjectId(PK)
ProjectContact
Int ProjectId(PK),
Int ContactId(PK),
Boolean IsPrimaryContact,
Boolean IsSecondaryContact
A project can have 1..n contacts, one of which is the primary contact for that project. Additionally if the project has more than one contact, one of the other contacts can be the secondary contact for that project.
A contact can be associated with many projects and may be the primary or secondary contact for several projects.
I need to generate an email for each group of projects that have a shared combination of primary and secondary contact. The idea is that the To field of the email contains the primary contact's email address, the CC field contains the secondary contact's email address (if there is a secondary contact) and the body of the email contains details of all the projects that have this combination of primary and secondary contacts.
I would like to populate a list containing objects with the following structure:
class EmailDetails
{
public Contact PrimaryContact;
public Contact SecondaryContact;
public IEnumerable<Project> Projects = new List<Project>();
}
So far I have this:
var QueryResults =
from project in ProjectSet
join primaryContact in ProjectContacts on project.ProjectId equals primaryContact.ProjectId where primaryContact.IsPrimary
join secondaryContact in ProjectContacts on project.ProjectId equals secondaryContact.ProjectId where secondaryContact.IsSecondary
select new {primaryContact, secondaryContact, project}
Where do I go from here?
Thanks.
It's rarely correct to use join in L2E/L2S. Use associations/navigation properties instead.
Off the top of my head (may require some tweaking):
var QueryResults = from project in ProjectSet
let p = project.Contacts.FirstOrDefault(c => c.IsPrimary)
let s = project.Contacts.FirstOrDefault(c => c.IsSecondary)
group project by new { Primary = p, Secondary = s } into g
select new EmailDetails
{
PrimaryContact = g.Key.Primary,
SecondaryContact = g.Key.Secondary,
Projects = from proj in g
select new ProjectDetails
{
Project = proj,
Region = proj.Region,
ProjectItems = proj.ProjectItems
}
};

Subsonic 3 Linq Projection Issue

OK I'm banging my head against a wall with this one ;-)
Given tables in my database called Address, Customer and CustomerType, I want to display combined summary information about the customer so I create a query to join these two tables and retrieve a specified result.
var customers = (from c in tblCustomer.All()
join address in tblAddress.All() on c.Address equals address.AddressId
join type in tblCustomerType.All() on c.CustomerType equals type.CustomerTypeId
select new CustomerSummaryView
{
CustomerName = c.CustomerName,
CustomerType = type.Description,
Postcode = address.Postcode
});
return View(customers);
CustomerSummaryView is a simple POCO
public class CustomerSummaryView
{
public string Postcode { get; set; }
public string CustomerType { get; set; }
public string CustomerName { get; set; }
}
Now for some reason, this doesn't work, I get an IEnumerable list of CustomerSummaryView results, each record has a customer name and a postcode but the customer type field is always null.
I've recreated this problem several times with different database tables, and projected classes.
Anyone any ideas?
I can't repro this issue - here's a test I just tried:
[Fact]
public void Joined_Projection_Should_Return_All_Values() {
var qry = (from c in _db.Customers
join order in _db.Orders on c.CustomerID equals order.CustomerID
join details in _db.OrderDetails on order.OrderID equals details.OrderID
join products in _db.Products on details.ProductID equals products.ProductID
select new CustomerSummaryView
{
CustomerID = c.CustomerID,
OrderID = order.OrderID,
ProductName = products.ProductName
});
Assert.True(qry.Count() > 0);
foreach (var view in qry) {
Assert.False(String.IsNullOrEmpty(view.ProductName));
Assert.True(view.OrderID > 0);
Assert.False(String.IsNullOrEmpty(view.CustomerID));
}
}
This passed perfectly. I'm wondering if you're using a reserved word in there?
This post seems to be referring to a similar issue...
http://groups.google.com/group/subsonicproject/browse_thread/thread/2b569539b7f67a34?hl=en&pli=1
Yes, the reason Rob's example works is because his projection's property names match exactly, whereas John's original example has a difference between CustomerType and type.Description.
This shouldn't have been a problem, but it was - the Projection Mapper was looking for properties of the same name and wasn't mapping a value if it didn't find a match. Therefore, your projection objects' properties would be default values for its type if there wasn't an exact name match.
The good news is, I got the latest source today and built a new Subsonic.Core.dll and the behavior is now fixed.
So John's code above should work as expected.
I just downloaded the latest build from 3/21/2010, which is about 2 months after the last poster on this thread, and the problem still exists in the packaged binary. Bummer.
Here what I have to do:
var data =
(from m in Metric.All()
where m.ParentMetricId == parentId
select new
{
m.MetricName,
m.MetricId,
})
.ToList();
var treeData =
from d in data
select new TreeViewItem
{
Text = d.MetricName,
Value = d.MetricId.ToString(),
LoadOnDemand = true,
Enabled = true,
};
return new JsonResult { Data = treeData };
If I try to do the projection directly from the Subsonic query, the Text property ends up with the ID, and the Value property ends up with the Name. Very strange.

Resources