LINQ to Entities many to many relationship - linq

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
}
};

Related

Get a list of entities by a list of attributes in Spring Boot eg. findAllByIdIn(List<Integer> ids)

I need help getting a list of entities by a list of attributes, say "id', "name' etc. Below is what I have so far and I'm expecting three entities but the result shows only one. The logic of the code below is basically to grab all entries with LOGIN as eventType and customer Id in the event repo. We're then getting the "eventdetailsIds" into a separate collection from the result found and searching(findByIdIn) for them in the LoginEventRepo. EventDetailsId is more or less a foreign key that joins event repo and loginEvent Repo. PS. I have implemented manually but I just need a more concise approach. Thanks.
public List<CustomerEventResponse> getAllCustomerLogins(String customerId) {
List<CustomerEventResponse> customerEventResponses;
List<EventEntity> eventEntityList = eventRepository.findByCustomerIdAndEventType(customerId, LOGIN_EVENT);
List<LoginEventDetailsEntity> loginEventDetailsEntityList = new ArrayList<>();
List<Integer> eventDetailsIds = new ArrayList<>();
for(EventEntity e: eventEntityList){
eventDetailsIds.add(e.getEventDetailsId());
Optional<LoginEventDetailsEntity> loginEventDetails = loginEventDetailsRepository.findById(e.getEventDetailsId());
loginEventDetails.ifPresent(loginEventDetailsEntityList::add);
}
List<LoginEventDetailsEntity> loginDetails = loginEventDetailsRepository.findAllById(eventDetailsIds);
The database is below:
Thanks.

How do you filter a list based on matching items in another list?

I have an Organisation object
public class Organisation
{
OrgId {get....}
OrgName {get...}
AccountTypes { get....} //this is of type List<AccountType>
}
and an AccountType object
public class AccountType
{
AccountTypeId {get....}
AccountTypeName {get...}
}
I'm looking for a way to look through the existing Organisations List and remove AccountTypes from each organisation where the account types are not found in another list of AccountTypes (which would be a post back from a browser).
Would I do something like?
var foundOrgs = from org in orgs
where org.OrganisationId == Convert.ToInt32(hash["orgId"])
select org;
Organisation organisation = foundOrgs.ElementAt(0);
organisation.AccountTypes.Clear();
organisation.AccountTypes = // What goes here?
I'm looking to do a Linq query that will compare one list with another and return only those items where the AccountTypeIDs match, or are present.
You can use List<T>.RemoveAll:
// where accounts is IEnumerable<int>
organisation.AccountTypes.RemoveAll(at => !accounts.Contains(at.AccountTypeId));
EDITED CODE
//created account id list over here
var AccountTypeID = accountType.Select(x=>x. AccountTypeId);
//you code
var foundOrgs = from org in orgs
where org.OrganisationId == Convert.ToInt32(hash["orgId"])
select org;
Organisation organisation = foundOrgs.ElementAt(0);
organisation.AccountTypes.Clear();
//changes in code where you want to change -// What goes here?
List<AccountTypes> templist = organisation.AccountTypes;
organisation.AccountTypes =
from acc in templist
where !AccountTypeID.Conains(acc.AccountTypeId)
select acc).ToList();
EDIT
No sure but you can try out
var orgdata= from org in foundOrgs
select { OrgId =org.OrgId ,OrgName = org.OrgName ,
AccountTypes = ( from acc in org.AccountTypes
where !AccountTypeID.Conains(acc.AccountTypeId)
select acc) };
Try something like this
var ids = {1, 2, 3};
var query = from item in context.items
where !ids.Contains( item.id )
select item;
this will give you list of element which are not part of 1,2,3 i.e ids list , same you can apply in you code first find out which are not there and than remove it from the list
Image

Attributes of an entity not available in LINQ to Entities

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

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).

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