How to change a field value in EF Core Select - asp.net-core

Imagine that an entity has many fields and I just want to make changes in 1-2 fields, Is it possible to do that in Select? I don't want to mention all fields in my Select cause.
Ex: I want to return all fields and make a tiny change in OrderId field at the same time.
_context.Set<Table>.Select(t=>t.OrderId=t.OrderId+1)

A workaround I've found is to use select and copy every field to a new instance of your entity/object and change the field you want a computed value for, like:
_context.Operations
.Where(t => t.SessionId == sessionId)
.Select(o => new Operation
{
OperationId = o.OperationId + 1;
SessionId = o.SessionId,
Amount = o.Amount,
Date = o.Date,
});

Related

Entity Framework problem with reducing projection

I've been working on improving performance for our .NET core API with EF 5.0.11 by reducing the projection of our queries, but I'm currently stuck with the following scenario:
I improved the projection of the queries like this:
var employeeEmailQuery = context.Employee
.Where(e => e.Active == true)
.Select(e => new EmployeeEmailView
{
Name = e.FullName,
Email = e.Email
});
This reduces the select query to just the two columns I need instead of a SELECT * on 80+ columns in the database.
In my database, I also have columns with translated descriptions. It looks like this:
What I would like to do is select the relevant translated description, based on the current culture, so I added the following code:
var culture = CultureInfo.DefaultThreadCurrentUICulture;
var employeeEmailQuery = context.Employee
.Where(e => e.Active == true)
.Select(e => new EmployeeEmailView
{
Name = e.FullName,
Email = e.Email,
this.SetDescription(e, culture);
});
The SetDescription method checks the culture and picks the correct column to set a Description property in the EmployeeEmailView. However, by adding this code, the query is now once again doing a SELECT *, which I don't want.
Does anybody have an idea on how to dynamically include a select column using EF without rewriting everything into raw SQL?
Thanks in advance.
I think the only way is to use an Interceptor to modify the query, or dynamically generate the EF IQueryable with Expressions.

MVC update the database based on a non primary key value

I have a database table that looks like this:
My goal is to update my "unavail" table based on the ID of either the component, part, or item depending on which one is relevant in my situation.
For example, if the partID = 43 I want to add to the 'unavail' column
I first started working on this by trying this
db.OffSiteItemDetails.Find(sod.PartID).unavail += sod.comp_returned;
(Where sod.PartId = 43)
But I quickly realized it was just checking for where the "ID" was equal to 43 which isn't what I want. After some investigation I saw people suggesting using
db.Where(x => x.non-pk == value)
So I created this
db.OffSiteItemDetails.Where(x => x.componentID == sod.ComponentID);
But from here I don't know how to change my unavail table values.
This was a tough question to type so if you need more clarity just ask
foreach(var item in db.OffSiteItemDetails.Where(x => x.componentID == sod.ComponentID))
{
// item.unavail = [new value]
// db.Update(item);
// ...I don't know how you update the data in your database
}
Something like that?

play-slick scala many to many

I have an endpoint lets say /order/ where i can send json object(my order), which contains some products etc, so my problem is i have to first save the order and wait for the order id back from the db and then save my products with this new order id( we are talking many to many relation thats why theres another table)
Consider this controller method
def postOrder = Action(parse.json[OrderRest]) { req => {
Created(Json.toJson(manageOrderService.insertOrder(req.body)))
}
}
this is how my repo methods look like
def addOrder(order: Order) = db.run {
(orders returning orders) += order
}
how can i chain db.runs to first insert order, get order id and then insert my products with this order id i just got?
im thinking about putting some service between my controller and repo, and managing those actions there, but i have no idea where to start
You can use for to chain database operations. Here is an example of adding a table to a db by adding a header row to represent the table and then adding the data rows. In this case it is a simple table containing (age, value).
/** Add a new table to the database */
def addTable(name: String, table: Seq[(Int, Int)]) = {
val action = for {
key <- (Headers returning Headers.map(_.tableId)) += HeadersRow(0, name)
_ <- Values ++= table.map { case (age, value) => ValuesRow(key, age, value) }
} yield key
db.run(action.transactionally)
}
This is cut down from the working code, but it should give the idea of how to do what you want. The first for statement would generate the order id and then the second statement would add the order with that order id.
This is done transactionally so that the new order will not be created unless the order data is valid (in database terms).

Need help creating a linq select

