I am trying to simplify and compact my code, and eliminate code duplication as much as possible. I have a method that queries RavenDB collections, and the query needs to adapt to the type I am going to query. This type changes according to the parameters passed to the method, and the where clause also needs to adapt.
I have a base type, AdministrativeArea, which other types derive from (Level1_AdministrativeAreas to Level5_AdministrativeAreas). Depending on the scenario, I need to query AdministrativeAreas, Level1_AdministrativeAreas, etc.
What I currently have:
private void Merge(MergeLevel currentMergeLevel, IDocumentSession currentSession)
{
(...)
IQueryable<AdministrativeArea> query;
if (currentMergeLevel == MergeLevel.Level1)
query = currentSession.Query<AdministrativeArea, AdminAreaName>()
.Where(area => !string.IsNullOrEmpty(area.NAME_0) && !string.IsNullOrEmpty(area.NAME_1));
(...)
}
Is there any way to pass in the types as a method parameter and have them applied to the query, like this:
private void Merge(MergeLevel currentMergeLevel, IDocumentSession currentSession, Type requiredType, Type indexType)
{
(...)
IQueryable<requiredType> query;
if (currentMergeLevel == MergeLevel.Level1)
query = currentSession.Query<requiredType, indexType>()
.Where(area => !string.IsNullOrEmpty(area.NAME_0) && !string.IsNullOrEmpty(area.NAME_1));
(...)
}
I have faced several problems at compile time, namely "is a variable but is used like a type", and the fact that member variables (NAME_0, NAME_1, etc.) can't be inferred because the compiler doesn't know "what's coming".
I suspect this simply can't be done; however, this has implications for code maintenance, as I'll have to create different methods for each type of query OR create one rather large method. Neither of which are too appealing, but I don't see any way around that.
A good way of filtering by type would be to include Raven-Entity-Name field in the "select" clause of an index.
Then you would be able to filter types by using EntityType field.
You can see an example of this kind of index in the built-in Raven/DocumentsByEntityName index
So, your index might look like this:
from doc in docs
let entityType = doc["#metadata"]["Raven-Entity-Name"]
where entityType.EndsWith("_AdministrativeAreas")
select new
{
EntityType = entityType,
//the rest of the fields
}
Note that this would work if you are inserting documents through existing client API (raw REST API won't add Raven-Entity-Name on it's own)
Related
I have a project with a large codebase that uses an in-house data access layer to work with the database. However, we want to support OData access to the system. I'm quite comfortable with expression trees in C#. How do I get at something I can parse here in order to get the structure of their actual query?
Is there a way to get an AST out of this thing that I can turn into sql code?
Essentially, you need to implement you own Query Provider which known how to translate the expression tree to an underlying query.
A simplified version of a controller method would be:
[ODataRoute("foo")]
public List<Foo> GetFoo(ODataQueryOptions<Foo> queryOptions)
{
var queryAllFoo = _myQueryProvider.QueryAll<Foo>();
var modifiedQuery = queryOptions.ApplyTo(queryAllFoo);
return modifiedQuery.ToList();
}
However!
This is not trivial, it took me about 1 month to implement custom OData query processing
You need to build the EDM model, so the WebApi OData can process and build right expression trees
It might involve reflection, creation of types at runtime in a dynamic assembly (for the projection), compiling lambda expressions for the best performance
WebAPI OData component has some limitations, so if you want to get relations working, you need to spend much more extra time, so in our case we did some custom query string transformation (before processing) and injecting joins into expression trees when needed
There are too many details to explain in one answer, it's a long way..
Good luck!
You can use ODataQueryOptions<T> to get abstract syntax trees for the $filter and $orderby query options. ($skip and $top are also available as parsed integers.) Since you don't need/want LINQ support, you could then simply pass the ASTs to a repository method, which would then visit the ASTs to build up the appropriate SQL stored proc invocation. You will not call ODataQueryOptions.ApplyTo. Here's a sketch:
public IEnumerable<Thing> Get(ODataQueryOptions<Thing> opts)
{
var filter = opts.Filter.FilterClause.Expression;
var ordering = opts.OrderBy.OrderByClause.Expression;
var skip = opts.Skip.Value;
var top = opts.Top.Value;
return this.Repository.GetThings(key, filter, ordering, skip, top);
}
Note that filter and ordering in the above are instances of Microsoft.OData.Core.UriParser.Semantic.SingleValueNode. That class has a convenient Accept<T> method, but you probably do not want your repository to depend on that class directly. That is, you should probably use a helper to produce an intermediate form that is independent of Microsoft's OData implementation.
If this is a common pattern, consider using parameter binding so you can get the various query options directly from the controller method's parameter list.
I have a large number of PL/SQL stored procs that return columns with single character strings representing some kind of status value from a fixed range. In the project I'm working on, these columns have been mapped by Dapper to string properties on the domain objects, which are awkward and unreliable to manage, so I'd like to switch to enums.
If I used enums with single character names like enum Foo {A, P} I'm pretty sure Dapper would map them correctly but I don't want that, I want enums with descriptive labels like so:
enum Foo {
[StringValue("A")]
Active,
[StringValue("P")]
Proposed
}
In the above example, StringValueAttribute is a custom attribute and I can use reflection to convert the "A" to Foo.Active, which works fine - except I need Dapper to perform that conversion logic for me. I wrote a custom type handler to do this:
public class EnumTypeHandler<T> : SqlMapper.TypeHandler<T>
{
public override T Parse(object value)
{
if (value == null || value is DBNull) { return default(T); }
return EnumHelper.FromStringValue<T>(value.ToString());
}
public override void SetValue(IDbDataParameter parameter, T value)
{
parameter.DbType = DbType.String;
parameter.Value = EnumHelper.GetStringValue(value as Enum);
}
}
//Usage:
SqlMapper.AddTypeHandler(typeof(Foo),
(SqlMapper.ITypeHandler)Activator.CreateInstance(typeof(EnumTypeHandler<>).MakeGenericType(typeof(Foo)));
The registration with SqlMapper.AddTypeHandler() seems to work fine, but when my DbConnection.Query() code runs, I get an error saying that the value 'A' could not be converted - the error is thrown from Enum.Parse, suggesting that Dapper isn't actually calling my type handler at all despite it being registered. Does anyone know a way around this?
Another user has reported this as an issue on Dapper's github site. Seems like it's a deliberate optimisation specifically around enums in Dapper, so I've changed my database model rather than trying to change the mapping code. I looked at trying to modify Dapper itself, but the source code of Dapper is optimised like nothing I've ever seen, emitting opcodes to perform conversions in the most performant way possible - no way I want to start trying to work out how to make changes there.
I'm attempting to create a generic WPF form or page, that when called, will load in data from a LINQ table. Here is the concept:
I have three tables in a LINQ DataContext that are identical (apart from the data within)
TypeID and Type are the columns
I would like to generically pass that data in those tables into my second form depending on which table the user selects (essentially so they can narrow down the list of objects of said Type.
I've seen some responses, (in particular the accepted answer to this one LINQ query with a generic table) that are very close to what I am looking for, but not quite. One issue I have with the above answer is that T must be a reference type.
I've done more searching and found some more answers like:
someClass<T> : <T> where T
But unfortunately these are further from my own context and I am unable to bridge the two concepts of what is happening. Below I have posted what I hope to do.
someDataContext db = new someDataContext();
private void pageLoader<T>(){
newPage n = new newPage(T) //This is where I was hoping I could pass the table(s) to the constructor.
}
And here is the constructor:
newPage(T){
listBox l = new listBox();
l.datasource = T;
}
Any assistance in any direction would be helpful (besides MSDN, please. I've been there and I'm still lost.)
Let start from the top. LINQ is merely an abbreviation for Language Integrated Query. It is interchangeable with Lambda. Different syntax but both accomplish the same task. Querying a collection or datasource. See http://msdn.microsoft.com/en-ca/library/bb397926.aspx
You are referring to the EntityFramework Code First approach of creating a database. LINQ is merely a way to access and manipulate the information within.
With that out of the way, what you are pointing out is a Generic Method and a Generic Class. T is simply a standard naming convention for a generic type. You could use any representation you like. If you are going to be passing in entities, you might use TEntity for example.
See http://www.dotnetperls.com/generic-method
http://www.dotnetperls.com/generic
When you see someClass where T, this is a constraint for type parameters.
And finally, what you have been waiting for...
https://codereview.stackexchange.com/questions/19037/entity-framework-generic-repository-pattern
The following should put you on the right path.
http://blog.gauffin.org/2013/01/repository-pattern-done-right/ <- This would be more of a better starting tutorial
I have been using Dapper.net for a while now and its a very good ORM mapper which works great with .Net dynamic types.
But I noticed that when Dapper retrieves data from a database it returns as DapperRow type.
Is there are any way that I can return it in any other type Like System.Dynamic.ExpandoObject?
Sure!
As per dapper documentation use the query method and get your dymanics:
dynamic account = conn.Query<dynamic>(#"
SELECT Name, Address, Country
FROM Account
WHERE Id = #Id", new { Id = Id }).FirstOrDefault();
Console.WriteLine(account.Name);
Console.WriteLine(account.Address);
Console.WriteLine(account.Country);
As you can see you get a dynamic object and you can access its properties as long as they are well defined in the query statement.
If you omit .FirstOrDefault() you get an IEnumerable<dynamic> which you can do whatever you want with it.
The DapperRow object is designed to share a lot of state between rows. For example, if you fetch 40 rows, the column names etc are only stored once. If we used ExpandoObject, this would need to be configured per row. Hence, the use of DapperRow as the behind-the-scenes implementation detail is a deliberate efficiency thing.
Note that the object returned from the dynamic APIs can also be cast as IDictionary<string,object>.
I would, however, be open to supporting other types that support this dictionary usage - of which ExpandoObject is one. So yes, it could be changed such that:
var rows = conn.Query<ExpandoObject>(...);
works. It simply requires code to support it, and that code does not currently exist. So "no, but perhaps in a future build".
Note also that you don't need to use DapperRow at all... The more expected scenario is to use the generic API to materialize your own types.
I have this problem and I solved by this way!
The Query() function returns a collection of dynamics which underneath are actually Dapper.SqlMapper.DapperRow object types. The Dapper.SqlMapper.DapperRow is private. I needed to dynamically add properties to the Dapper.SqlMapper.DapperRow objects but that doesn't appear to work. As a result I wanted to convert the Dapper.SqlMapper.DapperRow into an ExpandoObject.
I was able to build this generic helper method like below.
public class DapperHelpers
{
public static dynamic ToExpandoObject(object value)
{
IDictionary<string, object> dapperRowProperties = value as IDictionary<string, object>;
IDictionary<string, object> expando = new ExpandoObject();
foreach (KeyValuePair<string, object> property in dapperRowProperties)
expando.Add(property.Key, property.Value);
return expando as ExpandoObject;
}
}
Then you can use that like this:
IEnumerable<ExpandoObject> result =
db.SqlConn.Query(sqlScript)
.Select(x=> (ExpandoObject)ToExpandoObject(x));
reference: dapper-dot-net issues 166
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.