Use JSON_ARRAYAGG with Entity Framework Core - c#

I am trying to use JSON_ARRAYAGG(JSON_OBJECT(...)) in Entity Framework Core but I don't know much how to trick Entity Framework Core to use this function with a custom IQueryable<T>.
Does anybody have any simple example how this can be achieved ?
I can not build a raw query because the IQueryable is built dynamically based on params, but my idea was to first build the IQueryable<T> and then somehow combine that with the given functions. Lets take a simple example of what I want to achieve:
var people = await db.People.Select(x => new Person { Name = x.Name, Surname = x.Surname }).ToListAsync();
This will translate to:
select name, surname from people;
I want to have:
select JSON_ARRAYAGG(JSON_OBJECT("name", name, "surname", surname) from people;
One solution is to get the query from the IQueryable and do a nasty replace on the final string, but this does not seem a very good solution.
Is there any way I can modify the list of params on runtime without using replace function ?

Related

Passing a GetWhere query (Func<entityDTO,bool>) to a data layer method which needs a (Func<entity,bool>) parameter to work

I have the following method in a data access class which uses entity framework:
public static IEnumerable<entityType> GetWhere(Func<entityType, bool> wherePredicate)
{
using (DataEntities db = new DataEntities())
{
var query = (wherePredicate != null)
? db.Set<entityType>().Where(wherePredicate).ToList()
: db.Set<entityType>().ToList();
return query;
}
}
This works fine when I use the entities across all layers... however I am trying to move to using a DTO class and I would like to do something like the following:
public static IEnumerable<EntityTypeDTO> GetWhere(Func<EntityTypeDTO, bool> wherePredicate)
{
//call a method here which will convert Func<EntityTypeDTO,bool> to
// Func<EntityType,bool>
using (DataEntities db = new DataEntities())
{
var query = new List<EntityType>();
if (wherePredicate == null)
{
query = db.Set<EntityType>().ToList();
}
else
{
query = (wherePredicate != null)
? db.Set<EntityType>().Where(wherePredicate).AsQueryable<EntityType>().ToList()
: db.Set<EntityType>().ToList();
}
List<EntityTypeDTO> result = new List<EntityTypeDTO>();
foreach(EntityType item in query)
{
result.Add(item.ToDTO());
}
return result;
}
}
Essentially I want a method which will convert Func to Func.
I think I have to break down the Func into an expression tree and then rebuild it somehow in the entityType?
I want to do this to allow the Presentation Layer to just pass the Expression queries?
Am I missing something basic or is there an easier design pattern that can pass a query from a DTO to a data access class without knowing the details of the query?
I have tried making the DTO inherit from the entity which doesn't seem to work either?
If there is a better design pattern that I am missing I would love a pointer and I can investigate from there...
Firstly I would suggest that you put a querying layer of your own in front of Entity Framework rather than allowing any arbitrary Func to be passed in because it will be very easy in the future to pass a Func that Entity Framework can not translate into a SQL statement (it can only translate some expressions - the basics are fine but if your expression calls a C# method, for example, then Entity Framework will probably fail).
So your search layer could have classes that you build up as criteria (eg. a "ContainsName" search class or a "ProductHasId" class) that are then translated into expressions in your search layer. This separates your app entirely from the ORM, which means that ORM details (like the entities or like the limitations of what Funcs can and can't be translated) don't leak out. There's lots out there that's been written about this some of arrangement.
One final note, though, if you are working close to the ORM layer, Entity Framework is very clever and you could probably get a long way without trying to translate your Func<dto, bool> to a Func<entity, bool>. For example, in the below code, accessing "context.Products" returns a "DbSet" and calling Select on it returns an IQueryable and calling Where on that also returns an IQueryable. Entity Framework will translate all of that into a single SQL statement so it won't pull all other Products into memory and then filter the ID on that memory set, it will actually perform the filtering in SQL even though the filter is operating on a projected type (which is equivalent to the DTO in your case) and not the Entity Framework entity -
var results = context.Products
.Select(p => new { ID = p.ProductID, Name = p.ProductName })
.Where(p => p.ID < 10)
.ToList();
The SQL executed is:
SELECT
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductName] AS [ProductName]
FROM [dbo].[Products] AS [Extent1]
WHERE [Extent1].[ProductID] < 10
So, if you changed your code to get something like..
return context.Products
.Map<Product, ProductDTO()>()
.Where(productDtoWherePredicate)
.ToList();
.. then you might be just fine with the Funcs that you already have. I presume that you already have some sort of mapping functions to get from EF entities to DTOs (but if not then you might want to look into AutoMapper to help you out - which has support for "projections", which are basically IQueryable maps).
I am going to put this up as an answer.Thanks to Dan for the quick answer. Looking at what you are saying I can write a query/filter set of classes. for example, take the following code:
GetProducts().GetProductsInCategory().GetProductsWithinPriceRange(minPrice, maxPrice);
This code would run like so: Get Products would get all products in the table and the remaining functions would filter the results. if all queries run like this it may put a significant load on the Data Access Layer/ DB Server Connections... not sure.
or
An Alternate I will work on also is:
If each function creates a Linq expression, I could combine them like this: How do I combine multiple linq queries into one results set?
this may allow me to do this in a manner where I can return the filtered results set from the database.
Either way I am marking this as answered. I will update when I have more details.

Entity Framework get specific column from a string

I have a Web API project that uses Entity Framework. I have an action api/account that given an ID returns that account.
There is an additional parameter that can be provided which is what fields to be returned e.g. api/account?field=name
I'm trying to work out the best way of translating from this string input to Entity Framework. I know I can use .Select() to only get certain columns but that takes in a Func and the only way I can think of getting from the string to a Func is by using Reflection. This seems like it will be a peformance hit if I have to do Reflection for every property passed in, is there a better way of doing this?
Thanks
You can use this library System.Linq.Dynamic from Nuget, and this query
var selectStatement = string.Format("new ({0},{1})", field1, field2);
var result = db.Users.Select(selectStatement).ToListAsync().Result;

Converting IQueryable<T> object to another object?

I have no idea what the keywords are so here is an example of what I want:
return from i in userRepo.GetUsers()
select new SimpleUser{
i.UserId,
i.Name
};
userRepo.GetUsers() returns type IQueryable<User>. I'd like to convert this to IQueryable<SimpleUser> to I can restrict access to certain properties of the User domain.
How do I do this without hard coding the translation like this? What about tools like automapper or ValueInjecter, how can they do this?
Also, what is this technique called?
You must hardcode the translation or you must first convert it to IEnumerable. IQueryable represents expression tree translated to some execution in used provider - in your case I believe it will be Entity framework. You can't use any automatic mapping in such query because it will be translated to SQL which will not understand your .net methods or AutoMapper. Projections to custom types are part of the query and must be hardcoded. You can create custom extension method to IQueryable and reuse it where you need:
public static IQueryable<SimpleUser> ProjectToSimpleUser(this IQueryable<User> query)
{
return query.Select(u => new SimpleUser
{
// Here map your fields
});
}
Now you can use:
return repo.GetUsers().ProjectToSimpleUser();
In case of Entity framework SimpleUser mustn't be an mapped entity.
Provided that SimpleUser is assigneable to User (User is an interface of baseclass of SimpleUser), you can
var users = simpleUsers.Cast<User>();
optionally with
var users = simpleUsers.Cast<User>().AsQueryable();
And if you're not sure whether all items are actually Users, then you can use OfType<User> instead of Cast<User>
AutoMapper is the tool you want; it works via reflection and unless you tell it to do otherwise, it will map properties with the same name directly.
Auto-mapping is the technique.
This question is 9 years old so idk if it existed then but for anyone searching now, using .FirstOrDefault() works if you pick a single user.

how to do a Join in Entity Framework

Instead of writing a linq query, is there a way I can just do a join by simply doing something like this:
using (var db = new MatchGamingEntities())
{
db.Accounts.Join() //I am unsure of the syntax
db.Accounts.Include...
...
return View(Account.SingleOrDefault());
}
I want to use these predefined Entity functions instead of writing linq, is it practical? Also how do you use these predefined functions? I have a table called "Accounts" and "BankTransactions" they both have AccountId in common, How would I query that using these functions and what type of result would it return its one to many relationship.
LINQ is really your better bet, things start to get hectic in Lambda's really fast and linq just looks a lot better given the structured way compared to lambda's
See this SO Post:
C# Joins/Where with Linq and Lambda
var query = db.Accounts.Join(db.BankTransactions,
acc => acc.AccountID,
bank => bank.AccountID,
(acc,bank) => new { Account = acc, BankTransaction = bank });
Edit:
This should(or something similar) return a query that will return a collection of Accounts and inside each account it's relevant BankTransaction.
This should do it but again, rather use LINQ if possible.
Edit: Just as an afterthought, you can add additional lamba extensions like a where clause to the above one.

Can you apply OOP to Linq Projections?

Using
Visual Studio 2010
.Net Framework 4
C#
Linq to Entities
Issue
I would like to be able to apply Object Oriented Principles like DRY and SOLID to some Linq Projections. With compiled queries or passed parameters I can apply these to the rest of Linq successfully so far, just not in the projections.
Please let me know if this isn't possible, and I must choose one of my alternate solutions (described below), if it is possible then how, or if I am missing something and there is another alternative implementation that will satisfy the goal.
Details
At a high level I would like to be able to dynamically control the type used in a Linq Projection, either with a standard Linq Query or a CompiledQuery. I am using Linq to Entities in my examples and actual code, however the issue should be applicable to the core Linq.
Below are simplistic examples that are not dynamic and do not solve the issue. They are fixed to always use the FooUser for each type. What I would like to be able to do is dynamically control the type of user created in the projection all of which would be based on a common IUser interface. This would be or could be similar to how I can control what type the query filters on.
Alternate Solutions
I am trying to conform to DRY, SOLID, and also trying to avoid using an enum to deal which is a typical code smell. However in all my attempts and research I seem to have to fall to one of the following solutions.
Implement a query for each type
which are all the same except for
the type they filter on and the type
used int he projection. While this
violates DRY and OCP, I can
encapsulate this within a single
class and keep them close together
as complied queries. This will
require the class to change if I add
a new type or if how you query for
the data changes.
Implement a enum that has the types, and use a more generalized User class that has its type as a property. However this will cause me to have to use the enum in several locations and introduce long case statements to handle them, which I would like to avoid.
I would love not to have to choose between different evils, and have an implementation that can conform to all SOLID principles and DRY. However if I must I think I will end up with the first or a version of it.
Examples
Standard Simple Linq Query
using (MyEntities context = new MyEntities())
{
var results = from u in context.Users
where u.UserType == type
select new FooUser
{
Id = u.UserID,
Name = u.UserName,
Location = u.UserLocation
};
}
Compiled Version of the Above Query
private static readonly Func<MyEntities, int, IQueryable<FooUser>> query = CompiledQuery.Compile<MyEntities, int, IQueryable<FooUser>>(
(context, type) => from u in context.Users
where u.UserType == type
select new FooUser
{
Id = u.UserID,
Name = u.UserName,
Location = u.UserLocation
});-
I found a way to do this with a standard method call. I haven't figured out how to do it with a compiled query, it doesn't look likely.
I was not aware of the Constructor Constraint I on the where statement for a generic. This can suit my needs. I would love to do this with a compiled query, but can live happy with this solution.
public IQueryable<IUser> FooMethod<T>(int type) where T : IUser, new()
{
using (MyEntities context = new MyEntities())
{
var results = from u in context.users
where u.usertype == type
select new T
{
id = u.UserId,
name = u.UserName,
location = u.Userlocation
};
return results;
}
}
I chose to post an answer instead of deleting the question for two reasons, one in case others are looking for something similar it could be helpful. Then of course I could be way off base and its is always fun to have people shoot holes in things and see what better stuff we can come up with.

Categories

Resources