I am using the Dynamic Linq Library that Scott Guthrie describes here.
Scott Guthrie's examples are great and I have used the dynamic Where statements quite a bit.
Now, however, I am faced with a situation where I need to use the dynamic select functionality. Scott Guthrie shows a screenshot of this functionality (in the very last screenshot in the article) but very cleverly never explains it.
The problem is, even though the code compiles and runs, I don't see how it can possibly work in any useful manner. Perhaps with reflection?
Here is an example (remember, you must use the Dynamic Linq Library that Guthrie describes in the article above, this is not the normal Linq System.Linq).
In my sample here, I have a Users table with a UserId, FirstName, and LastName fields. But it really doesn't matter what database you use. The issue is very simple to reproduce. Here is my sample code:
First make sure you have this using statement on top:
using System.Linq.Dynamic;
Then you can run the following code:
using (DataClasses1DataContext dcdc = new DataClasses1DataContext())
{
var x = dcdc.Users.Select("new(UserId, FirstName, LastName)");
foreach (var item in x)
{
Console.WriteLine(item.ToString());
}
}
As you can see, this compiles and runs just fine. You get all your records back from the database. However, there is no way I can find to actually access the members of the new anonymous type.
Because the Select query is a string, there is no type inference at design time. So I cannot write:
Console.WriteLine(item.UserId);
The compiler has no idea that the anonymous type item has a member named UserId. So that code will not even compile (even though if you pause the debugger during the For..Each loop you will see that the debug window sees that there are UserId, FirstName and LastName members.
So... how is this supposed to work? How do you gain access to the members of the anonymous type?
It will work fine for data-binding (I suspect this is its intended use-case), which uses reflection under the hood. It will also work fine with dynamic in .NET 4.0:
foreach (dynamic item in x) {
Console.WriteLine(item.UserId);
}
Other than that... reflection or TypeDescriptor.
foreach (object item in x) {
Console.WriteLine(item.GetType().GetProperty("UserId").GetValue(item, null));
}
Related
We are investigating using LinQ to query an internal dynamic collection created by Dapper. The question is:
How to execute dynamic LinQ against the collection using Scott Guthrie dynamic linq (or some other technology if possible)? (http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library)
This is what we want to do (much simplified):
Use Dapper to return a dynamic collection (here called rows):
rows = conn.Query(“select ACCOUNT, UNIT, AMOUNT from myTable”);
If we use a “static” LinQ query there is no problem. So this works fine:
var result = rows.Where(w => w.AMOUNT > 0);
But we would like to write something similar to this using dynamic Linq:
var result = rows.Where("AMOUNT > 0");
But we can’t get this to work.
The error we get is:
No property or field ‘AMOUNT’ exists in type ‘Object’
(We have tried a lot of other syntax also – but cant get it to work)
Please note: We do not want to use dynamic SQL when Dapper requests data from the database (that is easy). We want to execute many small dynamic Linq statements on the collection that the Dapper query returns.
Can it be that ScottGu dynamic Linq only works with ‘LinQ to SQL’?
Is there some other alternative approach to achieve the same thing?
(Performance is a key issue)
/Erik
conn.Query("...")
returns an IEnumerable<dynamic>. However, "dynamic LINQ" pre-dates dynamic, and presumably nobody has updated it to work with dynamic; it could certainly be done, but it is work (and isn't trivial). Options:
use Query<T> for some T
make the required changes to "dynamic LINQ", and preferably make those changes available to the wider community
I suspect that conn.Query(“select ACCOUNT, UNIT, AMOUNT from myTable”); returns IEnumerable<object>. In order for DLinq to work, you need to have IEnumerable<TheActualType>.
You can try this:
conn.Query<dynamic>("yourQueryString")
.ToList()
//.ToAnonymousList()
.Where("AMOUNT > 0");
If that doesn't work, you could try and use ToAnonymousList, that tries to return the IList<TheActualType.
I have this code that returns JSon for autocomplete.
public ActionResult AutocompleteCompany(string term)
{
var model = CacheObjects.Companies
.Where(x => x.CompanyName.Contains(term))
.Select(x => new
{
label = x.CompanyName,
id = x.CompanyId
});
return this.Json(model, JsonRequestBehavior.AllowGet);
}
There is a performance issue here because I am newing up the label and id.
There must be another way of doing this which is faster?
EDIT - it is probably the Contains clause that is the performance issue here
As your concern seems to be about the overhead/performance of Anonymous Types, in terms of performance, anonymous types are similar to other normal types. As behind the scenes the CLR compiles them down to normal types (just with an unspeakable name).
See here: Performance of anonymous types in C#
EDIT: In terms of what you're doing, selecting specific properties from an object for a strongly typed solution I cannot see any way to improve on it.
Please see a similar question here (in terms of pulling multiple properties from an object using LINQ) all answers provided use anonymous types as this is the preferred solution: Select Multiple Fields from List in Linq
Depending on your client side implementation there are a number of things you could do (if you're not already) depending on the data you acquire (both in terms of the amount plus the frequency in which it updates) you could always have it all pulled into a JSON object client side when the page loads and query it with Javascript for your autocomplete functionality (or you could cache it server side and still use LINQ). Also you could make it so that the autocomplete function is not called after each keystroke in your input box but instead wait 2 seconds or so before making the call for the objects.
I have a Repeater that is databound to a SQL database. To access the information I do the following:
string Author = (string)DataBinder.Eval(e.Item.DataItem, "Author");
There are other properties (expressions? as intellisense puts it) that I need to access, but I am unsure of what their names are. Can I loop through the e.Item.DataItem and get the names of all the expressions?
I posed this question already, sort of, but I think I was unclear. The result of that post gave me what looks like the table structure from the database, not the actual expression names/values:
UrlWithExtension [System.String]
ThumbnailUrl [System.String]
Content [System.Object]
Language [System.String]
// etc
Getting the values is not really important, just the names of the expressions.
Thanks!
I think you might be referring to what is called Fields (essentially variables that are declared at class level and made public). You can use the same method that I supplied in that other Q&A thread, with a small modification:
obj.GetType().
GetFields().
ToList().
ForEach(p =>
Console.WriteLine("{0} [{1}]", p.Name, p.FieldType.ToString()
));
I didn't really think about that when I made the code for the properties, since I almost never expose fields publicly in my classes.
When I need to know what the interface of an object looks like, I often find it easiest to simply add a break point in the debugger, and add a watch to examine the object a bit closer. That will reveal all (non-method) members and their types (and current content as well).
The answer to your other post appears to be the answer to this one as well. To get the "Expresions" that you're looking for, you could do something like this...
var props = e.Item.DataItem.GetType().GetProperties();
foreach (var item in props)
{
Console.WriteLine(string.Format("{0}:{1}", item.Name, DataBinder.Eval(e.Item.DataItem, item.Name)));
}
This loop will go over your DataItem and grab each property and output its Name and Value to the console. If your Author isn't showing up in the list of results, it could be that it isn't a property but a public Field instead, so you should take a look at GetFields() or some of the other methods as well.
Example using GetFields...
var props = e.Item.DataItem.GetType().GetFields();
foreach (var item in props)
{
Console.WriteLine(string.Format("{0}:{1}", item.Name, DataBinder.Eval(e.Item.DataItem, item.Name)));
}
Ok, understand that I come from Cold Fusion so I tend to think of things in a CF sort of way, and C# and CF are as different as can be in general approach.
So the problem is: I want to pull a "table" (thats how I think of it) of data from a SQL database via LINQ and then I want to do some computations on it in memory. This "table" contains 6 or 7 values of a couple different types.
Right now, my solution is that I do the LINQ query using a Generic List of a custom Type. So my example is the RelevanceTable. I pull some data out that I want to do some evaluation of the data, which first start with .Contains. It appears that .Contains wants to act on the whole list or nothing. So I can use it if I have List<string>, but if I have List<ReferenceTableEntry> where ReferenceTableEntry is my custom type, I would need to override the IEquatable and tell the compiler what exactly "Equals" means.
While this doesn't seem unreasonable, it does seem like a long way to go for a simple problem so I have this sneaking suspicion that my approach is flawed from the get go.
If I want to use LINQ and .Contains, is overriding the Interface the only way? It seems like if there way just a way to say which field to operate on. Is there another collection type besides LIST that maybe has this ability. I have started using List a lot for this and while I have looked and looked, a see some other but not necessarily superior approaches.
I'm not looking for some fine point of performance or compactness or readability, just wondering if I am using a Phillips head screwdriver in a Hex screw. If my approach is a "decent" one, but not the best of course I'd like to know a better, but just knowing that its in the ballpark would give me little "Yeah! I'm not stupid!" and I would finish at least what I am doing completely before switch to another method.
Hope I explained that well enough. Thanks for you help.
What exactly is it you want to do with the table? It isn't clear. However, the standard LINQ (-to-Objects) methods will be available on any typed collection (including List<T>), allowing any range of Where, First, Any, All, etc.
So: what is you are trying to do? If you had the table, what value(s) do you want?
As a guess (based on the Contains stuff) - do you just want:
bool x= table.Any(x=>x.Foo == foo); // or someObj.Foo
?
There are overloads for some of the methods in the List class that takes a delegate (optionally in the form of a lambda expression), that you can use to specify what field to look for.
For example, to look for the item where the Id property is 42:
ReferenceTableEntry found = theList.Find(r => r.Id == 42);
The found variable will have a reference to the first item that matches, or null if no item matched.
There are also some LINQ extensions that takes a delegate or an expression. This will do the same as the Find method:
ReferenceTableEntry found = theList.FirstOrDefault(r => r.Id == 42);
Ok, so if I'm reading this correctly you want to use the contains method. When using this with collections of objects (such as ReferenceTableEntry) you need to be careful because what you're saying is you're checking to see if the collection contains an object that IS the same as the object you're comparing against.
If you use the .Find() or .FindAll() method you can specify the criteria that you want to match on using an anonymous method.
So for example if you want to find all ReferenceTableEntry records in your list that have an Id greater than 1 you could do something like this
List<ReferenceTableEntry> listToSearch = //populate list here
var matches = listToSearch.FindAll(x => x.Id > 1);
matches will be a list of ReferenceTableEntry records that have an ID greater than 1.
having said all that, it's not completely clear that this is what you're trying to do.
Here is the LINQ query involved that creates the object I am talking about, and the problem line is:
.Where (searchWord => queryTerms.Contains(searchWord.Word))
List<queryTerm> queryTerms = MakeQueryTermList();
public static List<RelevanceTableEntry> CreateRelevanceTable(List<queryTerm> queryTerms)
{
SearchDataContext myContext = new SearchDataContext();
var productRelevance = (from pwords in myContext.SearchWordOccuranceProducts
where (myContext.SearchUniqueWords
.Where (searchWord => queryTerms.Contains(searchWord.Word))
.Select (searchWord => searchWord.Id)).Contains(pwords.WordId)
orderby pwords.WordId
select new {pwords.WordId, pwords.Weight, pwords.Position, pwords.ProductId});
}
This query returns a list of WordId's that match the submitted search string (when it was List and it was just the word, that works fine, because as an answerer mentioned before, they were the same type of objects). My custom type here is queryTerms, a List that contains WordId, ProductId, Position, and Weight. From there I go about calculating the relevance by doing various operations on the created object. Sum "Weight" by product, use position matches to bump up Weights, etc. My point for keeping this separate was that the rules for doing those operations will change, but the basic factors involved will not. I would have even rather it be MORE separate (I'm still learning, I don't want to get fancy) but the rules for local and interpreted LINQ queries seems to trip me up when I do.
Since CF has supported queries of queries forever, that's how I tend to lean. Pull the data you need from the db, then do your operations (which includes queries with Aggregate functions) on the in-memory table.
I hope that makes it more clear.
What would be the best approach to allow users to define a WHERE-like constraints on objects which are defined like this:
Collection<object[]> data
Collection<string> columnNames
where object[] is a single row.
I was thinking about dynamically creating a strong-typed wrapper and just using Dynamic LINQ but maybe there is a simpler solution?
DataSet's are not really an option since the collections are rather huge (40,000+ records) and I don't want to create DataTable and populate it every time I run a query.
What kind of queries do you need to run? If it's just equality, that's relatively easy:
public static IEnumerable<object[]> WhereEqual(
this IEnumerable<object[]> source,
Collection<string> columnNames,
string column,
object value)
{
int columnIndex = columnNames.IndexOf(column);
if (columnIndex == -1)
{
throw new ArgumentException();
}
return source.Where(row => Object.Equals(row[columnIndex], value);
}
If you need something more complicated, please give us an example of what you'd like to be able to write.
If I get your point : you'd like to support users writting the where clause externally - I mean users are real users and not developers so you seek solution for the uicontrol, code where condition bridge. I just though this because you mentioned dlinq.
So if I'm correct what you want to do is really :
give the user the ability to use column names
give the ability to describe a bool function (which will serve as where criteria)
compose the query dynamically and run
For this task let me propose : Rules from the System.Workflow.Activities.Rules namespace. For rules there're several designers available not to mention the ones shipped with Visual Studio (for the web that's another question, but there're several ones for that too).I'd start with Rules without workflow then examine examples from msdn. It's a very flexible and customizable engine.
One other thing: LINQ has connection to this problem as a function returning IQueryable can defer query execution, you can previously define a query and in another part of the code one can extend the returned queryable based on the user's condition (which then can be sticked with extension methods).
When just using object, LINQ isn't really going to help you very much... is it worth the pain? And Dynamic LINQ is certainly overkill. What is the expected way of using this? I can think of a few ways of adding basic Where operations.... but I'm not sure how helpful it would be.
How about embedding something like IronPython in your project? We use that to allow users to define their own expressions (filters and otherwise) inside a sandbox.
I'm thinking about something like this:
((col1 = "abc") or (col2 = "xyz")) and (col3 = "123")
Ultimately it would be nice to have support for LIKE operator with % wildcard.
Thank you all guys - I've finally found it. It's called NQuery and it's available from CodePlex. In its documentation there is even an example which contains a binding to my very structure - list of column names + list of object[]. Plus fully functional SQL query engine.
Just perfect.