Linq Retrieve Entities using a Navigational Property - c#

Linq and EF.
I'm pretty new so I have some problem to retrieve entities using a Navigational Property (CmsContents).
I can return as an List but not as an IEnumerable.
Could you tell me what is wrong in my code?
Also do you know a better approach to retrieve Entities suing Navigational Properties?
Please provide me an example of code thanks!
public IEnumerable<CmsGroupsType> GetMostPopularContents()
{
using (var context = new CmsConnectionStringEntityDataModel())
{
context.CmsGroupsTypes.MergeOption = MergeOption.NoTracking;
var contents = context.CmsGroupsTypes.Single(g => g.GroupTypeId == 1).CmsContents;
return contents.ToList();
}
}
Error 1 Cannot implicitly convert type 'System.Collections.Generic.List<WebProject.DataAccess.DatabaseModels.CmsContent>' to 'System.Collections.Generic.IEnumerable<WebProject.DataAccess.DatabaseModels.CmsGroupsType>'. An explicit conversion exists (are you missing a cast?)

The generic types don't match: Your .ToList() is of CmsContent, but your return type is an IEnumerable of CmsGroupsType. I'm not sure if that was intentional, but changing the return type to IEnumerable<CmsContent> will make everything work.

Change your return type from CmsGroupsType to WebProject.DataAccess.DatabaseModels.CmsContent

Related

How to filter a generic list?

I have the code below which was working, but when I try to add the Where clause to filter the collection I get the error:
'object' does not contain a definition for 'Where' and no extension
method 'Where' accepting a first argument of type 'object' could be
found (are you missing a using directive or an assembly reference?)
I tried casting the object to OfType<Certification> and that failed. I also tried casting to IQueryable and that failed with a similar error. So I checked the type of my certifications variable and it is "System.Collections.Generic.List``1[[GainesTrader_WCF.Certification, GainesTrader WCF,". Can you see the solution to this?
GainesTrader_WCF.Service1 client = new GainesTrader_WCF.Service1();
object certifications = client.GetCertifications();
//var filtered = certifications.OfType<Certification>().Where(o => o.CertificationAcronym == "MCSD");
var filtered = certifications.Where(o => o.CertificationAcronym == "MCSD");
Certifications.DataSource = filtered;
Certifications.DataBind();
why is the certificates variable of type object? Look at the WCF proxy and verify the return type. When you set up the proxy, visual studio should've downloaded all related types.
Also, this is the first time, I've seen someone apply the Where extension method to a Object type. It doesn't even make sense.
You should cast your certifications variable to type IEnumerable<Certification>:
var filtered = certifications
.OfType<IEnumerable<Certification>>()
.Where(o => o.CertificationAcronym == "MCSD");
or
var certifications = (IEnumerable<Certification>)client.GetCertifications();
var filtered = certifications.Where(o => o.CertificationAcronym == "MCSD");

Abstracting out queries to the Azure Table Storage using Expressions

I'm creating a class to perform CRUD functionality with Azure Table Storage.
I'm using generic types in this.
I have the following method, which i'm trying to pass in an expression to get used in the TableQuery, but am having some issues.
The line TableQuery<T> query = new TableQuery<T>().Where<T>(criteria); won't compile, and gives me the message
Cannot implicitly convert type 'System.Linq.IQueryable<T>'
to 'Microsoft.WindowsAzure.Storage.Table.TableQuery<T>'.
An explicit conversion exists (are you missing a cast?)
I understand the message and know it's telling me i'm missing a cast, though I'm unsure how to code it correctly.
My full method is:
public List<T> GetSome<T>(Expression<Func<T, bool>> criteria) where T : ITableEntity, new()
{
TableQuery<T> query = new TableQuery<T>().Where<T>(criteria); // <---- This line isn't working
List<T> results = table.ExecuteQuery<T>(query).ToList<T>();
return results;
}
Ok, so I figured it out - how i can pass in a lambda expression for Azure Table Storage to use.
I changed my method to the following:
public List<T> GetSome<T>(Expression<Func<T, bool>> criteria) where T : ITableEntity, new()
{
// table, in this case, is my `CloudTable` instance
List<T> results = table.CreateQuery<T>().Where(criteria).ToList();
return results;
}
I can now pass in an expression. For example, to search against a DynamicTableEntity I can use:
// my table storage class
TableStorage ts = new TableStorage("ContactData");
// search with expression
List<DynamicTableEntity> results = ts.GetSome<DynamicTableEntity>(t => t.Properties["FirstName"].StringValue == "Darren");
If this is something you wouldn't/shouldn't do against an Azure Table Store, please do let me know.
In the meantime, this is how I have met the requirement.
The error is because the value returned by the extension method Where is of type IQueryable<T>, but you're assigning to a variable of type TableQuery<T> and there is no implicitly valid type conversion between these types.

Filtering data from Entity Framework

