How to convert GetFuncType using LINQBridge - linq

I have a client using .net and I am using LINQBride with some existing code that uses LINQ. I don't really know much about linq but am wondering if there is a quick conversion using LINQBridge for this expression
DynamicMethod.CreateDelegate(Expression.GetFuncType(typeof(IDataReader), type));
Thanks

LinqBridge only implements Linq to Objects, it doesn't support expressions. But you can achieve something similar using reflection:
static Type GetFuncType(params Type[] typeArgs)
{
string typeName = "System.Func`" + typeArgs.Length;
Type genericTypeDef = typeof(Func<>).Assembly.GetType(typeName); // Func<,...,>
return genericTypeDef.MakeGenericType(typeArgs); // Func<TArg1, ..., TResult>
}

Related

How to invoke a UDF with LINQ in Cosmos DB SDK v3?

The documentation for LINQ to SQL translation for Cosmos DB states:
User-Defined Function Extension function: Supports translation from the stub method UserDefinedFunctionProvider.Invoke to the corresponding user-defined function.
However, this function is not publicly accessible in .NET SDK v3 (though it is in v2). So what's the workaround until the bug has been fixed?
There are several workarounds:
Don't use LINQ.
Use LINQ but without calling UDFs, then get the query string using query.ToQueryDefinition.QueryText and manipulate it to insert UDF calls at the places you need them, and then evaluate the SQL string (yuck!).
Hack it. First add a dummy method:
public static object Invoke(string udfName, object[] arguments) { return null; }
Use this method in your lambda expressions whenever you would otherwise use UserDefinedFunctionProvider.Invoke. Implement an ExpressionVisitor that replaces all occurrences of MethodCallExpression mce where mce.Method matches the dummy method by
Expression.Call(null, udfMethod, mce.Arguments[0], mce.Arguments[1])
where udfMethod is
MethodInfo udfMethod = typeof(CosmosClient).Assembly
.GetType("Microsoft.Azure.Cosmos.Linq.UserDefinedFunctionProvider", throwOnError: true)
.GetMethod("Invoke", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
Use the resulting expression in your Where, Select etc.
(Add a unit test to check when the bug has been fixed and the hack can be removed.)
I am using the Microsoft.Azure.Cosmos 3.22.1 SDK for my example with the UDF (user defined functions) and it worked fine.
I used the example from microsoft.
It is of course also possible to use the UDF in combination with where clauses.
CosmosClient client = new(endpoint, key);
IQueryable<Product> queryable = client
.GetContainer("database", "products")
.GetItemLinqQueryable<Product>()
.Select(b => new Product{ id = b.id, price = b.price, priceWithTax = CosmosLinq.InvokeUserDefinedFunction("tax", b.price).ToString() });
var productIterator = queryable.ToFeedIterator<Product>();
while (productIterator.HasMoreResults)
{
var responseMessage = await productIterator.ReadNextAsync();
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(responseMessage));
}

Dynamic Repository With Dynamic Methods

