I am trying to make use of the code in this question to implement a query like this:
public void LoadLive(DbConnection pConnection)
{
using (DbDataReader lReader = pConnection.ExecuteReader("..."))
{
mList.AddRange(from t in lReader select new MyObject { Name = t.GetString(0) });
}
}
When I attempt to compile this (with the extension method in place), I receive this error:
error CS1934: Could not find an implementation of the query pattern for source type 'System.Data.Common.DbDataReader'. 'Select' not found. Consider explicitly specifying the type of the range variable 't'.
Am I missing something about how this is supposed to work?
You must call the extension method from the answer in the linked question:
mList.AddRange(from t in lReader.AsEnumerable()
select new MyObject { Name = t.GetString(0) });
Unless you are going to write your own extension method, Select, Where, etc all return an IEnumerable and the typical method signature will resemble Func<DbDataReader, myT>. What you are looking for is something like Jon Skeet's sample here.
Compiler error CS1934 is produced when no standard query operators are implemented for a given datasource.
In your case (DbDataReader), you could specify the type of t as IDataRecord:
mList.AddRange(from IDataRecord t in lReader
select new MyObject { Name = t.GetString(0) });
Related
I am trying to get the MethodInfo from a method TableExists<T> so I can call it with a type.
The method is declared inside OrmLiteSchemaApi class. There are 2 overloads:
public static bool TableExists<T>(this IDbConnection dbConn)
{
// code omitted
}
public static bool TableExists(this IDbConnection dbConn, string tableName, string schema = null)
{
// code omitted
}
I am trying to get the MethodInfo like this:
var tableMethod = typeof(OrmLiteSchemaApi).GetMethod("TableExists");
But it generates exception:
System.Reflection.AmbiguousMatchException: 'Ambiguous match found.'
I could only find an old question related to this that suggested to pass an empty object array as parameter but this doesn't seem to work for .net core.
I guess I need to specify the specific overload but I am not sure exactly how.
How do I get the MethodInfo?
You can use GetMethods (plural!) to get an array of all matching methods, and then look for the one which has IsGenericMethod:
var tm = typeof(OrmLiteSchemaApi)
.GetMethods()
.Where(x => x.Name == "TableExists")
.FirstOrDefault(x => x.IsGenericMethod);
I recommend this over using parameter specifiers, since it'll give you an object you can step through at debug time if there are ever any problems.
Passing an empty object array would only work if you're looking for a function with no parameters. Instead, you need to use a different overload of GetMethod that specifies the types of parameters as a type array. That way you can tell it which reference to get by specifying which types of parameters it should look for.
I'm appalled I haven't found anything on the internet about this problem, but probably I'm looking for the wrong words. Here is what I need to do.
Suppose I have a generic type: List<string> works for the sake of simplicity. How do I get the parameter type (in this case typeof(string))?
Keep in mind that I need to do this from outside the generic class (not inside a class method, which is what I've seen in other SO questions). The bottom line is that I have an instance of a generic type, I need to know both its type AND its parameter type (in the example above, I would like to get both typeof(List) AND typeof(string), not anything like typeof(List<string>)). Of course, this must be done at runtime.
Thanks to everyone who will reply.
It sounds like what you're looking for is Type.GetGenericArguments(). You would call it on the Type of the instance in question. It returns an array of Type (to Eric Lippert's chagrin).
typeof(List<string>).GetGenericArguments()[0]
var myList = new List<String>();
var shouldBeString = myList.GetType().GetGenericArguments().FirstOrNull();
var shouldBeGenericList = myList.GetType().GetGenericTypeDefinition();
See http://msdn.microsoft.com/en-us/library/system.type.getgenericarguments.aspx and http://msdn.microsoft.com/en-us/library/system.type.getgenerictypedefinition.aspx respectively
Why won't you make your function generic? It will let compiler sort it out for you.
void your_func<T>(List<T> lst)
{
Type list_type = typeof(List<T>);
Type generic_list_type = typeof(List<>);
Type generic_argument_type = typeof(T);
// do what you need
}
You can invoke it like normally:
var lst = new List<string>();
// ...
obj.your_func(lst);
Other option is to use reflection as described in other answers.
I'm trying to extend SqlMethods.Like method to support property name rather than property value, i wrote the following extension method :
public static bool Like(this object obj, string propertyName, string pattern)
{
var properties = obj.GetType().GetProperties().Select(p => p.Name);
if(!properties.Contains(propertyName))
throw new Exception(string.Format("Object does not contain property:{0}", propertyName));
return SqlMethods.Like(obj.GetType().GetProperty(propertyName).GetValue(obj, null).ToString(), pattern);
}
however the method throws the following exception :
Method 'Boolean Like(System.Object, System.String, System.String)' has no supported translation to SQL.
how can i write an extension method with transaction to SQL support ?
I found this answer from RichardD that is exactly the correct answer. Reposting for clarity, but original is linked below.
using System;
using System.Linq;
using System.Linq.Expressions;
public static class Extensions
{
public static IQueryable<T> WhereLike<T>(this IQueryable<T> source, string propertyName, string pattern)
{
if (null == source) throw new ArgumentNullException("source");
if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");
var a = Expression.Parameter(typeof(T), "a");
var prop = Expression.Property(a, propertyName);
var body = Expression.Call(typeof(SqlMethods), "Like", null, prop, Expression.Constant(pattern));
var fn = Expression.Lambda<Func<T, bool>>(body, a);
return source.Where(fn);
}
}
...
.WhereLike("Description", "%a%b%c%"));
The solution uses expression trees, but all advanced LinqToSql operations will require familiarity with that.
From: http://forums.asp.net/p/1488418/3503874.aspx
What you want to do does not seem to make sense in the contxt of what SqlMethods.Like actually does. When you pass in a property of a class you are essentially telling it to translate that into the equivelent field in the SQL query. e.g.
var result = from names in db.Names
where SqlMethods.Like(names.FullName, '%Smith%')
select names;
would translate to something like:
SELECT *
FROM Names
WHERE Fullname LIKE '%Smith%'
(in practice it would be different using parameters and sp_executeSQL but coneptually that is what it would do).
If you want to pass in the name of a property what does that mean in terms of SQL, conceptually it makes no sense e.g.
SELECT *
FROM Names
WHERE --what would go here-- LIKE '%Smith%'
As such you are not going to be able to create a Linq To SQL method that creates nonsense SQL.
What are you actually trying to do, the chance is that you are going about it completely the wrong way.
Edit:hmm from your comment i think i understand what you want to do, in essense you want to be able to specify the column you are doing a LIKE comparison with at run time. You cannot do it exactly. You could use a stored procedure that used dynamic SQL and took a string parameter for the column. You could then expose this as a method on your data context class.
I'm trying to get the name of a method on a type using a lambda expression. I'm using Windows Identity Foundation and need to define access policies with the type name with namespace as a resource and the method name as the action. Here is an example.
This is the type I would be getting the type name and method name from:
namespace My.OrderEntry {
public class Order {
public void AddItem(string itemNumber, int quantity) {}
}
}
This is how I would like to define the access policy through a DSL:
ForResource<Order>().Performing(o => o.AddItem).AllowUsersHaving(new Claim());
From that statement, I would like to get "My.OrderEntry.Order" as the resource and "AddItem" as the action. Getting the type name with namespace is no problem, but I don't think I can use a lambda for a method like I'm trying to do.
public static IPermissionExp Performing<T>(
this IActionExp<T> exp,
Func<T, delegate???> action) {} //this is where I don't know what to define
Is this sort of thing even possible to do? Is there another way to do this sort of thing without using magic strings?
There are two ways to do this:
1: You could make overloads that take the various Func and Action delegates(eg Expression<Func<T, Func<TParam1,TParam2, TReturn>>. Note that your callers would need to specify the generic parameters explicitly, either in the method call or by creating the delegate. This would be used like this:
ForResource<Order>().Performing(o => new Action<string>(o.AddItem)).AllowUsersHaving(new Claim());
2: You could take an Expression<Action> that contains a method call, and parse out the MethodInfo being called from the expression tree. This would be used like this:
ForResource<Order>().Performing(o => { o.AddItem(null); }).AllowUsersHaving(new Claim());
It looks like this is what you are looking for if you want the name of the action delegate method passed in to the Performing function.
public static IPermissionExp Performing<T>(
this IActionExp<T> exp,
Expression<Action<T, string, int>> action)
{
var expression = action.Body as MethodCallExpression;
string actionMethodName = string.Empty;
if (expression != null)
{
actionMethodName = expression.Method.Name;
}
// use actionMethodName ("AddItem" in the case below) here
}
This would allow you to call the method like this...
ForResource<Order>().Performing((o, a, b) => o.AddItem(a, b)).AllowUsersHaving(new Claim());
I recently did a thing at work where you defined the a method using a lambda, which the internal object then took the name of. You could use strings as well, or pass in a MethodInfo but the first one isn't really type safe (and typos are a big risk), and the latter is not very elegant.
Basically I had a method like this (this is not the exact method, it is a bit more advanced):
public void SetRequest(Request req, Expression<Func<Service, Func<long, IEnumerable<Stuff>>> methodSelector);
The key here is the "Expression" thing, this lets you "select" a method like this:
SetRequest(req, service => service.SomeMethodTakingLongReturningStuffs);
Method selector is made into a expression tree which you can then fetch different bits of data from. I don't recall exactly what the resulting tree looks like, it also depends on how your lambdas look.
You could pass it in as a Action instead, which doesn't force any return type. It is still a little messy though, because you have to pass some arguments to the method in order for it to compile.
Let me start by saying I'm pretty new to using interfaces.
I'm writing a method (GetClaimDetails) that will return information about a medical insurance claim. If it is claim type A, it will return an list of the ClaimDetailA class. If claim type B, return list of ClaimDetailB class. Both of these classes share common properties but each have unique properties. The common properties are implemented in an interface.
I extracted an interface named IClaimDetail and set both to implement it. When i set the method to return IClaimDetail and have it return an instance of an object that implements IClaimsDetail, I get the compiler message
'Cannot implicitly convert type 'System.Collections.Generic.List DentalClaimDetail' to 'System.Collections.Generic.List IClaimDetail'
private static List<IClaimDetail> GetClaimDetailsB(string claimNumber, string connectionStringName)
{
var claimReportRows = new List<DentalClaimDetail>();
..removed for brevity
return claimReportRows;
}
public class DentalClaimDetail : IClaimDetail
{
...
}
When a method returns an interface, you just return an object the implements the interface. Correct? What am I doing wrong?
var claimReportRows = new List<IClaimDetail>();
Just change this. Then you will be able to insert DentalClaimDetail into it still.
Generics actually generate an type on-the-fly at compile time for every generic argument, so List<IClaimDetail> is one type, and List<DentalClaimDetail> is actually another type, so you will get compiler errors for that.
Yes, lame, but simply changing your call as outlined by Daniel A. White
var claimReportRows = new List<IClaimDetail>();
(although you should just be able to use the type directly unless you are using Linq) and then having the code use casting to cast the DentalClaimDetail to an IClaimDetail should do the trick.
If not using Linq, you can do something like:
List<IClaimDetail> claimReportRows = new List<IClaimDetail>();
//...populate Dentail Claims Here...
foreach(DentalClaimDetail dcd in dentalClaims)
{
claimReportRows.Add((IClaimDetail)dcd);
}
return claimReportRows.
Hope this helps!