How to alter this LINQ to SQL so it doesn't bomb at runtime? - linq-to-sql

public IQueryable<Story> FindAllStories(){
var stories = (from s in db.Stories
orderby s.DateEntered descending
select new Story
{
Title = s.Title,
UserName = s.aspnet_User.UserName
}
);
return stories;
}
I need to pass this as IQueryable so the pagination helper I found online can only pull the items I need. The problem is that at runtime when the helper tries to do source.Count(); the compiler isn't a happy camper because it's an 'explicit contruction of an entity type query'.
How would I alter this LINQ to SQL method so this does not happen?
Also, to help me grasp this, why does the previous code not work and this one does?
public IQueryable<Story> FindAllStories(){
var stories = (from s in db.Stories
orderby s.DateEntered descending
select s);
return stories;
}
Update
I'm beginning to think the way to accomplish this (verified it works) is to create a POCO called UserStory. The new class has 2 properties: one of type Story and the other string UserName. I can then return an IQueryable of UserStory without a problem.
That's great; however, I still don't get why that method would work and my other doesn't. The other is adding a property of string UserName to my partial class Story and passing that object between layers. What's the difference?

The following link is to a blog post tat describes an issue similar to yours. It seems like the solution was to return a type that inherets from Story instead of a Story type:
http://devlicio.us/blogs/derik_whittaker/archive/2008/04/25/linq2sql-explicit-construction-of-entity-exception.aspx
Hope this helps.

Related

Laravel Query Builder Issue

I'm trying to make it so that the items pulled from the database are only from the current month, however when I do this using various methods it throws an error (which I can't debug due to a the issue mentioned here). In the code below if I just simply paginate the full results it works fine, but when I start to use query builder methods it gives an error, does anybody have any idea why this error is occurring?
public function index()
{
// $trades=Trade::paginate(10);
$currentMonth = date('m');
$trades = DB::table('trades')->whereMonth('date', $currentMonth)->paginate(10);
// dd($trades);
$pastwinners=Winner::paginate(10);
return view('raffle', compact('pastwinners'), compact('trades'));
}
As you can see above the $pastwinners variable and the first $trades variable provide the proper values, but when I'm trying to select only the ones from this month (using the 'date' field) it seems to break.
Try this one. And if you want to paginate your results, do not forget to add pagination links to your view. Also do not forget the import Carbon in your controller class.
https://laravel.com/docs/5.6/pagination
public function index()
{
$trades = Trade::whereMonth('date' , Carbon::today()->month)->paginate();
$pastwinners = Winner::all();
return view('raffle', compact('pastwinners', 'trades');
}

Entity Framework 4.0 Code-First Dynamic Query

I would like to query a table based on a list of KeyValuePair. With a Model-First approach, I could do the following:
var context = new DataContext();
var whereClause = new StringBuilder();
var objectParameters = new List<ObjectParameter>();
foreach(KeyValuePair<string, object> pair in queryParameters)
{
if (whereClause.Length > 0)
whereClause.Append(" AND ");
whereClause.Append(string.Format("it.[{0}] = #{0}", pair.Key));
parameters.Add(new ObjectParameter(pair.Key, pair.Value));
}
var result = context.Nodes.Where(whereClause.ToString(), parameters.ToArray());
Now I'm using a Code-First approach and this Where method is not available anymore. Fortunately, I saw an article somewhere (I can't remember anymore) which suggested that I could convert the DbContext to a IObjectContextAdapter then call CreateQuery like this:
var result = ((IObjectContextAdapter)context)
.ObjectContext.CreateQuery<Node>(whereClause.ToString(), parameters.ToArray());
Unfortunately, this throws an error:
'{ColumnName}' could not be resolved in the current scope or context. Make sure that all referenced variables are in scope, that required schemas are loaded, and that namespaces are referenced correctly.
Where {ColumnName} is the column specified in the whereClause.
Any ideas how I can dynamically query a DbSet given a list of key/value pairs? All help will be greatly appreciated.
I think your very first problem is that in the first example you are using Where on the entity set but in the second example you are using CreateQuery so you must pass full ESQL query and not only where clause! Try something like:
...
.CreateQuery<Node>("SELECT VALUE it FROM ContextName.Nodes AS it WHERE " + yourWhere)
The most problematic is full entity set name in FROM part. I think it is defined as name of the context class and name of the DbSet exposed on the context. Another way to do it is creating ObjectSet:
...
.ObjectContext.CreateObjectSet<Node>().Where(yourWhere)

why this Linq to sql function return nulls?

I am new to linq to sql
I wrote this function:
public ICollection<ICustomer> GetAll()
{
DataClasses1DataContext context = new DataClasses1DataContext();
var customers = from customer in context.Customers select customer;
return customers.ToList().Cast<ICustomer>().ToList();
}
But it always return list of null values.
The database contain 3 records "filled with data" but this function return 3 nulls.
how to fix that?
It may not be able to cast the results properly, have you made your partial Customer object implement ICustomer? If not, that is the reason.
Also you don't have to bring it to a list twice, or even once for that matter since you aren't returning a list, it might be more appropriate to change your signature to List or IEnumerable depending on your usage.
You can test whether or not the cast is succeeding by doing a simple test.
DataClasses1DataContext context = new DataClasses1DataContext();
var customers = from customer in context.Customers select customer;
int numberOfCustomers = customers.Count();
var myCustomers = customers.Cast<ICustomer>(); //you could also do .OfType<ICustomer>();
int numberOfICustomers = myCustomers.Count();
If numberOfCustomers is 3 and numberOfICustomers is 0 then you know that was the issue.
Your problem is almost certainly at the .Cast() method (confirm this by stepping through your code & ensuring that customers is populated correctly).
Does the Customer object implement the ICustomer interface? It sounds like an obvious thing to check but that would be a likely problem.

