public static object ExecuteScalar(string SQL)
{
try
{
var A = new EGModel.EGEntity().Connection;
var command = ((EntityConnection)(A)).StoreConnection.CreateCommand();
command.CommandType = System.Data.CommandType.Text;
command.CommandText = SQL;
if (((EntityConnection)(A)).StoreConnection.State == System.Data.ConnectionState.Closed)
((EntityConnection)(A)).StoreConnection.Open();
return command.ExecuteScalar();
}
catch { return null; }
}
public object MFICHE(int ID)
{
var i = from b in IConnection.EGEntity().fiche
where (m.ID== ID)
select new { b.Date, m.Name, Addresss = IConnection.ExecuteScalar("SELECT main.F_ADDRESS(4588)") };
return i;
}
I am getting error:
LINQ to Entities does not recognize the method 'System.Object ExecuteScalar(System.String)' method, and this method cannot be translated into a store expression.
Why i am getting error?
But Addresss = "ASASAS" is runing?
The problem is that the expression tree generated from your query includes a call to your ExecuteScalar method - which the Entity Framework expression parser doesn't know anything about. It doesn't look inside that method to see what it's doing - it just knows that the call exists, and fails because it can't translate it.
You wouldn't normally want to execute a separate SQL statement for each result returned from a query? You've got an obvious "N+1 selects" problem.
If you know you've only got a single result (due to the ID constraint) you could fetch the relevant data into an object and then execute the second query:
public object MFICHE(int ID)
{
var query = from b in IConnection.EGEntity().fiche
where b.ID == ID
select new { b.Date, b.Name };
// You only expect a single result, right?
var result = query.Single();
// Shouldn't this be using something to do with the result?
var address = IConnection.ExecuteScalar("SELECT main.F_ADDRESS(4588)");
return new { result.Date, result.Name, Address = address };
}
As an aside, it's very odd to have static methods in a type beginning with I, which would usually be an interface. Additionally, this code:
catch { return null; }
is horrible - you should catch specific exceptions, log them, and normally rethrow them. It's almost never appropriate to just carry on as if nothing had gone wrong.
Related
Continued from this solution (thanks Daniel Hilgarth)
return db.Tags.Select(ConstructTagItem());
And the method:
private Expression<Func<Tag, TagItem>> ConstructTagItem()
{
return a => new TagItem {ID = a.Id Name = a.Name };
}
Additional question, how do i use it in this scenario then:
return (from c in db.News_Attributes
select new NewsTagItem
{
NewsID = c.News_Id,
TagID = c.Tag_Id,
Content = c.Content,
Attribute = new TagItem
{
ID = c.Tag.Id,
Name = c.Tag.Name
}
});
I want to reuse the method from the other answer:
private Expression<Func<Tag, TagItem>> ConstructTagItem
{
get { return a => new TagItem {ID = a.Id Name = a.Name }; }
}
To construct something like this:
return (from c in db.News_Attributes
select new NewsTagItem
{
NewsID = c.News_Id,
TagID = c.Tag_Id,
Content = c.Content,
Attribute = ConstructTagItem // TODO: need some way to tell the method that it should use c.Tag
});
I want to use the same construction of my TagItem multiple places. This will make it easier if the object changes, and save lines.
I guess that I somehow have to define that it is c.Tag into ConstructTagItem(), but I really don't know much about expressions yet. So i hope that someone is able to help?
I'm not sure if I have a full handle on what you're trying to do. What does "use it in this scenario" mean? Can you mimic your previous technique with something like this in order to encapsulate creating a NewsTagItem, or is it something else you're trying to achieve?
private Expression<Func<News_Attribute, NewsTagItem>> ConstructNewsTagItem()
{
return c => new NewsTagItem
{
NewsID = c.News_Id,
Name = a.Name
TagID = c.Tag_Id,
Content = c.Content,
Attribute = new TagItem
{
ID = c.Tag.Id,
Name = c.Tag.Name
}
}
});
db.News_Attributes.Select(ConstructNewsTagItem());
UPDATE:
OK, we can't directly re-use your ConstructTagItem() because it returns an expression containing a function. What you need is a MemberInitExpression. It's a little tricky to create by hand, but we can use a trick whereby we create the expression we desire wrapped with a thunk, so that it isn't evaluated, and then grab the body of the thunk to get the expression. See the snippet below:
private Expression GenerateNewTagItem(TagItem c)
{
Expression<Func<TagItem>> expr = () => new TagItem { ID = c.ID, Name = c.Name };
return expr.Body;
}
With this function, we can now do pretty much exactly what you want:
return (from c in db.News_Attributes
select new NewsTagItem
{
NewsID = c.News_Id,
TagID = c.Tag_Id,
Content = c.Content,
Attribute = GenerateNewTagItem(c)
});
Pretty neat right?
I'm building a LINQ-based query generator.
One of the features is being able to specify an arbitrary server-side projection as part of the query definition. For example:
class CustomerSearch : SearchDefinition<Customer>
{
protected override Expression<Func<Customer, object>> GetProjection()
{
return x => new
{
Name = x.Name,
Agent = x.Agent.Code
Sales = x.Orders.Sum(o => o.Amount)
};
}
}
Since the user must then be able to sort on the projection properties (as opposed to Customer properties), I recreate the expression as a Func<Customer,anonymous type> instead of Func<Customer, object>:
//This is a method on SearchDefinition
IQueryable Transform(IQueryable source)
{
var projection = GetProjection();
var properProjection = Expression.Lambda(projection.Body,
projection.Parameters.Single());
In order to return the projected query, I'd love to be able to do this (which, in fact, works in an almost identical proof of concept):
return Queryable.Select((IQueryable<TRoot>)source, (dynamic)properProjection);
TRoot is the type parameter in SearchDefinition. This results in the following exception:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
The best overloaded method match for
'System.Linq.Queryable.Select<Customer,object>(System.Linq.IQueryable<Customer>,
System.Linq.Expressions.Expression<System.Func<Customer,object>>)'
has some invalid arguments
at CallSite.Target(Closure , CallSite , Type , IQueryable`1 , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet]
(CallSite site, T0 arg0, T1 arg1, T2 arg2)
at SearchDefinition`1.Transform(IQueryable source) in ...
If you look closely, it's inferring the generic parameters incorrectly: Customer,object instead of Customer,anonymous type, which is the actual type of the properProjection expression (double-checked)
My workaround is using reflection. But with generic arguments, it's a real mess:
var genericSelectMethod = typeof(Queryable).GetMethods().Single(
x => x.Name == "Select" &&
x.GetParameters()[1].ParameterType.GetGenericArguments()[0]
.GetGenericArguments().Length == 2);
var selectMethod = genericSelectMethod.MakeGenericMethod(source.ElementType,
projectionBody.Type);
return (IQueryable)selectMethod.Invoke(null, new object[]{ source, projection });
Does anyone know of a better way?
Update: the reason why dynamic fails is that anonymous types are defined as internal. That's why it worked using a proof-of-concept project, where everything was in the same assembly.
I'm cool with that. I'd still like to find a cleaner way to find the right Queryable.Select overload.
The fix is so simple it hurts:
[assembly: InternalsVisibleTo("My.Search.Lib.Assembly")]
Here's my test as requested. This on a Northwind database and this works fine for me.
static void Main(string[] args)
{
var dc = new NorthwindDataContext();
var source = dc.Categories;
Expression<Func<Category, object>> expr =
c => new
{
c.CategoryID,
c.CategoryName,
};
var oldParameter = expr.Parameters.Single();
var parameter = Expression.Parameter(oldParameter.Type, oldParameter.Name);
var body = expr.Body;
body = RebindParameter(body, oldParameter, parameter);
Console.WriteLine("Parameter Type: {0}", parameter.Type);
Console.WriteLine("Body Type: {0}", body.Type);
var newExpr = Expression.Lambda(body, parameter);
Console.WriteLine("Old Expression Type: {0}", expr.Type);
Console.WriteLine("New Expression Type: {0}", newExpr.Type);
var query = Queryable.Select(source, (dynamic)newExpr);
Console.WriteLine(query);
foreach (var item in query)
{
Console.WriteLine(item);
Console.WriteLine("\t{0}", item.CategoryID.GetType());
Console.WriteLine("\t{0}", item.CategoryName.GetType());
}
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
Console.WriteLine();
}
static Expression RebindParameter(Expression expr, ParameterExpression oldParam, ParameterExpression newParam)
{
switch (expr.NodeType)
{
case ExpressionType.Parameter:
var parameterExpression = expr as ParameterExpression;
return (parameterExpression.Name == oldParam.Name)
? newParam
: parameterExpression;
case ExpressionType.MemberAccess:
var memberExpression = expr as MemberExpression;
return memberExpression.Update(
RebindParameter(memberExpression.Expression, oldParam, newParam));
case ExpressionType.AndAlso:
case ExpressionType.OrElse:
case ExpressionType.Equal:
case ExpressionType.NotEqual:
case ExpressionType.LessThan:
case ExpressionType.LessThanOrEqual:
case ExpressionType.GreaterThan:
case ExpressionType.GreaterThanOrEqual:
var binaryExpression = expr as BinaryExpression;
return binaryExpression.Update(
RebindParameter(binaryExpression.Left, oldParam, newParam),
binaryExpression.Conversion,
RebindParameter(binaryExpression.Right, oldParam, newParam));
case ExpressionType.New:
var newExpression = expr as NewExpression;
return newExpression.Update(
newExpression.Arguments
.Select(arg => RebindParameter(arg, oldParam, newParam)));
case ExpressionType.Call:
var methodCallExpression = expr as MethodCallExpression;
return methodCallExpression.Update(
RebindParameter(methodCallExpression.Object, oldParam, newParam),
methodCallExpression.Arguments
.Select(arg => RebindParameter(arg, oldParam, newParam)));
default:
return expr;
}
}
Also, dynamic method resolution doesn't really do much for you in this case as there are only two very distinct overloads of Select(). Ultimately you just need to remember that you won't have any static type checking on your results since you don't have any static type information. With that said, this will also work for you (using the above code example):
var query = Queryable.Select(source, expr).Cast<dynamic>();
Console.WriteLine(query);
foreach (var item in query)
{
Console.WriteLine(item);
Console.WriteLine("\t{0}", item.CategoryID.GetType());
Console.WriteLine("\t{0}", item.CategoryName.GetType());
}
I have a collection of CLR objects. The class definition for the object has three properties: FirstName, LastName, BirthDate.
I have a string that reflects the name of the property the collection should be sorted by. In addition, I have a sorting direction. How do I dynamically apply this sorting information to my collection? Please note that sorting could be multi-layer, so for instance I could sort by LastName, and then by FirstName.
Currently, I'm trying the following without any luck:
var results = myCollection.OrderBy(sortProperty);
However, I'm getting a message that says:
... does not contain a defintion for 'OrderBy' and the best extension method overload ... has some invalid arguments.
Okay, my argument with SLaks in his comments has compelled me to come up with an answer :)
I'm assuming that you only need to support LINQ to Objects. Here's some code which needs significant amounts of validation adding, but does work:
// We want the overload which doesn't take an EqualityComparer.
private static MethodInfo OrderByMethod = typeof(Enumerable)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(method => method.Name == "OrderBy"
&& method.GetParameters().Length == 2)
.Single();
public static IOrderedEnumerable<TSource> OrderByProperty<TSource>(
this IEnumerable<TSource> source,
string propertyName)
{
// TODO: Lots of validation :)
PropertyInfo property = typeof(TSource).GetProperty(propertyName);
MethodInfo getter = property.GetGetMethod();
Type propType = property.PropertyType;
Type funcType = typeof(Func<,>).MakeGenericType(typeof(TSource), propType);
Delegate func = Delegate.CreateDelegate(funcType, getter);
MethodInfo constructedMethod = OrderByMethod.MakeGenericMethod(
typeof(TSource), propType);
return (IOrderedEnumerable<TSource>) constructedMethod.Invoke(null,
new object[] { source, func });
}
Test code:
string[] foo = new string[] { "Jon", "Holly", "Tom", "William", "Robin" };
foreach (string x in foo.OrderByProperty("Length"))
{
Console.WriteLine(x);
}
Output:
Jon
Tom
Holly
Robin
William
It even returns an IOrderedEnumerable<TSource> so you can chain ThenBy clauses on as normal :)
You need to build an Expression Tree and pass it to OrderBy.
It would look something like this:
var param = Expression.Parameter(typeof(MyClass));
var expression = Expression.Lambda<Func<MyClass, PropertyType>>(
Expression.Property(param, sortProperty),
param
);
Alternatively, you can use Dynamic LINQ, which will allow your code to work as-is.
protected void sort_grd(object sender, GridViewSortEventArgs e)
{
if (Convert.ToBoolean(ViewState["order"]) == true)
{
ViewState["order"] = false;
}
else
{
ViewState["order"] = true;
}
ViewState["SortExp"] = e.SortExpression;
dataBind(Convert.ToBoolean(ViewState["order"]), e.SortExpression);
}
public void dataBind(bool ord, string SortExp)
{
var db = new DataClasses1DataContext(); //linq to sql class
var Name = from Ban in db.tbl_Names.AsEnumerable()
select new
{
First_Name = Ban.Banner_Name,
Last_Name = Ban.Banner_Project
};
if (ord)
{
Name = BannerName.OrderBy(q => q.GetType().GetProperty(SortExp).GetValue(q, null));
}
else
{
Name = BannerName.OrderByDescending(q => q.GetType().GetProperty(SortExp).GetValue(q, null));
}
grdSelectColumn.DataSource = Name ;
grdSelectColumn.DataBind();
}
you can do this with Linq
var results = from c in myCollection
orderby c.SortProperty
select c;
For dynamic sorting you could evaluate the string i.e. something like
List<MyObject> foo = new List<MyObject>();
string sortProperty = "LastName";
var result = foo.OrderBy(x =>
{
if (sortProperty == "LastName")
return x.LastName;
else
return x.FirstName;
});
For a more generic solution see this SO thread: Strongly typed dynamic Linq sorting
For this sort of dynamic work I've been using the Dynamic LINQ library which makes this sort of thing easy:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
http://msdn2.microsoft.com/en-us/vcsharp/bb894665.aspx
You can copy paste the method I post in that answer, and change the signature/method names:
How to make the position of a LINQ Query SELECT variable
You can actually use your original line of code
var results = myCollection.OrderBy(sortProperty);
simply by using the System.Linq.Dynamic library.
If you get a compiler error (something like cannot convert from or does not contain a definition...) you may have to do it like this:
var results = myCollection.AsQueryable().OrderBy(sortProperty);
No need for any expression trees or data binding.
You will need to use reflection to get the PropertyInfo, and then use that to build an expression tree. Something like this:
var entityType = typeof(TEntity);
var prop = entityType.GetProperty(sortProperty);
var param = Expression.Parameter(entityType, "x");
var access = Expression.Lambda(Expression.MakeMemberAccess(param, prop), param);
var ordered = (IOrderedQueryable<TEntity>) Queryable.OrderBy(
myCollection,
(dynamic) access);
Ok, I'll admit that I don't entirely "get" lambda expressions and LINQ expression trees yet; a lot of what I'm doing is cutting and pasting and seeing what works. I've looked over lots of documentation, but I still haven't found the my "aha" moment yet.
With that being said...
I'm attempting to dynamically add a GroupBy expression to my Linq expression. I followed the question here:
Need help creating Linq.Expression to Enumerable.GroupBy
and tried to implement what I saw there.
First off, I've got entity classes for my database, and a table calledObjCurLocViewNormalized
I've got an method that does the initial call,
public IQueryable<ObjCurLocViewNormalized> getLocations()
{
IQueryable<ObjCurLocViewNormalized> res = (from loc in tms.ObjCurLocViewNormalized
select loc);
return res;
}
so I can call:
IQueryable<MetAmericanLinqDataModel.ObjCurLocViewNormalized> locations = american.getLocations();
No problem so far.
Now, I want to group by an arbitrary column, with a call like this:
var grouped = locations.addGroupBy(childLocationFieldName);
Right now, I have a method :
static public System.Linq.IQueryable<System.Linq.IGrouping<string, TResult>> addGroupBy<TResult>(this IQueryable<TResult> query, string columnName)
{
var providerType = query.Provider.GetType();
// Find the specific type parameter (the T in IQueryable<T>)
var iqueryableT = providerType.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(IQueryable<>), null).FirstOrDefault();
var tableType = iqueryableT.GetGenericArguments()[0];
var tableName = tableType.Name;
var data = Expression.Parameter(iqueryableT, "query");
var arg = Expression.Parameter(tableType, tableName);
var nameProperty = Expression.PropertyOrField(arg, columnName);
var lambda = Expression.Lambda<Func<TResult, string>>(nameProperty, arg);
var expression = Expression.Call(typeof(Enumerable),
"GroupBy",
new Type[] { tableType, typeof(string) },
data,
lambda);
var predicate = Expression.Lambda<Func<TResult, String>>(expression, arg); // this is the line that produces the error I describe below
var result = query.GroupBy(predicate).AsQueryable();
return result;
}
All this compiles ok, but when I run it, I get the error:
System.ArgumentException: Expression of type 'System.Collections.Generic.IEnumerable`1[System.Linq.IGrouping`2[System.String,MetAmericanLinqDataModel.ObjCurLocViewNormalized]]' cannot be used for return type 'System.String'
and the error comes from this line:
var predicate = Expression.Lambda<Func<TResult, String>>(expression, arg);
I'm copying and adapting this code from successful work I did in dynamically added Where clauses to an expression. So I'm sort of stabbing in the dark here.
If anyone out there can help to shed some light on this, Obviously posting complete working code and doing all my thinking for me would be great :), but if you could just lay out just why this is wrong, or how to wrap my head around these concepts, that would be great. If you can point to documentation that can really help be bridge the gap between the basics of lambda expressions, and building dynamic expression trees, that would be great. There's obviously big holes in my knowledge, but I think this information could be useful to others.
thanks everyone for your time, and of course if I find the answer elsewhere, I'll post it here.
Thanks again.
Don
The solution should be pretty simple:
public static IQueryable<IGrouping<TColumn, T>> DynamicGroupBy<T, TColumn>(
IQueryable<T> source, string column)
{
PropertyInfo columnProperty = typeof(T).GetProperty(column);
var sourceParm = Expression.Parameter(typeof(T), "x");
var propertyReference = Expression.Property(sourceParm, columnProperty);
var groupBySelector = Expression.Lambda<Func<T, TColumn>>(propertyReference, sourceParm);
return source.GroupBy(groupBySelector);
}
Assuming a sample class like this:
public class TestClass
{
public string TestProperty { get; set; }
}
You invoke it like this:
var list = new List<TestClass>();
var queryable = list.AsQueryable();
DynamicGroupBy<TestClass, string>(queryable, "TestProperty");
All that you need to do to make it work is the following:
static public IQueryable<IGrouping<TValue, TResult>> addGroupBy<TValue, TResult>(
this IQueryable<TResult> query, string columnName)
{
var providerType = query.Provider.GetType();
// Find the specific type parameter (the T in IQueryable<T>)
const object EmptyfilterCriteria = null;
var iqueryableT = providerType
.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(IQueryable<>), EmptyfilterCriteria)
.FirstOrDefault();
Type tableType = iqueryableT.GetGenericArguments()[0];
string tableName = tableType.Name;
ParameterExpression data = Expression.Parameter(iqueryableT, "query");
ParameterExpression arg = Expression.Parameter(tableType, tableName);
MemberExpression nameProperty = Expression.PropertyOrField(arg, columnName);
Expression<Func<TResult, TValue>> lambda = Expression.Lambda<Func<TResult, TValue>>(nameProperty, arg);
//here you already have delegate in the form of "TResult => TResult.columnName"
return query.GroupBy(lambda);
/*var expression = Expression.Call(typeof(Enumerable),
"GroupBy",
new Type[] { tableType, typeof(string) },
data,
lambda);
var predicate = Expression.Lambda<Func<TResult, String>>(expression, arg); // this is the line that produces the error I describe below
var result = query.GroupBy(predicate).AsQueryable();
return result;*/
}
And you will call you expression in the following manner:
var grouped = locations.addGroupBy<string, ObjCurLocViewNormalized>(childLocationFieldName);
First generic parameter "string" us used for saying explicilty what type of elements you a grouping on. For example you can group by "int" field and method call will be like following:
var grouped = locations.addGroupBy<int, ObjCurLocViewNormalized>(someFieldNameWithTheTypeOfInt);
Edit
Just to finish this solution your way:
//return query.GroupBy(lambda);
MethodCallExpression expression = Expression.Call(typeof (Enumerable),
"GroupBy",
new[] { typeof(TResult), typeof(TValue) },
data,
lambda);
var result = Expression.Lambda(expression, data).Compile().DynamicInvoke(query);
return ((IEnumerable<IGrouping<TValue, TResult>>)result).AsQueryable();
I am using SubSonic 3.0.0.3 along with the Linq T4 Templates. My ProjectRepository, for example, has the following two methods:
public int Add(Project item)
{
int result = 0;
ISqlQuery query = BuildInsertQuery(item);
if (query != null)
{
result = query.Execute();
}
return result;
}
private ISqlQuery BuildInsertQuery(Project item)
{
ITable tbl = FindTableByClassName();
Insert query = null;
if (tbl != null)
{
Dictionary<string, object> hashed = item.ToDictionary();
query = new Insert(_db.Provider).Into<Project>(tbl);
foreach (string key in hashed.Keys)
{
IColumn col = tbl.GetColumn(key);
if (col != null)
{
if (!col.AutoIncrement)
{
query.Value(key, hashed[key]);
}
}
}
}
return query;
}
Along with performing the insert (which works great), I'd really like to get the value of the auto-incrementing ProjectId column. For the record, this column is both the primary key and identity column. Is there perhaps a way to append "SELECT SCOPE_IDENTITY();" to the query or maybe there's an entirely different approach which I should try?
You can do this with the ActiveRecord templates which does all of the wiring above for you (and also has built-in testing). In your scenario, the Add method would have one line: Project.Add() and it would return the new id.
For your needs, you can try this:
var cmd=query.GetCommand();
cmd.CommandSql+=";SELECT SCOPE_IDENTITY() as newid";
var newID=query.Provider.ExecuteScalar(cmd);
That should work..
*Edit - you can create an ExtensionMethod for this on ISqlQuery too, to save some writing...