Abstracting out queries to the Azure Table Storage using Expressions - c#

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.

Related

Type error trying to call Any() using Expression<Func<..>> from method

I am creating a reusable mapping expression from my EF entity to my BLL entity:
private Expression<Func<Person, bool>> GetNameFilter(string name)
{
return person => person.Profile.UserName == name;
}
internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
return perk => new Bll.Perk
{
Id = perk.PerkId,
Name = perk.PerkName,
Description = perk.PerkDescription,
//Compilation Error
Owned = perk.Players.Any(GetNameFilter(name))
};
}
And I am getting a compilation error on the noted line. The error reads:
ICollection does not contain a definition for 'Any' and the best extension method overload 'Queryable.Any(IQueryable, Expression>)' requires a receiver of type 'IQueryable'
But this does not happen when I push this expression in directly:
internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
return perk => new Bll.Perk
{
Id = perk.PerkId,
Name = perk.PerkName,
Description = perk.PerkDescription,
//No Compilation Error
Owned = perk.Players.Any(person => person.Profile.UserName == name)
};
}
Why is this happening? The type of both expressions is the same.
Using the LinqExpression solution found below, I am now getting the following error at runtime:
An exception of type 'System.InvalidCastException' occurred in LinqKit.dll but was not handled in user code
Additional information: Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'.
internal FutureQuery<Perk> GetPlayerInfoPerks(string username)
{
return Master
.Perks
.VisiblePerks
.Select(Master.Perks.MapPerkPerk(username))
.Future();
}
Is this due to the use of the EntityFramework.Future library?
Why is this happening? The type of both expressions is the same.
The type of both expressions is not the same - they just look visually the same. The following is valid:
dbContext.Persons.Any(GetNameFilter(name))
and this is not:
perk.Players.Any(GetNameFilter(name))
Why? Because the first expects Expression<Func<...>> while the second - just Func<..> (the typical difference between IQueryable<T> and IEnumerable<T> methods with the same name). Hope you see the difference. When you type it directly, the C# compiler does its magic to emit one or the another, but when you do that manually, you are supposed to use the correct one.
The problem is addressed by LinqKit package with Invoke / Expand custom extension methods (and more generally with AsExpandable).
For your concrete example, the LinqKit solution could be like this:
using LinqKit;
...
internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
// LinqKit requires expressions to be in variables
var nameFilter = GetNameFilter(name);
return Linq.Expr((Ef.Perk perk) => new Bll.Perk
{
Id = perk.PerkId,
Name = perk.PerkName,
Description = perk.PerkDescription,
Owned = perk.Players.Any(p => nameFilter.Invoke(p))
}).Expand();
}

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();

Assign a function delegate that returns an anonymous type to a variable

The code below is valid:
IEnumerable<SomeThing> things = ...;
// map type SomeThing to a new anonymous type, resulting in a strongly typed
// sequence based on an anon type
var newList = things.Select(item =>
{
return new
{
ID = item.ID,
DateUpdatedOrCreated = ((DateTime)(item.DateUpdated ??
item.DateCreated)).ToShortDateString(),
Total = item.Part1 + item.Part2
};
});
newList now appears in Visual Studio as IEnumerable<'a> and is strongly typed with the anonymous type created in the function. That is so cool.
What I can't seem to do is figure out a way to assign just the lambda expression (and not the enumeration) to an implicitly typed variable. Even though the compiler has no problem with the anonymous type in the context above, if I try (say)
var func = (SomeThing item)=> {
return new { ... };
};
I get the error "Cannot assign lambda expression to implicitly-typed local variable". This seems a strange compiler limitation; unless I am missing something, the types are just as non-ambiguous in the 2nd example as they are in the first first: both type parameters are well defined.
Is there any way to do this? Since it's an anonymous type, of course, I don't have any way to use a type to assign it explicitly, so it seems I'd be stuck with making a class for the output type if not.
Update
Shortly after going about my merry way with Jon Skeet's answer, I found a similar dilemma instantiating classes. In case it's not obvious, the same trick can be used to create strongly typed classes using inferred anonymous types.
class Processor<T,U>
{
public Processor(Func<T,U> func) {
}
}
// func is a delegate with anon return type created using method in answer below
var instance = new Processor(func); // does not compile! Requires type arguments!
cannot be created directly, but can be created in much the same way as the trick below:
public static Processor<T,U> Create<T,U>(Func<T,U> func) {
return new Processor<T,U>(func);
}
var instance = Processor.Create(func); // all good
You can do it via type inference:
var func = BuildFunc((SomeThing item) => {
return new { ... };
});
...
static Func<TSource, TResult> BuildFunc<TSource, TResult>(
Func<TSource, TResult> function) {
return function;
}
Note that BuildFunc doesn't really do anything - it just provides the method call needed to get the compiler to do type inference for the generic type arguments for Func<,> - it adds the information that you're interested in Func<,>, basically - that's information which can't be specified as part of a variable declaration, without also specifying the type arguments.

Return partial linq query from method - how to declare return type

