Recently I have been playing with AutoMapper as a tool to populate our DTOs.
The cool thing about AutoMapper is its Project().To() that let us map a Queryable so that we can select the fields that we want according to our map.
But here we have another scenario too.We want to be able to translate some of the values of an entity into other representation.
Suppose that we have a string field that its value in DB is 'Apparatment' and we want to translate it to another language while we are selecting our DTOs.
I think that if we want to write this in SQL it will be something like this :
SELECT CASE BuidlingType WHEN 'Appartment' THEN 'apparatment in another langaure' WHEN 'Flat' THEN 'flat in another languate' END AS BuildingType FROM buildings
I know that we can define value resolvers in AutoMapper. The question I would like to ask is ,can we use these resolvers in a Project().To() scenario ? If the answer is yes then how we should use them (to return an expression instead of a value) and if not , is there any other alternative approach to be able to translate a DTO on the fly ?
No you can't use resolvers in LINQ projections.
I guess I'm a little confused - those translations look a little difficult in the SQL you have. Are your translations stored in a database, or do you hard code them in your SQL?
Typically my localized labels are stored either in resource files or specialized tables. If they're in tables, I don't necessarily returned translated data labels with data. I have two queries and the translation query is almost certainly cached.
I would start with "What LINQ do I build to make the correct SQL" and then I can help with "how can I configure AutoMapper to build this LINQ?"
Related
I was wondering if it was possible to select/build a multilevel object hierarchy in one single query? As I'm not sure about the terminology, I'll give an example:
Let's say we have a Product, which has one Subrange, which has one Range, which has one Provider.
I can easily build my Product POCO with its Subrange with
Db.Products.WithSubrange.Get(#id);
But could I build it with Product.Subrange.Range and Product.Subrange.Range.Provider in a single query?
I've tried several ways, like:
Db.Products.With(Db.Products.Subrange.WithRange()).Get(#id);
Db.Products.With(Db.Subrange.WithRange()).Get(#id);
but I can't find it out. It would be ok to query the Range and Provider afterward (it's already amazing this way) but a single query would be nice. Explicit Joins maybe?
BTW if Sir Rendle happens to come-by, I would like to thank him for his amazing work. Simple.Data rocks!
Try chaining the 'With's
Db.Products.WithSubRange().WithRange().WithProvider().Get(#id);
Alternatively you can use
Db.Products.FindAllById(#id).WithSubRange().WithRange().WithProvider().FirstOrDefault();
Read: http://simplefx.org/simpledata/docs/pages/Retrieve/LazyVsEagerLoading.htm
The act of doing what you have described relates to the terms "Lazy Loading" and "Eager Loading".
I have a problem where I have to get the column names and their values from all the Tables in my schema and show that the result in a grid.
I have used the direct approach for this but I have to implement the SqlSiphon structure. For this I have to make getters and setters of each of the column of each Table in the schema which is impossible.
What should I use to get the Column names and their values dynamically from the table.
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = '" + #Tablename1 + "' AND TABLE_SCHEMA='dbo'"
What will be the best dynamic solution?
And what will be Best to use List , Dictionay or something like 2d Array which will give the column names as well as column values?
A few suggestions:
I'm not completely clear on what you're trying to achieve, but consider using an ORM (Linq2SQL, WEF, NHibernate)
In .NET, a suitable type to represent a database table would be a DataTable
Edit: After a few more re-reads I think I understand what you're asking - you already have a database/schema and you want to automatically create the entity classes needed by SqlSiphon. This is called "database-first" (as opposed to model-first). However, from a brief scan of the SqlSiphon documentation it appears it does not support database-first. Is this why you are trying to put the columns into a grid - to make it easier to manually create the entity classes for SqlSiphon?
Edit2: Note that trying to use an ORM on top of a database whose schema is frequently modified will be problematic. My next guess is that you're trying to figure out how to create an entity class in SqlSiphon which you can use to retrieve database schema information like table columns? I'm still struggling to understand what you're actually asking here - perhaps you can update your question?
Edit3: I think the answer to your question is take a different approach to your design - ORM's like SqlSiphon are not intended to be used to retrieve and modify the database schema itself.
Might be worth taking a step back an comparing against how other people solve similar problems.
Typically, each table on a database represents an entity, and you also have a class per entity, and you may use an ORM system to avoid duplication of work. So, in a typical system, you have a table for customers, and a table for invoices, and a table for invoice lines, etc. and then a class that represents a customer, a class for an invoice, a class for an invoice line, etc. As you later add functionality (and possible columns/properties) you change the classes, rather than just seeing what columns are on the database - you can of course decorate these with XML documentation and get Intelisense goodness.
There are many ORM systems out there, and each have their strengths and weaknesses, but I personally like LINQ to SQL for adding onto an existing data model.
I'm looking for anyone who's done anything along the lines of querying JSON strings with the Entity Framework.
I should give a little background about what I'm trying to do here. The database I'm using is for a workflow engine that I'm working on. It handles all the workflow data, and also allows you to store some custom data as a JSON string. The workflow engine I'm using handles the serializing and de-serializing of the JSON strings on a per request basis, but in the event I would want to do a query and filter based on values in the JSON string, I would have to pull the entire table into memory and de-serialize all the entries and then filter. This is, for obvious reasons, not acceptable. The reason for doing this, is we want a single workflow database that can be used for all applications that use this workflow engine, and we are trying to avoid having to do cross database views to seperate application specific databases to get the custom data. Since in most cases, the custom request data that is being stored as JSON strings is relatively simple, and in most cases isn't needed when querying, which is by design. But in the event that we do need to do custom searches, we need a way to be able to parse these custom JSON objects. And I'm hoping this can be done dynamically with Entity so I don't have to write extra stored procs for querying specific types of objects. Ideally I would just have one library that uses entity to allow querying of any JSON data structure.
I started with a database function that I found that parses JSON and returns a flattened table that contains the values (parent object id, name, value, and type). Then imported that function into my entity model. Here's a link to where I got the code from. Pretty interesting article.
Consuming JSON Strings in SQL Server
Here's the basics of where I'm at.
using (var db = new WorkflowEntities()) {
var objects = db.Requests.RequestData();
}
In the above code example, Request object is my base workflow Request object. RequestData() is an extension method on type
DbSet<Request>
and parseJSON is the name of my database function.
My plan is to write a series of extension methods that will filter the Queryables
IQueryable<parseJSON_result>
So for example, if I have an object that looks like this.
RequestDetail : {
RequestNumber: '123',
RequestType: 1,
CustomerId: 1
}
I would be able to do something like
db.Request.RequestData().Where("RequestType", 1);
or something along those lines. The .Where method would Take RequestData(), which is an IQueryable that contains the parsed JSON, it would filter and return the new IQueryable result.
So my question really is, has anyone done anything like this? If so, what kind of approach have you taken? My original intent was to do something dictionary style, but it seemed too difficult. Any thoughts, ideas, suggestions, wisdom, would be much appreciated. I worked on this for awhile, and I feel like I really didn't get that far. Which is mostly just because I can't decide how I want the syntax to look, and I'm not sure if I should be doing more work database side.
This was my original idea for syntax, but I couldn't run the [] operator without hydrating the object.
db.Request.Where(req => req.RequestData()["RequestType"] == 1).Select(req => req.RequestData()["CustomerInfo"]);
I know this is a pretty long post, so if you've read this far, thanks for just taking the time to read the whole thing.
As of SQL Server 2016, FOR JSON and OPENJSON exist, equivalent to FOR XML and OPENXML. You can Index on expressions that reference JSON stored in NVARCHAR columns.
This is a very late answer, but for anyone who is still searching...
As #Emyr says, SQL 2016 supports querying inside JSON columns using JSON_VALUE or OPENJSON statements.
Entity Framework still does not support this directly, but you can use the SqlQuery method to run a raw SQL command directly against the database which can query inside JSON columns and saves querying and deserializing every row in order to run a simple query.
What you could do is create a CLR SQL Server User-Defined Function then use it from your query.
See this link https://msdn.microsoft.com/en-us/library/ms131077.aspx
i would think that a table-valued functions is more suited for your situation.
I create a EDM using my database and saw that while it was able to make relations like
Customers.First().Orders
there is nothing like
Customer.First().Orders.FindOrderByOrderID()
Customer.First().Orders.FindOrderByOrderName()
etc.
Maybe I was expecting it to be like that and that's how it doesnt work
and I will probably just have to LINQ to entities and create mangers that handle business logic in them.
or does LINQ to SQL do this?
You can use LINQ with the Orders property, like this:
var order = Customer.First().Orders.FirstOrDefault(o => o.OrderId == someId);
This will return null if there was no matching Order.
With LINQ to Entities you can do this. Such as the example SLaks posted above.
If you're feeling adventurous, it is possible to write a function to do this. Since Entity Framework knows which column is the primary key it is possible to write a function like GetEntityByPrimaryKey.
CodeProject has an article regarding the repository pattern and if you search for "SelectByKey" you'll see their implementation of that. I use something similar and find it very helpful.
The idea is that you can use LINQ to write more flexible queries. Note, however, that you could probably so something like FindOrderByOrderName in .NET 4.0 by creating your own dynamic type (not trivial), that responded to calls following this pattern by building a LINQ query automatically. You'd lose intellisense, of course, and I doubt it would be worth it, but it could be done.
I have been puzzling over a problem this morning with LinqToSQL. I'll try and summarise with the abbreviated example below to explain my point.
I have DB two tables:
table Parent
{
ParentId
}
table Child
{
ChildId
ParentId [FK]
Name
Age
}
These have LinqToSQL equivalent classes in my project, however, I have written two custom model classes that I want my UI to use, instead of using the LinqToSQL classes.
My data access from the front end goes through a service class, which in turn calls a repository class, which queries the data via linq.
At the repository level I return an IQueryable by:
return from data in _data.Children
select new CustomModel.Child
{
ChildId = data.ChildId,
ParentId = date.ParentId
};
My service layer then adds an additional query restriction by parent before returning the list of children for that parent.
return _repository.GetAllChildren().Where(c => c.Parent.ParentId == parentId).ToList();
So at this point, I get the method has no supported translation to sql error when I run everything as the c.Parent property of my custom model cannot be converted. [The c.Parent property is an object reference to the linked parent model class.]
That all makes sense so my question is this:
Can you provide the querying process
with some rules that will convert a
predicate expression into the correct
piece of SQL to run at the database
and therefore not trigger an error?
I haven't done much work with linq up to now so forgive my lack of experience if I haven't explained this well enough.
Also, for those commenting on my choice of architecture, I have changed it to get around this problem and I am just playing around with ideas at this stage. I'd like to know if there is an answer for future reference.
Many thanks if anyone can help.
Firstly, it begs the question: why is the repository returning the UI types? If the repo returned the database types, this wouldn't be an issue. Consider refactoring so that the repo deals only with the data model, and the UI does the translation at the end (after any composition).
If you mean "and have it translate down to the database" - then basically, no. Composable queries can only use types defined in the LINQ-to-SQL model, and a handful of supported standard functions. Something similar came up recently on a related question, see here.
For some scenarios (unusual logic, but using the typed defined in the LINQ-to-SQL model), you can use UDFs at the database, and write the logic yourself (in TSQL) - but only with LINQ-to-SQL (not EF).
If the volume isn't high, you can use LINQ-to-Objects for the last bit. Just add an .AsEnumerable() before the affected Where - this will do this bit of logic back in managed .NET code (but the predicate won't be used in the database query):
return _repository.GetAllChildren().AsEnumerable()
.Where(c => c.Parent.ParentId == parentId).ToList();