CRM 2011 - N:N (Many-To-Many) Linq Issue - linq

I have two entities who are N:N - related with each other. With an example I'll show you what I mean :
I have a Session (ave_Session) and there we can put "Trainers"
(ave_trainer) on each Session
I'm tryting to get a list of al the
"Trainers" for a particular Session
They are related to each other in
N:N (relationship name : ave_ave_session_ave_trainer)
I work in VS2010 and with C# => I'm trying to get the data through LINQ
I recently just started with LINQ, so maybe you guys can help me out on this one. The following I've tried and i gave me an "AttributeFrom and AttributeTo must be either both specified or both ommited. You can not pass only one or the other. AttributeFrom: , AttributeTo: ave_trainerid"-error :
var formatteurs = (from f in ORGContext.CreateQuery<ave_trainer>()
join s in ORGContext.CreateQuery<ave_ave_session_ave_trainer>() on f.Id equals s.ave_trainerid.Value
join c in ORGContext.CreateQuery<ave_session>() on s.ave_sessionid.Value equals c.Id
where c.Id == item.Id
select f).ToList();
The item.id is the Id of the session. Thx in advance if you can help me out!

From the MSDN page:
// List the contacts in the Softball team marketing list.
System.Console.WriteLine("List all contacts in Softball Team:");
var members = from c in crm.contacts
join mlm in crm.listmembers on c.contactid equals mlm.entityid
join ml in crm.lists on mlm.listid equals ml.listid
where ml.listname == "Softball Team"
select c;
foreach (var c in members)
{
System.Console.WriteLine(c.fullname + " " + c.emailaddress1);
}

