Subsonic Linq guid problem - linq

The construtor 'Void .ctor(System.Guid, Int32)' is not supported.
this error occured with the following statements:
var Test = from r in db.UserRoles
join p in db.UserPermissions
on new { r.userId, r.roleId} equals new { p.userId, p.roleId }
select r;
userId is a guid
roleId is an integer

Right - the constructor for UserRoles looks like it needs a Guid and int - something you're not supplying explicitly. SubSonic has no way of figuring this out for you - one of the many reasons I keep telling people to abstract the membership stuff behind an interface and don't try to use SubSonic to get to it - you're circumventing most of their magic.

Related

NHibernate Linq Query - Select Sub Queries

I'm new to NHibernate and not great at Linq, but this is seriously kicking my butt, and I can't find any really clear examples on SO.
I need to get Thread information from the database, but I need to include a subquery that does a count on the number of Posts on a particular thread.
Here is a SQL Statement
Select ID, ThreadName,
(Select Count(Posts.ID) From Posts Where ThreadID = Threads.ID) as Replies
From Threads
And Class Structure:
Class Thread
Property ID as Integer
Property ThreadName as String
Property Replies as Integer
End Class
Class Post
Property ID as Integer
Property ThreadID as Integer
Property PostText as String
End Class
Any help would be much appreciated. And bonus points to supply both a LINQ example and a one using the NHibernate syntax.
So the query would be like this:
C#
var query =
from thrs in session.Query<YourNamespace.Thread>() // in C# Thread would need
select new YourNamespace.Thread // precise NS to distinguish System.Threading
{
ID = thrs.ID,
ThreadName = thrs.ThreadName,
Replies = thrs.Posts.Count()
};
var list = query.ToList(); // the above statement was executed
VB:
Dim query = From t As Thread In session.Query(Of Thread)()
Select New Thread With {
.ID = t.ID,
.ThreadName= t.ThreadName,
.Replies = t.Posts.Count
}
Dim list as List(of Thread) = query.ToList()
The very important think here is, that the Thread must have a mapping to the collection of Posts
C#
public class Thread
{
...
// really sorry for C# ... I will learn VB syntax ...
public virtual IList<Post> Posts { get; set; }
VB
Public Class Thread
Public Overridable Property Posts As IList(Of Post)
If this collection of Posts, would be mapped in NHibernate, then the above LINQ syntax will work out of the box

LINQ to Entities does not recognize the method 'Boolean CheckMeetingSettings(Int64, Int64)' method

I am working with code first approach in EDM and facing an error for which I can't the solution.Pls help me
LINQ to Entities does not recognize the method 'Boolean
CheckMeetingSettings(Int64, Int64)' method, and this method cannot be
translated into a store expression.
My code is following(this is the query which I have written
from per in obj.tempPersonConferenceDbSet
where per.Conference.Id == 2
select new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327,per.Person.Id)
}
public bool CheckMeetingSettings(int,int)
{
///code I have written.
}
Please help me out of this.
EF can not convert custom code to SQL. Try iterating the result set and assigning the property outside the LINQ query.
var people = (from per in obj.tempPersonConferenceDbSet
where per.Conference.Id == 2
order by /**/
select new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
}).Skip(/*records count to skip*/)
.Take(/*records count to retrieve*/)
.ToList();
people.ForEach(p => p.CanSendMeetingRequest = CheckMeetingSettings(6327, p.Id));
With Entity Framework, you cannot mix code that runs on the database server with code that runs inside the application. The only way you could write a query like this, is if you defined a function inside SQL Server to implement the code that you've written.
More information on how to expose that function to LINQ to Entities can be found here.
Alternatively, you would have to call CheckMeetingSettings outside the initial query, as Eranga demonstrated.
Try:
var personDetails = obj.tempPersonConferenceDbSet.Where(p=>p.ConferenceId == 2).AsEnumerable().Select(p=> new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327,per.Person.Id)
});
public bool CheckMeetingSettings(int,int)
{
///code I have written.
}
You must use AsEnumerable() so you can preform CheckMeetingSettings.
Linq to Entities can't translate your custom code into a SQL query.
You might consider first selecting only the database columns, then add a .ToList() to force the query to resolve. After you have those results you van do another select where you add the information from your CheckMeetingSettings method.
I'm more comfortable with the fluid syntax so I've used that in the following example.
var query = obj.tempPersonConferenceDbSet
.Where(per => per.Conference.Id == 2).Select(per => new { Id = per.Person.Id, JobTitle = per.Person.JobTitle })
.ToList()
.Select(per => new PersonDetails { Id = per.Id,
JobTitle = per.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327, per.Person.Id) })
If your CheckMeetingSettings method also accesses the database you might want to consider not using a seperate method to prevent a SELECT N+1 scenario and try to express the logic as part of the query in terms that the database can understand.

Using an IEqualityComparer with a LINQ to Entities Except clause