Inspired by this post dynamic-repositories-in-lightspeed I am trying to build my own like this.
I have a abstract GenericRepository like this. I have omitted most of the code for simplicity (Its just normal Add/Update/Filtering methods).
public abstract class GenericRepository<TEntity, TContext> :
DynamicObject,
IDataRepository<TEntity>
where TEntity : class, new()
where TContext : DbContext, new()
{
protected TContext context;
protected DbSet<TEntity> DbSet;
}
As you can see, my abstract GenericRepository extends from DynamicObject to support dynamic repositories.
I also have a abstract UnitOfWork implementation which generated a repository for a given entity at runtime like this. Again, base classes and other details are irrelevant for the question, but I'm happy to provide them if you require.
public abstract class UnitOfWorkBase<TContext> : IUnitOfWork
where TContext : DbContext, new()
{
public abstract IDataRepository<T> Repository<T>()
where T : class, IIdentifiableEntity, new();
// Code
}
Following class implements abstract method of the above class.
public class MyUnitOfWorkBase : UnitOfWorkBase<MyDataContext>
{
public override IDataRepository<T> Repository<T>()
{
if (Repositories == null)
Repositories = new Hashtable();
var type = typeof(T).Name;
if (!Repositories.ContainsKey(type))
{
var repositoryType = typeof(GenericRepositoryImpl<,>);
var genericType = repositoryType.MakeGenericType(typeof(T), typeof(InTeleBillContext));
var repositoryInstance = Activator.CreateInstance(genericType);
Repositories.Add(type, repositoryInstance);
}
return (IDataRepository<T>)Repositories[type];
}
}
Now, whenever I want to create a dynamic repository for basic CRUD functions, I can do it like this.
var uow = new MyUnitOfWorkBase();
var settingsRepo = uow.Repository<Settings>();
var settingsList = settingsRepo.Get().ToList();
Now, What I want to do is something like this.
dynamic settingsRepo = uow.Repository<Settings>();
var result = settingsRepo.FindSettingsByCustomerNumber(774278L);
Here, FindSettingsByCustomerNumber() is a dynamic method. I resolve this method using this code.
public class GenericRepositoryImpl<TEntity, TContext> :
GenericRepository<TEntity, TContext>
where TEntity : class, IIdentifiableEntity, new()
where TContext : DbContext, new()
{
public override bool TryInvokeMember(InvokeMemberBinder binder,
object[] args, out object result)
{
// Crude parsing for simplicity
if (binder.Name.StartsWith("Find"))
{
int byIndex = binder.Name.IndexOf("By");
if (byIndex >= 0)
{
string collectionName = binder.Name.Substring(4, byIndex - 4);
string[] attributes = binder.Name.Substring(byIndex + 2)
.Split(new[] { "And" }, StringSplitOptions.None);
var items = DbSet.ToList();
Func<TEntity, bool> predicate = entity => entity.GetType().GetProperty(attributes[0]).GetValue(entity).Equals(args[0]);
result = items.Where(predicate).ToList();
return true;
}
}
return base.TryInvokeMember(binder, args, out result);
}
}
This is the problem I am having.
using this line var items = DbSet.ToList(); works well, but if I were to query a large table with 1000's of data, then performance issues occur.
If I directly try to use the IQueryble interface and call it like this
Func predicate = entity => entity.GetType().GetProperty(attributes[0]).GetValue(entity).Equals(args[0]);
result = DbSet.Where(predicate).ToList();
It gives me an error saying there is no method GetProperty() in LINQ to Entities.
Is it possible to make it work using LINQ to Entities?
You need to know that LINQ-to-Entities needs to convert your expression (given by the predicate) into a SQL query. entity is replaced by the database column. Additionally LINQ2Entities supports various expressions (e.g. EqualExpression, etc.). However it cannot support the whole .NET Framework. Especially: what should GetType() on a database column return?
Therefore you need to use the Expresson API to generate the predicate and use only expressions supported by LINQ2Entities. For example: Use a MemberAccess expression for accessing a property (LINQ2Entities is able to map that to an SQL query).
Hint: we are doing predicate generation for Entity Framework and had to overcome some additional problems which we could solve using the library LinqKit.
If you do not know about the .NET Expression API yet, you need to gather skills in that area before you can resume your dynamic repository idea.
BTW: I don't think that it is a very good idea to have this kind of automatic calls. They are not refactoring safe (i.e. what if you rename the DB column? All your method calls run into problems, and it is not detectable by the compiler).
I would use it only to generate predicates for Where() clauses from Filter-like DTO types.
Unusual pattern - dynamic methods on a repository patterns.But that is another topic.
Dynamic invocation of the repository you have.
So now you need to understand Linq to Entities a little more.
Linq to Entities language reference what you can do with linq to Entities.
Given the expression tree has to be converted in to DB instructions,
it isnt surprising there are restrictions.
In case you are interested The EF provider specs and links to samples
So given you want to Dynamic EF, you have a few options.
I concentrate on dynamic wheres, but you can apply to other EF methods.
Check out
Dynamic Linq on codeplex
which allows things like
public virtual IQueryable<TPoco> DynamicWhere(string predicate, params object[] values) {
return Context.Set<TPoco>().Where(predicate, values);
}
This Where is an IQueryable extension that accepts strings...
Samples of using this string based predicate parser
LinqKit or even PM> Install-Package LinqKit
Linqkit takes dynamic EF to the next level,
Offers amazing features like
public IQueryable<TPoco> AsExpandable() {
return Context.Set<TPoco>().AsExpandable();
}
which allows you build AND and ORs progressively.
Expression trees
Expression Building API is the most powerful tool to support you here .
Learning the API is hard. using the tool harder.
eg Dealing with concatenation very hard. BUT if you can understand the API and how expressions work.
It is possible.
Here is a SIMPLE example. (imagine something complex)
public static Expression<Func<TPoco, bool>> GetContainsPredicate<TPoco>(string propertyName,
string containsValue)
{
// (tpoco t) => t.propertyName.Contains(value ) is built
var parameterExp = Expression.Parameter(typeof(TPoco), #"t");
var propertyExp = Expression.Property(parameterExp, propertyName);
MethodInfo method = typeof(string).GetMethod(#"Contains", new[] { typeof(string) });
var someValue = Expression.Constant(containsValue, typeof(string));
var containsMethodExp = Expression.Call(propertyExp, method, someValue);
return Expression.Lambda<Func<TPoco, bool>>(containsMethodExp, parameterExp);
}

How do I use a custom comparer with the Linq Distinct method?

I was reading a book about Linq, and saw that the Distinct method has an overload that takes a comparer. This would be a good solution to a problem I have where I want to get the distinct entities from a collection, but want the comparison to be on the entity ID, even if the other properties are different.
According to the book, if I have a Gribulator entity, I should be able to create a comparer like this...
private class GribulatorComparer : IComparer<Gribulator> {
public int Compare(Gribulator g1, Gribulator g2) {
return g1.ID.CompareTo(g2.ID);
}
}
...and then use it like this...
List<Gribulator> distinctGribulators
= myGribulators.Distinct(new GribulatorComparer()).ToList();
However, this gives the following compiler errors...
'System.Collections.Generic.List' does not contain a definition for 'Distinct' and the best extension method overload 'System.Linq.Enumerable.Distinct(System.Collections.Generic.IEnumerable, System.Collections.Generic.IEqualityComparer)' has some invalid arguments
Argument 2: cannot convert from 'LinqPlayground.Program.GribulatorComparer' to 'System.Collections.Generic.IEqualityComparer'
I've searched around a bit, and have seen plenty of examples that use code like this, but no complaints about compiler errors.
What am I doing wrong? Also, is this the best way of doing this? I want a one-off solution here, so don't want to start changing the code for the entity itself. I want the entity to remain as normal, but just in this one place, compare by ID only.
Thanks for any help.
You're implementing your comparer as an IComparer<T>, the LINQ method overload requires an implementation of IEqualityComparer:
private class GribulatorComparer : IEqualityComparer<Gribulator> {
public bool Equals(Gribulator g1, Gribulator g2) {
return g1.ID == g2.ID;
}
}
edit:
For clarification, the IComparer interface can be used for sorting, as that's basically what the Compare() method does.
Like this:
items.OrderBy(x => new ItemComparer());
private class ItemComparer : IComparer<Item>
{
public int Compare(Item x, Item y)
{
return x.Id.CompareTo(y.Id)
}
}
Which will sort your collection using that comparer, however LINQ provides a way to do that for simple fields (like an int Id).
items.OrderBy(x => x.Id);

Entity Framework 4.1 simple dynamic expression for object.property = value

I know there is a way to use Expressions and Lambdas to accomplish this but I having a hard time piecing it all together. All I need is a method that will dynamically query an Entity Framework DBSet object to find the row where the propery with the given name matches the value.
My context:
public class MyContext : DbContext
{
public IDbSet<Account> Accoounts{ get { return Set<Account>(); } }
}
The method that I'm looking to write:
public T Get<T>(string property, object value) : where T is Account
{...}
I would rather not have to use Dynamic SQL to accomplish this so no need to suggest it because I already know it's possible. What I'm really looking for is some help to accomplish this using Expressions and Lambdas
Thanks in advance, I know it's brief but it should be pretty self-explanatory. Comment if more info is needed
I'm trying to avoid dynamic linq as much as possible because the main point of linq is strongly typed access. Using dynamic linq is a solution but it is exactly the oppose of the linq purpose and it is quite close to using ESQL and building the query from sting concatenation. Anyway dynamic linq is sometimes real time saver (especially when it comes to complex dynamic ordering) and I successfully use it in a large project with Linq-to-Sql.
What I usually do is defining some SearchCriteria class like:
public class SearchCriteria
{
public string Property1 { get; set; }
public int? Property2 { get; set; }
}
And helper query extension method like:
public static IQueryable<SomeClass> Filter(this IQueryable<SomeClass> query, SearchCriteria filter)
{
if (filter.Property1 != null) query = query.Where(s => s.Property1 == filter.Property1);
if (filter.Property2 != null) query = query.Where(s => s.Property2 == filter.Property2);
return query;
}
It is not generic solution. Again generic solution is for some strongly typed processing of classes sharing some behavior.
The more complex solution would be using predicate builder and build expression tree yourselves but again building expression tree is only more complex way to build ESQL query by concatenating strings.
Here's my implementation:
public T Get<T>(string property, object value) : where T is Account
{
//p
var p = Expression.Parameter(typeof(T));
//p.Property
var propertyExpression = Expression.Property(p, property);
//p.Property == value
var equalsExpression = Expression.Equal(propertyExpression, Expression.Constant(value));
//p => p.Property == value
var lambda = Expression.Lambda<Func<T,bool>>(equalsExpression, p);
return context.Set<T>().SingleOrDefault(lambda);
}
It uses EF 5's Set<T>() method. If you are using a lower version, you'll need to implement a way of getting the DbSet based on the <T> type.
Hope it helps.
Dynamic Linq may be an option. Specify your criteria as a string and it will get built as an expression and ran against your data;
An example from something I have done;
var context = new DataContext(ConfigurationManager.ConnectionStrings["c"].ConnectionString);
var statusConditions = "Status = 1";
var results = (IQueryable)context.Contacts.Where(statusConditions);
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Convert Dataset to IQueryable<T> or IEnumerable<T>

Since there is no Linq to DB2 yet (c'mon IBM!), and I want to deal with IQueryables or IEnumerables in my code, how would I convert a DataTable to an IQueryable? Or an IEnumerable?
I have an interface and a class that matches the columns in the datatable...
IQueryable<IMyData> GetAS400Data(..parameters..)
{
DataSet d = GetData();
...
//Some code to convert d to IQueryable<IMyData>
}
DataTable.Rows does not support .AsQueryable, since MSFT yanked it, so I'm not sure what to do here.
table.AsEnumerable()...
table.AsEnumerable().AsQueryable()...
However, you'd need to write your own translation (Select) to your type; and the IQueryable<T> would still be using LINQ-to-Objects; the only purpose (in this scenario) of using IQueryable<T> over IEnumerable<T> would be to use expressions for some other reason - perhaps for the dynamic LINQ library.
you can use something like this.
DataSet ds = GetData();
DataTable dt= ds.Tables[0];
var query =
from row in dt.AsEnumerable()
select new IMyData()
{
property1= row[0],
property2= row[1]
};
Take a look here it seems that a provider with entity framework for DB2 exists.

Resources