Need help building LINQ to SQL Expression

I need to translate the following Code to an Expression and I will explain why:
results = results.Where(answer => answer.Question.Wording.Contains(term));
results is IQueryable<ISurveyAnswer>
Question is ISurveyQuestion
Wording is String
The problem is, Question is not always the name of the LINQ to SQL property.
This will give me the PropertyInfo for the actual ISurveyQuestion property
private static PropertyInfo FindNaturalProperty<TMemberType>(Type search)
{
IDictionary<string,PropertyInfo> properties = new Dictionary<string,PropertyInfo>();
search.GetProperties().Each(prop =>
{
if (null != prop.PropertyType.GetInterface(typeof(TMemberType).Name))
properties.Add(prop.Name, prop);
});
if (properties.Count < 1) throw new ArgumentException(String.Format("{0} has no properties of type {1}", search.Name, typeof(TMemberType).Name));
if (properties.Count == 1) return properties.Values.First();
search.GetInterfaces().Each(inter =>
{
inter.GetProperties().Each(prop =>
{
if (null != prop.PropertyType.GetInterface(typeof(TMemberType).Name))
properties.Remove(prop.Name);
});
});
if (properties.Count < 1) throw new ArgumentException(String.Format("{0} has no properties of type {1} that are not members of an interface", search.Name, typeof(TMemberType).Name));
if (properties.Count > 1) throw new AmbiguousMatchException(String.Format("{0} has more than one property that are of type {1} and are not members of an interface", search.Name, typeof(TMemberType).Name));
return properties.Values.First();
}
Once I have the PropertyInfo how do I translate that to an Expression Tree?
EDIT:
What I basically need is:
results = results.Where(answer => answer.GetQuestionProperty().GetValue(answer).Wording.Contains(term));
But that doesn't work so I need to build the Expression Tree myself, for linq-to-sql.
Reading the question I think what you're after is Dynamic Linq - which is a helper library to let you build Linq queries dynamically (!) using strings as opposed to at design time. That means that if you can get your property name you should be able create your query on the fly.
ScottGu has an article here
What your trying to do is create a dynamic query and you want the action tables / properties your query against to be dynamic as well. I am not sure if this is easily possible based on how you want to use it.
Check out ScottGu's blog post:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
and
Check out Rick Strahl's blog post:
http://www.west-wind.com/Weblog/posts/143814.aspx
http://www.linqpad.net/
linqpad will convert it for you.

C# LINQ problem with case sensitive

I have this:
var sortName = Request.Params["sortName"];
var query = Request.Params["query"];
Func<UsuarioEndereco, bool> whereClause = (uen => uen.GetPropValue<string>(sortName).Contains(query));
The "uen.GetPropValue<string>(sortName)" will be filled dynamically with the sortName the user typed in the page.
For example, if an user looks for a person named "Joe", the snippet will be:
(uen => uen.namePerson.Contains(Joe))
But, I'm having problems with LINQ Case-sensitive searches. If I type "Joe", I will something. On the other hand, If I type "joe", it bring nothing.
How can I make this "Contains(sortName)" works with Case-Insensitive?? I've tried some things with String.Comparer but it reports errors on build solution.
Thanks!!
I believe the following will generate proper SQL:
uen=>(uen.GetPropValue<string>(sortName)).ToLower().Contains(query.ToLower()))
If this is really LINQ-to-SQL, try using the SqlMethods.Like method instead of String.Contains.
However, I think the problem is that this is NOT LINQ-to-SQL, because you are using delegates instead of Expression trees. So this is being brought client side, then executed locally ("LINQ to Objects"). Hence, String.Contains is doing what it does locally.
In that way, James's answer is correct, since he's calling ToLower() on both the value and the query. (Although, beware of culture issues -- perhaps specify which culture you want.)
You could also use the String.IndexOf Method (String, Int32, StringComparison) (http://msdn.microsoft.com/en-us/library/ms224424.aspx). This method allows you to specify if the matching should be done case-sensitively or not, and if it should use a Invariant culture or not.
So in your example:
Func<UsuarioEndereco, bool> whereClause = (uen => uen.GetPropValue<string>(sortName).IndexOf(query, 0, StringComparison.OrdinalIgnoreCase));
I'm not commenting on if this is a better solution than the one provided by James Curran. It could or could not be, performance wise.
This is the entire code:
var sortOrder = Request.Params["sortorder"];
var sortName = Request.Params["sortname"];
var query = Request.Params["query"];
IEnumerable<UsuarioEndereco> pagedEndereco;
Func<UsuarioEndereco, bool> whereClause = (uen => uen.GetPropValue<string>(sortName).Contains(query));
pagedEndereco = sortOrder.Equals("asc", StringComparison.CurrentCultureIgnoreCase) ?
_agendaServico.SelecionaUsuarioEnderecos(u.codUsuario).Where(whereClause).OrderByDescending(uen => uen.GetPropValue<IComparable>(sortName)) :
_agendaServico.SelecionaUsuarioEnderecos(u.codUsuario).Where(whereClause).OrderBy(uen => uen.GetPropValue<IComparable>(sortName));
The Extension Method GetPropValue is:
public static T GetPropValue<T>(this object component, string propertyName)
{
return (T)TypeDescriptor.GetProperties(component)[propertyName].GetValue(component);
}