I have a linq query written in method syntax. I need to create a very similar method with just some changes to the final Select.
Is it possible to return the partial Linq query from a method so I dont duplicate the code? The issue I have is finding the "Type" of the query to mark the method with.
If I use query.GetType(), it returns (cut down version) :
SubSonic.Linq.Structure.Query`1[<>f__AnonymousType18`6[advert,client]]
I tried to create a return type:
SubSonic.Linq.Structure.Query<advert, client> query = new SubSonic.Linq.Structure.Query<advert, client>();
However I receive the error:
Error 20 Using the generic type 'SubSonic.Linq.Structure.Query<T>' requires '1' type arguments
So I guess I am asking how to declare a return type that is a Subsonic Query containing an anonymous type containing a number of objects? (2 in my example)
Please excuse my simple example:
eg:
internal ????? GetQueryBody(string param1, string param2){
/* buld the linq query here */
}
internal List<Booking> GetSearchResultsOne(string param1, string param2){
var query = this.GetQueryBody(string param1, string param2);
var res = query.Select( db => new Booking { /*fields */).ToList();
return res;
}
internal List<BookingData> GetSearchResultsTwo(string param1, string param2){
var query = this.GetQueryBody(string param1, string param2);
var res = query.Select( db => new BookingData { /*fields*/).ToList();
return res;
}
Thank you for your time,
Yohimbo
Use IEnumerable<T> to return a query.
About the anonymous type: If a type is anonymous, how should another methode know about it? Read more here. To solve the problem, give your anonymous type a name by creating a class.
If you only want to return two types you could also return a tuple: Then T is Tuple<advert,client>. You can create a tuple by
var t = new Tuple<advert,client>(client, advert);
Answer 1: You can't do it because Booking and BookingData are different types so the expression trees are different.
Answer 2: Assuming you can find a common base class, there are two approaches to your question.
The 'type' of what a Linq Query acts on is actually an Expression<TDelegate>. You can construct Expression trees and store them and manipulate them, and then use them where needed.
The 'argument' for your final Select() is actually an Expression<Func<TSource, TResult>>. You can use any function in that location as long as it conforms to that delegate.
In other words, you can store the entire pre-formed expression trees from the top, or you can store one tree and substitute the bit at the bottom. There isn't enough in your sample for me to write the code, and you still have to resolve that fatal flaw.

Generic extension method : Type argument cannot be inferred from the usage

I'm trying to create a generic extension method, that works on typed data tables :
public static class Extensions
{
public static TableType DoSomething<TableType, RowType>(this TableType table, param Expression<Func<RowType, bool>>[] predicates)
where TableType : TypedTableBase<RowType>
where RowType : DataRow
{
// do something to each row of the table where the row matches the predicates
return table;
}
[STAThread]
public static void main()
{
MyTypedDataSet.MyTypedDataTable table = getDefaultTable();
}
public static MyTypedDataSet.MyTypedDataTable getDefaultTable()
{
// this line compiles fine and does what I want:
return new MyTypedDataSet.MyTypedDataTable().DoSomething<MyTypedDataSet.MyTypedDataTable, MyTypedDataSet.MyTypedRow>(row => row.Field1 == "foo");
// this line doesn't compile :
return new MyTypedDataSet.MyTypedDataTable().DoSomething(row => row.Field1 == "foo");
// Error : The type arguments .. cannot be inferred from the usage
}
}
The first line works fine, but it's really ugly...
The second line doesn't compile because the compiler cannot infer the type of RowType.
This is a method that will be used as part of a DataLayer by many different programmers, so I would rather not need them to specify the TypeParameter.
Shouldn't the compiler know that RowType is the same type as the one that was used by TypedTableBase ?
For different reasons that may not be obvious in this code sample, I really need to return the datatable in its original form. And the reason I need RowType is so the 'Expression<Func<T, bool>>' will be typed and seen by InteliSence.
Thanks
Method type inference does not make inferences from arguments to constraints. It makes inferences from arguments to formal parameters and then checks whether the inferences made from the arguments to the formals satisfy the constraints.
In your case there is not enough data from the arguments to deduce what the type parameters are without first looking at the constraints, which we're not going to do until we check the inferences against the constraints. Sorry about that, but that's how the type inference algorithm is specified.
I've been asked questions about this many times and the consensus seems to be that I am morally wrong for maintaining the position that inference should infer from arguments to formal parameters alone. For about a dozen people telling me I'm wrongheaded in this regard, see the comments to my analysis of this closely related issue:
http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx
I maintain my position.
Eric's answer is great for explaining why the types cannot be inferred. Here are a couple of suggestions to hopefully cut down on the verbosity of the code that you will have to write.
If you can explicitly define the type of your lambda expression, then it can infer the types.
One example of how to do that is below. I've created a criteria parameter that is explicitly of type Expression<Func<MyTypedDataSet.MyTypedRow, bool>>. In this example, this doesn't save you much typing, but perhaps in practice you can make use of this.
MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable();
Expression<Func<MyTypedDataSet.MyTypedRow, bool>> criteria = row => row.Field1 == "foo";
return table.DoSomething(criteria);
EDIT: altered my example to use another extension method rather than deriving a custom TypedTableBase<T> class from System.Data.TypedTableBase<T>.
Below is another example that can do a better job of inferring the type parameters. You define another extension method (mine is called RowPredicate) that only has one type parameter to infer. The first parameter is of type TypedTableBase<RowType>, so the compiler should have no problem inferring the type from that:
public static Expression<Func<RowType, bool>> RowPredicate<RowType>(this TypedTableBase<RowType> table, Expression<Func<RowType, bool>> predicate)
where RowType : DataRow
{
return predicate;
}
This allows you to compile the following code:
MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable();
return table.DoSomething(table.RowPredicate(row => row.Field1 == "foo"));
Primarily the table parameter simply servers to inform the compiler of the type to use for RowType. Is this a good idea? I'm not so sure, but it does allow the compiler to infer all of the generic types.
Even if that wasn't ideal, I gave up trying to return anything at all which allows me to do something like the following:
public static void DoSomething<RowType>(this TypedTableBase<RowType> table, param Expression<Func<RowType, bool>>[] predicates)
where RowType : DataRow
{
// do something to each row of the table where the row matches the predicates
// do not return the table... too bad for chaining commands
}
And then use it like so:
MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable();
table.DoSomething(row => row.Field1 == "foo"));
and the compiler infers the type correctly.
Thank you both for your answers.

Categories

Resources