I have simple method where I retrieve data from database and send it to the View. But in the meantime data need to filtered. I have below code:
public ActionResult Index(string Name, string Manufacturer)
{
var dev = db.Devices;
if(!String.IsNullOrEmpty(Name))
{
dev = dev.Where(w => w.Name.Contains(Name));
}
if(!String.IsNullOrEmpty(Manufacturer))
{
dev = dev.Where(w => w.Manufacturer.Contains(Manufacturer));
}
return View(dev.ToList());
}
but I'm getting this error:
Cannot implicitly convert type
'System.Linq.IQueryable' to
'System.Data.Entity.DbSet'. An explicit
conversion exists (are you missing a cast?)
I tried adding cast eg:
(DbSet<Device>)
But didn't helped. Can anyone suggest me how to modify my code?
The problem is db.Devices will be a DbSet<Device> collection, not an IQueryable<T>, so on these lines
dev = dev.Where(...)
the Where will return IQueryable<T> and given DbSet<T> can't be implicitly set as IQueryable<T> you get an exception.
What you need to do here is convert your DbSet<T> to an IQueryable<T> and that can be done pretty easily by calling AsQueryable i.e.
var dev = db.Devices.AsQueryable();
By
var dev = db.Devices;
you declare dev to be of type DbSet<Device>. The Where-methods return an IQueryable and therefore, you cannot use the variable dev. Change the declaration as follows:
var dev = db.Devices.AsQueryable();

How get propery value of an dynamic type?

[update]
I'm sorry, i should tag this question
as MVC-2, I pass result of query into
view's model, so i must specify type
of my model in View's header
defintion. I declare it like this:
Inherits="System.Web.Mvc.ViewPage<IQueryable<dynamic>>"
how ever nothing changed and none of
answers doesn't work for me :(.
finally i used an ModelView class as
helper to put my query result in it.
:(
[/update]
I have a query like this:
IQueryable<dynamic> result = from d in KiaNetRepository.KiaNetEntities.Discounts
where d.AgentTypeID == agentTypeId
select new { d.Category, d.DiscountValue, d.PriceConfige };
then i retrive value in my view like this:
foreach(var item in result){
Category cat = item.Category; // throws exception 'object' does not contain a definition for 'Category'
//...
}
note that type of query as IQueryable is anonymouse class...
Try to declare names explicitly:
select new { Category = d.Category, DiscountValue = d.DiscountValue, PriceConfige = d.PriceConfige }
If you are not forcing result to be of IQueryeable<dynamic> for any specific reason, I would recommend using var result = .... This will let the compiler make result of type IQueryable<T> with T the type of the anonymous class that you create using new { ... } in the select. There is no necessity for using dynamic from the code that you show here.
If you replace the inappropriate declaration IQueryable<dynamic> by var, sure it works, I've just also tested it.
Your problem is that your foreach loop being in the view page gets compiled into a separate assembly. Since anonymous types are internal the dynamic doesn't see it because of the permissions don't allow it.
Simplest fix is to call ToList() on your query statement and then select each anonymous type and copy parameters to a declared class or expandoobject.

"Member access 'DataType MemberName' of 'Namespace.ClassName' not legal on type 'System.Collections.Generic.IEnumerable`1[Namespace.ClassName]."

I would love a solution to my current problem, but I would love EVEN MORE if I can understand what that error actually means.
I have LINQ to SQL classes for two tables in my DB: Providers and Assignments. I added the following member to the Provider class:
public IEnumerable<Assignment> Assignments
{
get
{
return (new linqDataContext())
.Assignments
.Where(a => a.ProviderID == this.ProviderID);
}
}
Then, I bind a GridView using a query that pulls from the parent Provider and uses the child member Assignments, like this:
protected void PopulateProviders()
{
linqDataContext context = new linqDataContext();
var list = from p in context.Providers
where (p.Assignments.Count(a => a.Category == ddlCategory.SelectedValue) > 0)
select p;
lvProviders.DataSource = list;
lvProviders.DataBind();
}
At .DataBind(), when it actually runs the query, it throws the following error:
Member access 'System.String Category' of 'Namespace.Assignment' not legal on type 'System.Collections.Generic.IEnumerable`1[Namespace.Assignment].
I've tried checking for nulls (a => a != null && a.Category ...) but that hasn't worked. I'm not sure what to try next. I think that, if I knew what the error is trying to tell me, I could find the solution. As it stands, I don't know why member access would be illegal.
That Assignments property is all wrong. First of all, property getters should not have side-effects, and more importantly, entity classes should never have reverse dependencies on the DataContext. Linq to SQL has no way to decipher this query; it's relying on a property that does all sorts of crazy stuff that Linq to SQL can't hope to understand.
Get rid of that Assignments property now. Instead of doing that, you need to write this query as a join:
int category = (int)ddlCategory.SelectedValue;
var providers =
from p in context.Providers
join a in context.Assignments
on p.ProviderID equals a.ProviderID
into g
where g.Count(ga => ga.Category == category) > 0
select p;
That should do what you're trying to do if I understood the intent of your code correctly.
One last side note: You never dispose properly of the DataContext in any of your methods. You should wrap it like so:
using (var context = new linqDataContext())
{
// Get the data here
}
I think somewhere it doesn't know that type that is in the IEnumerable. You are trying to call a method that is not part of the IEnumerable inteface.
Why don't you just move the query from the property out to the PopulateProviders() method?
Remove your custom-defined Assignments property. In the your Linq-To-SQL dbml file, create an association between Providers and Assignments, with Providers as the parent property, and ProviderID as the Participating Property for both entities. LINQ will generate a property "IEnumerable Assignments" based on matches between ProviderID using a consistent DataContext.

Categories

Resources