It seems a little backwards the way you have it written now (assuming I'm parsing it correctly).
What you'd normally do is put your 'starting thing' first and then go through the mapping to get to the ones you want. I don't have any CRM 2011 experience, so hopefully I didn't mess this up too much. :)
Also, I'm not a fan of single-character names, so I took the liberty of using longer names :)
var formatteurs = (
// first get the session we're interested in
from session in ORGContext.CreateQuery<ave_session>()
where session.Id == item.Id
// now get the mapping rows that are related to it
join mapping in ORGContext.CreateQuery<ave_ave_session_ave_trainer>()
on session.Id equals s.ave_sessionid.Value
// now get from the mapping rows to the actual trainers
join trainer in ORGContext.CreateQuery<ave_trainer>()
on mapping.ave_trainerid.Value equals trainer.Id
select trainer
).ToList();

Related

Entity Framework returns wrong data after execution of two similar queries

I have two similar queries, the first one:
var activatedSerialNumbers = (from activation in entities.Activations
where !canceledActivationsIds.Contains(activation.Id)
where activation.CustomerId == customerId
join licenseConfiguration in entities.LicenseConfigurations
on activation.Id equals licenseConfiguration.ActivationId
where licenseConfiguration.ProductId == productId
join activatedSerialNumber in entities.ActivatedSerialNumbers
on activation.Id equals activatedSerialNumber.ActivationId
where deactivatedSams.All(dsn => dsn.ToLower() !=
activatedSerialNumber.Name.ToLower())
select new SamWithLicense
{
Name = activatedSerialNumber.Name,
Features = licenseConfiguration.LicenseFeatures
}).ToList();
The second:
var activationsForSam = (from activation in entities.Activations
where !canceledActivationsIds.Contains(activation.Id)
where activation.CustomerId == customerId
let activatedSerialNumbers = activation.ActivatedSerialNumbers
.Select(sn => sn.Name.ToLower())
where activatedSerialNumbers.Contains(loweredSn)
join licenseConfiguration in entities.LicenseConfigurations
on activation.Id equals activatedProduct.ActivationId
select new SamWithLicense
{
Name = selectedSerialNumber,
Features = licenseConfiguration.LicenseFeatures
}).ToList();
In some situations I execute them one after another and in most cases it works fine, but somethimes - not. In the result of second query Counter takes from another row:
Visual Studio - Quick watch
SQL Management Studio
I guess it's a matter of a EF cache or smth, but don't know how to fix it properly.
In your first query you are joining the Activation Id (PK) to LicenseConfigurations ActivationId (FK)
join licenseConfiguration in entities.LicenseConfigurations
on activation.Id equals licenseConfiguration.ActivationId
in your second query, it looks like you are joining on a value defined outside of the query "activatedProduct"
join licenseConfiguration in entities.LicenseConfigurations
on activation.Id equals activatedProduct.ActivationId

LINQ/LinqPad: same query different results

So we copy and paste the exact same query from LinqPad into our EF 4.3 application, pointed at the exact same database and get a different result. In LinqPad we get 2 records returned. In our application we reaise an error "Object reference not set to an instance of an object."
var Shippings = shippingRepository.All.ToArray();
var SalesOrderHeaders = salesOrderHeaderRepository.All.ToArray();
var Customers = customerRepository.All.ToArray();
var Stores = storeRepository.All.ToArray();
var Departments = departmentRepository.All.ToArray();
var toShip = from sh in Shippings
join h in SalesOrderHeaders on sh.OrderId equals h.SalesOrderHeaderId
join c in Customers on h.CustomerId equals c.CustomerId
join st in Stores on h.StoreId equals st.StoreId
join d in Departments on h.DepartmentId equals d.DepartmentId into outer
from o in outer.DefaultIfEmpty()
select new
{
OrderId = sh.OrderId,
CustomerName = c.Name,
StoreName = st.Name,
DepartmentName = (o.Name == null) ? o.Name : "None",
DeliveryDate = h.DeliveryDateTime
};
In the application code, when we remove the outer join (to add Departments) and it's associated field the query returns the same 2 records asn in LinqPad.
Does anyone have any insight into how to fix this feature?
Click on "Add a connection" in linqpad and select datacontext from assembly like
You can choose Entity Framework datacontext or Entity Framework BDContext with POCO depending upon your scenario. click next and provide path to the assembly along with connection string and you will be good to go.
In LINQPad are you actually querying against your entity model? Take a look at this link if you aren't. I had a similar problem when starting out and didn't realize I had set up a default LINQ to SQL connection earlier and was querying against that.

LINQ - How to select and count the right results

I have 3 tables: DiaryPosts, DiaryImpressions, Impressions.
Impressions is a small list with some fields: 'like', 'dislike', 'agree', 'disagree'. The user can vote according to what he thinks about the post.
DiaryImpressions is the table that handles the relationship between the posts and the users who vote.
My problem is, I have to count results of each impression vote for each post, so maybe for one post 13 users voted for like, 2 for dislike, 34 agree and 1 disagree.
I have no idea how to perform the query in some way I can get this specific count results for each impression.
Can anyone help me with that?
You can do this via the GroupBy method. It allows you to automatically "group" the elements based on the impression, and count the results per group.
var post(from c in posts selec c)
string post1like;
string post2dislike;
string postagree3;
string postdisagree3;
foreach (var item in posts)
{
var ipressionslike=(from c in imressions where impressioid=item.id where c.impressionID='LIKE' select c.userID).Tolist()
var ipressionsdislike=(from c in imressions where impressioid=item.id where c.impressionID='disLIKE' select c.userID).Tolist()
var ipressionslike=(from c in imressions where impressioid=item.id where c.impressionID='LIKE' select c.userID).Tolist()
var ipressionsagree=(from c in imressions where impressioid=item.id where c.impressionID='disLIKE' select c.userID).Tolist()
post1like+=item.id+""+ipressionsdislike.count;
post2dislike+=item.id+""+ipressionslike.count;
postagree3+=item.id+""+ipressionsagree.count;
}
it should count the impressions for each post and count the amount of users that like or dislike so if you have 30 people dislike for each post it should get them I cannot see your table structure but I hope it will help or point you somewhere
I have to guess but here is what I think the SQL would look like:
SELECT I.Name, COUNT(I.Name)
FROM DairyPosts P
JOIN DairyImpressions DI ON P.ID=DI.DairyID
JOIN Impressions I ON DI.ImpressionsID = I.ID
And what the linq would look like:
List<Dairy> dairyposts = GetDairyPosts();
var impressionCounts =
from p in dairyposts
group p by p.ImpressionName into g
select new { Type = g.Key, ImpressionCount = g.Count() };
Of course I have to assume your list is created a certain way, if you can post how your list is actually created that would help. (As I said in the comments)

Linq query error

I am using following Linq query:
from p in People
where p.Name == "George Lucas"
select p.TitlesActedIn
where TitlesActedIn is a list. People and TitlesActedIn are associted
But I am getting error:
InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.PropertyExpression' to type 'System.Data.Services.Client.ResourceExpression'.
Please suggest solution.
A very simple way to do it:
var query = People
.Expand("TitlesActedIn")
.Where(p => p.Name == "George Lucas")
.First()
.TitlesActedIn.Select(t => t.ShortName);
query.Dump();
Its important to note, that this will crash if the name you pass it does not exist. (The First Operator will throw an exception. You would need to either guarantee that the name exists, or do it in two steps.
If you want to do it in one step it comes down to this:(please note what is coming back)
http://odata.netflix.com/catalog/People()?$filter=Name eq 'George Lucas'&$top=1&$expand=TitlesActedIn
You need the expand or it will quit evaluating after the .First(), because TitlesActedIn will be empty.
It basically translates to select the Person, include (expand) the TitlesActedIn association, then select the name (client side)
The downside of this is that you are pulling back everything (all fields) from the Titles table. So for every title associated to the Person it is returning (Title, Year, Description, ShortName, etc).
If you did this in two queries you could only pull back "ShortName" from the TitlesActedIn association.
UPDATED: See this question and answer to understand the limitations on Select Many in Data Services + Another solution based on $expand (note this requires the server to support expand)
If this is WCF Data Services and TitlesActedIn is a collection of related movies.
Then you can do this in one query only if Person.Name is the primary key.
To illustrate this:
var titles = from p in people
where p.Name == "George Lucas"
from m in p.TitlesActedIn
select m;
Will do what you want but only if Name is the key of the Person entity, otherwise this is unsupported.
If Name is not the key one way to do this (today) is with two queries, something like this:
var key = (from p in people
where p.Name == "George Lucas"
select new {p.Id}).Single().Id;
var titles = from p in people
where p.Id == key
from m in p.TitlesActedIn
select m;
Another option though would be do an expand:
var george = (from p in people.Expand("TitlesActedIn")
where p.Name == "George Lucas"
select p).Single();
var titles = george.TitlesActedIn;
But that relies on the server supporting $expand - which not all servers do...
Note we are currently working on adding any/all support to OData and WCF Data Services, once that is released you would be able to write:
var titles = from t in titles
where t.Actors.Any(a => a.Name == "George Lucas")
select t;
Hope this helps
Note: in the code that gets the key for George Lucas I create an anonymous type because today WCF Data Services doesn't support materializing primitives directly.
Interestingly, the following works:
from p in People
where p.Name == "George Lucas"
select new { p.TitlesActedIn }
as does this:
(from p in People
where p.Name == "George Lucas"
select new { p.TitlesActedIn }).First().TitlesActedIn
The WCF client automatically adds the expansion call in the URI translation:
http://odata.netflix.com/Catalog/People()?$filter=Name eq 'George Lucas'&$top=1&$expand=TitlesActedIn&$select=TitlesActedIn/*
I get a similar error if I use a group by clause along with the lambda expression to fetch data using WCF Data Service. I got to know that certain operations are not supported by WCF data services. Please make sure you are not using unsupported LINQ operations.
http://msdn.microsoft.com/en-us/library/ee622463.aspx

Need help Understanding Linq group by with joins

Hi I created this Linq query
var k = from account in _session.All<AccountDetail>()
join subscriber in _session.All<Subscriber>() on account.ID equals subscriber.AccID
join subscriberServices in _session.All<SubscriberServce>() on subscriber.ID equals subscriberServices.UserID
join paymentMethod in _session.All<PaymentMethod>() on subscriberServices.PaymentMethod_ID equals paymentMethod.ID
join paymentFrequency in _session.All<PaymentFrequency>() on subscriberServices.PaymentFrequency_ID equals paymentFrequency.ID
group account by new {AccID= account.ID,paymentFrequency= paymentFrequency.Description,paymentMethod= paymentMethod.Description} into G
select new GenerateInvoiceData() { AccID = G.Key.AccID};
I don't understand
group account by new {AccID= account.ID,paymentFrequency= paymentFrequency.Description,paymentMethod= paymentMethod.Description} into G
why do I specify account when I'm not restricted to it in the anonymous type i.e. I can type paymentFrequency.Description.
The group account part is saying what you want the elements in each group to be. The by new { ... } is what you want the key for each group to be. That's not restricted to being part of the information in an element.
As a simplest example, you might have:
from person in people
group person.FirstName by person.LastName
which would give you groups where the key of each group was the last name of all the people represented in the group, and each element of each group would be the first name of someone.
You might want to read two of my Edulinq blog posts:
How query expressions work
The GroupBy method

Resources