I need some help creating an LINQ select, i have a table with some columns in it, but only 2 of interest to this problem.
userid, type
Now this table have many thousands entries, and I only want the top, let’s say 50. So far so good, but the hard part is that there a lot of rows in success that should only be counted as 1.
Example
Type UserId
============
Add 1
Add 1
Add 1
Add 2
I would like this to only be counted as 2 in the limit of rows I am taking out, but I would like all the rows to be outputted still.
Is this possible with a single SQL request, or should I find another way to do this?
Edit: I can add columns to the table, with values if this would solve the problem.
Edit2: Sotred procedures are also an solution
Example 2: This should be counted as 3 rows
Type UserId
============
Add 1
Add 1
Add 2
Add 1
Are you stuck on LINQ?
Add a PK identity.
Order by PK.
Use a DataReader and just count the changes.
Then just stop when the changes count is at your max.
If you are not in a .NET environment then same thing with a cursor.
Since LINQ is deferred you might be able to just order in LINQ and then on a ForEach just exit.
I'm not close to a computer right now so I'm not sure is 100% correct syntax wise, but I believe you're looking for something like this:
data.Select(x => new {x.Type, x.UserId})
.GroupBy(x => x.UserId)
.Take(50);
You could do it with Linq, but it may be a LOT slower than a traditional for loop. One way would be:
data.Where((s, i) => i == 0 ||
!(s.Type == data[i-1].Type && s.UserId == data[i-1].UserId))
That would skip any "duplicate" items that have the same Type and UserID as the "previous" item.
However this ONLY works if data has an indexer (an array or something that implements IList). An IEnumerable or IQueryable would not work. Also, it is almost certainly not translatable to SQL so you'd have to pull ALL of the results and filter in-memory.
If you want to do it in SQL I would try either scanning a cursor and filling a temp table if one of the values change or using a common table expression that included a ROW_NUMBER column, then doing a look-back sub-query similar to the Linq method above:
WITH base AS
(
SELECT
Type,
UserId,
ROW_NUMBER() OVER (ORDER BY ??? ) AS RowNum
FROM Table
)
SELECT b1.Type, b1.UserId
FROM base b1
LEFT JOIN base b2 ON b1.RowNum = b2.RowNum - 1
WHERE (b1.Type <> b2.Type OR b1.UserId <> b2.UserId)
ORDER BY b1.RowNum
You can do this with LINQ, but I think it might be easier to go the "for(each) loop" route...
data.Select((x, i) => new { x.Type, x.UserId, i })
.GroupBy(x => x.Type)
.Select(g => new
{
Type = g.Key,
Items = g
.Select((x, j) => new { x.UserId, i = x.i - j })
})
.SelectMany(g => g.Select(x => new { g.Type, x.UserId, x.i }))
.GroupBy(x => new { x.Type, x.i })
.Take(50);
.SelectMany(g => g.Select(x => new { x.Type, x.UserId }));

How can I recreate this complex SQL Query using NHibernate QueryOver?

Imagine the following (simplified) database layout:
We have many "holiday" records that relate to going to a particular Accommodation on a certain date etc.
I would like to pull from the database the "best" holiday going to each accommodation (i.e. lowest price), given a set of search criteria (e.g. duration, departure airport etc).
There will be multiple records with the same price, so then we need to choose by offer saving (descending), then by departure date ascending.
I can write SQL to do this that looks like this (I'm not saying this is necessarily the most optimal way):
SELECT *
FROM Holiday h1 INNER JOIN (
SELECT h2.HolidayID,
h2.AccommodationID,
ROW_NUMBER() OVER (
PARTITION BY h2.AccommodationID
ORDER BY OfferSaving DESC
) AS RowNum
FROM Holiday h2 INNER JOIN (
SELECT AccommodationID,
MIN(price) as MinPrice
FROM Holiday
WHERE TradeNameID = 58001
/*** Other Criteria Here ***/
GROUP BY AccommodationID
) mp
ON mp.AccommodationID = h2.AccommodationID
AND mp.MinPrice = h2.price
WHERE TradeNameID = 58001
/*** Other Criteria Here ***/
) x on h1.HolidayID = x.HolidayID and x.RowNum = 1
As you can see, this uses a subquery within another subquery.
However, for several reasons my preference would be to achieve this same result in NHibernate.
Ideally, this would be done with QueryOver - the reason being that I build up the search criteria dynamically and this is much easier with QueryOver's fluent interface. (I had started out hoping to use NHibernate Linq, but unfortunately it's not mature enough).
After a lot of effort (being a relative newbie to NHibernate) I was able to re-create the very inner query that fetches all accommodations and their min price.
public IEnumerable<HolidaySearchDataDto> CriteriaFindAccommodationFromPricesForOffers(IEnumerable<IHolidayFilter<PackageHoliday>> filters, int skip, int take, out bool hasMore)
{
IQueryOver<PackageHoliday, PackageHoliday> queryable = NHibernateSession.CurrentFor(NHibernateSession.DefaultFactoryKey).QueryOver<PackageHoliday>();
queryable = queryable.Where(h => h.TradeNameId == website.TradeNameID);
var accommodation = Null<Accommodation>();
var accommodationUnit = Null<AccommodationUnit>();
var dto = Null<HolidaySearchDataDto>();
// Apply search criteria
foreach (var filter in filters)
queryable = filter.ApplyFilter(queryable, accommodationUnit, accommodation);
var query1 = queryable
.JoinQueryOver(h => h.AccommodationUnit, () => accommodationUnit)
.JoinQueryOver(h => h.Accommodation, () => accommodation)
.SelectList(hols => hols
.SelectGroup(() => accommodation.Id).WithAlias(() => dto.AccommodationId)
.SelectMin(h => h.Price).WithAlias(() => dto.Price)
);
var list = query1.OrderByAlias(() => dto.Price).Asc
.Skip(skip).Take(take+1)
.Cacheable().CacheMode(CacheMode.Normal).List<object[]>();
// Cacheing doesn't work this way...
/*.TransformUsing(Transformers.AliasToBean<HolidaySearchDataDto>())
.Cacheable().CacheMode(CacheMode.Normal).List<HolidaySearchDataDto>();*/
hasMore = list.Count() == take;
var dtos = list.Take(take).Select(h => new HolidaySearchDataDto
{
AccommodationId = (string)h[0],
Price = (decimal)h[1],
});
return dtos;
}
So my question is...
Any ideas on how to achieve what I want using QueryOver, or if necessary Criteria API?
I'd prefer not to use HQL but if it is necessary than I'm willing to see how it can be done with that too (it makes it harder (or more messy) to build up the search criteria though).
If this just isn't doable using NHibernate, then I could use a SQL query. In which case, my question is can the SQL be improved/optimised?
I have manage to achieve such dynamic search criterion by using Criteria API's. Problem I ran into was duplicates with inner and outer joins and especially related to sorting and pagination, and I had to resort to using 2 queries, 1st query for restriction and using the result of 1st query as 'in' clause in 2nd creteria.