I have an entity that I'd like to compare with a subset and determine to select all except the subset.
So, my query looks like this:
Products.Except(ProductsToRemove(), new ProductComparer())
The ProductsToRemove() method returns a List<Product> after it performs a few tasks. So in it's simplest form it's the above.
The ProductComparer() class looks like this:
public class ProductComparer : IEqualityComparer<Product>
{
public bool Equals(Product a, Product b)
{
if (ReferenceEquals(a, b)) return true;
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
return false;
return a.Id == b.Id;
}
public int GetHashCode(Product product)
{
if (ReferenceEquals(product, null)) return 0;
var hashProductId = product.Id.GetHashCode();
return hashProductId;
}
}
However, I continually receive the following exception:
LINQ to Entities does not recognize
the method
'System.Linq.IQueryable1[UnitedOne.Data.Sql.Product]
Except[Product](System.Linq.IQueryable1[UnitedOne.Data.Sql.Product],
System.Collections.Generic.IEnumerable1[UnitedOne.Data.Sql.Product],
System.Collections.Generic.IEqualityComparer1[UnitedOne.Data.Sql.Product])'
method, and this method cannot be
translated into a store expression.
Linq to Entities isn't actually executing your query, it is interpreting your code, converting it to TSQL, then executing that on the server.
Under the covers, it is coded with the knowledge of how operators and common functions operate and how those relate to TSQL. The problem is that the developers of L2E have no idea how exactly you are implementing IEqualityComparer. Therefore they cannot figure out that when you say Class A == Class B you mean (for example) "Where Person.FirstName == FirstName AND Person.LastName == LastName".
So, when the L2E interpreter hits a method it doesn't recognize, it throws this exception.
There are two ways you can work around this. First, develop a Where() that satisfies your equality requirements but that doesn't rely on any custom method. In other words, test for equality of properties of the instance rather than an Equals method defined on the class.
Second, you can trigger the execution of the query and then do your comparisons in memory. For instance:
var notThisItem = new Item{Id = "HurrDurr"};
var items = Db.Items.ToArray(); // Sql query executed here
var except = items.Except(notThisItem); // performed in memory
Obviously this will bring much more data across the wire and be more memory intensive. The first option is usually the best.
You're trying to convert the Except call with your custom IEqualityComparer into Entity SQL.
Obviously, your class cannot be converted into SQL.
You need to write Products.AsEnumerable().Except(ProductsToRemove(), new ProductComparer()) to force it to execute on the client. Note that this will download all of the products from the server.
By the way, your ProductComparer class should be a singleton, like this:
public class ProductComparer : IEqualityComparer<Product> {
private ProductComparer() { }
public static ProductComparer Instance = new ProductComparer();
...
}
The IEqualityComparer<T> can only be executed locally, it can't be translated to a SQL command, hence the error

linq help - newbie

how come this work
public IQueryable<Category> getCategories(int postId)
{
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
var query = from c in categories.GetAll()
join pcm in postCategoryMap.GetAll() on c.CategoryId equals pcm.CategoryId
where pcm.PostId == 1
select new Category
{
Name = c.Name,
CategoryId = c.CategoryId
};
return query;
}
but this does not
public IQueryable<Category> getCategories(int postId)
{
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
var query = from c in categories.GetAll()
join pcm in postCategoryMap.GetAll() on c.CategoryId equals pcm.CategoryId
where pcm.PostId == postId
select new Category
{
Name = c.Name,
CategoryId = c.CategoryId
};
return query;
}
The issue is most likely in the implementation of the query provider.
pcm.PostId == 1
and
pcm.PostId == postId
actually have a big difference. In the expression tree the first is generated as a ConstantExpression which doesnt need to be evaulated.
With the second, the compiler actually generates an inner class here (this is the _DisplayClassX that you see). This class will have a property (will most likely be the same name as your parameter) and the expression tree will create a MemberAccessExpression which points to the auto-generated DisplayClassX. When you query provider comes accross this you need to Compile() the Lambda expression and evaluate the delegate to get the value to use in your query.
Hope this helps.
cosullivan
The problem is not the linq itself,
you need to be sure that the context or provider object is able to fetch the data.
try testing the
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
objects and see if they are populated or if they behaving as required.
you may want to search the generated code for c__DisplayClass1 and see what you can see there. some times the generated code dose some weird things.
when you step into you code check the locals and the variable values. this may also give you some clues.
Edit : Have you tried to return a List<> collection ? or an Enumerable type?
Edit : What is the real type of the item and query may not be iterable

When selecting an anonymous type with LINQ from EF, is there no way to run a method on an object as you select it?

Let's say I have a method:
bool myMethod(int a)
{
//return a bool
}
So let's say I the following
// assume a has prop1 and prop2 both ints
var mySelection = from a in myContainer
where a=somecondition
select new {
a.prop1,
myMethod(a.prop2)
};
Is there really no way to run myMethod in the anonymous type declaration? Is there some sort of trick?
Can I put an anonymous method in there to return the equivalent of myMethod(a.prop2)?
Well lets separate this into LINQ to Objects and LINQ to Entities
In LINQ to Object the above fails because the compiler doesn't know what the Property name is, if you change it to this:
var mySelection = from a in myContainer
where a=somecondition
select new {
a.prop1,
prop2 = myMethod(a.prop2)
};
It will work in LINQ to Objects
However the Entity Framework won't be able to translate the method call (unless it is a function known to the EF like a Model Defined Function, EdmMethods or SqlMethods) so you'll have to rewrite that query like this:
var mySelection = from a in myContainer
where a=somecondition
select new {
a.prop1,
a.prop2
};
var myResults = from a in mySelection.AsEnumerable()
select new {a.prop1, prop2 = myMethod(a.prop2)};
This pulls what you need out the database, and then using the AsEnumerable() call turns the call to myMethod into something processed by LINQ to Objects rather than LINQ to Entities
Hope this helps
Alex
I don't think there is a way to call out to a method from an anonymous initializer. Even if there were, it probably wouldn't perform very well.
If you need to create a result set that requires additional processing, I would create a concrete class.

Resources