how to use in clause in Linq Query and pass it dynamically from code - asp.net-core

I am converting my project to EF Core in my old project I have a query running.
IDictionary<int, IGrouping<int, UserPurchaseItemAddonWithAmount>> addons =
context.Fetch<UserPurchaseItemAddonWithAmount>($"Select UPIA.*, EA.Amount From UserPurchaseItemAddons UPIA Inner Join ExtraAddons EA on UPIA.AddonID = EA.AddonID Where UPIA.UserPurchaseItemID in ({string.Join(',', userPurchaseItems.Select(S => S.UserPurchaseItemID))})")
.GroupBy(G => G.UserPurchaseItemID).ToDictionary(D => D.Key);
I need to convert this query in to Linq query what I am doing is below
IDictionary<int, IGrouping<int, UserPurchaseItemAddonWithAmount>> addons =
(from f in context.UserPurchaseItemAddons
join s in context.ExtraAddons
on f.AddonId equals s.AddonId
select new
{
Amount = s.Amount,
UserPurchaseItemAddonID = f.UserPurchaseItemAddonId,
UserPurchaseItemID = f.UserPurchaseItemId,
BranchItemVariantID = f.BranchItemVariantId,
AddonID = f.AddonId,
UserID = f.UserId,
IsDeleted = f.IsDeleted,
ModifiedOn = f.ModifiedOn,
ModifiedBy = f.ModifiedBy,
Reason = f.Reason,
}).GroupBy(G => G.UserPurchaseItemID).ToDictionary(D => D.Key);
This query is causing a compiler error related to casting to IGrouping<int, UserPurchaseItemAddonWithAmount> to an anonymous type. The other thing is that how can I apply in clause in where condition in above query, just like the first query .
class
public class UserPurchaseItemAddonWithAmount
{
public decimal Amount { get; set; }
public int UserPurchaseItemAddonID { get; set; }
public int UserPurchaseItemID { get; set; }
public int BranchItemVariantID { get; set; }
public int AddonID { get; set; }
public int UserID { get; set; }
public bool IsDeleted { get; set; }
public DateTime? ModifiedOn { get; set; }
public int? ModifiedBy { get; set; }
public string? Reason { get; set; }
}

Try the following query. Main mistake that you have returned anonymous class.
var purchaseItemIds = userPurchaseItems.Select(S => S.UserPurchaseItemID);
IDictionary<int, IGrouping<int, UserPurchaseItemAddonWithAmount>> addons =
(from f in context.UserPurchaseItemAddons
join s in context.ExtraAddons on f.AddonId equals s.AddonId
where purchaseItemIds.Contains(f.UserPurchaseItemID)
select new UserPurchaseItemAddonWithAmount
{
Amount = s.Amount,
UserPurchaseItemAddonID = f.UserPurchaseItemAddonId,
UserPurchaseItemID = f.UserPurchaseItemId,
BranchItemVariantID = f.BranchItemVariantId,
AddonID = f.AddonId,
UserID = f.UserId,
IsDeleted = f.IsDeleted,
ModifiedOn = f.ModifiedOn,
ModifiedBy = f.ModifiedBy,
Reason = f.Reason,
})
.AsEnumerable()
.GroupBy(G => G.UserPurchaseItemID)
.ToDictionary(D => D.Key);

Related

Conversion of this sql query to LINQ query

I want to convert this sql query into a linq query.
SELECT
CreationUtcTime,
Speed,
convert((CreationUtcTime - LAG(CreationUtcTime) OVER (ORDER BY CreationUtcTime)), char) AS diff
FROM assetstatusrecords
WHERE
Speed <> 0.00 and
CreationUtcTime <= '2022-03-28' and
CreationUtcTime >= '2022-02-21' and
AssetId = '7556d50c-95e5-4cd5-a31d-b4d6c6ab1fb1'
ORDER BY CreationUtcTime
Model Class for LINQ
class AssetStatusRecord : Entity
{
protected AssetStatusRecord()
{
}
public AssetStatusRecord(CoordinatesValue coordinates, double speed,
LengthValue distanceTravelled, Guid sensorId, Guid? assetId,
int? heading, Guid readingId, DateTime? sensorDateTime)
{
Coordinates = coordinates;
Speed = speed;
DistanceTravelled = distanceTravelled;
SensorId = sensorId;
AssetId = assetId;
Heading = heading;
ReadingId = readingId;
SensorDateTime = sensorDateTime;
}
public CoordinatesValue Coordinates { get; private set; }
public double Speed { get; private set; }
public LengthValue DistanceTravelled { get; private set; }
public Guid SensorId { get; private set; }
public Guid? AssetId { get; private set; }
public int? Heading { get; private set; }
public Guid ReadingId { get; private set; }
public DateTime? SensorDateTime { get; private set; }
}
And the Entity Class are as follows : -
public class Entity : IEntity
{
public Entity();
public Guid Id { get; protected set; }
public long SequentialId { get; protected set; }
public DateTime CreationUtcTime { get; protected set; }
public DateTime CreationLocalTime { get; protected set; }
}
And the Interface IEntity :-
public interface IEntity
{
Guid Id { get; }
long SequentialId { get; }
DateTime CreationUtcTime { get; }
}
This model class can be used to execute linq query which I am using in below query in comments
If you are using EF Core, you can execute such query via linq2db.EntityFrameworkCore extension. Note that I'm one of the creators.
With this extension you can use LAG in LINQ query:
var query =
from s in context.AssetStatusRecord.ToLinqToDB() // switch LINQ Provider
where s.Speed != 0
&& s.CreationUtcTime <= endTime
&& s.CreationUtcTime >= startTime
&& s.AssetId == assetId
orderby s.CreationUtcTime
select new
{
s.CreationUtcTime,
s.Speed,
diff = s.CreationUtcTime -
Sql.Ext.Lag(s.CreationUtcTime)
.Over()
.OrderBy(s => s.CreationUtcTime)
.ToValue()
};
var result = query.ToList();
If for any two records A and B such that A.SequentialId < B.SequentialId the condition A.CreationUtcTime <= B.CreationUtcTime is met, then without LAG function you can do something like this:
DateTime dateFrom = DateTime.Parse("2022-02-21");
DateTime dateTo = DateTime.Parse("2022-03-28");
string assetId = "7556d50c-95e5-4cd5-a31d-b4d6c6ab1fb1";
var records =
from rec in context.AssetStatusRecords
where
rec.CreationUtcTime >= dateFrom &&
rec.CreationUtcTime <= dateTo &&
rec.Speed != 0 &&
rec.AssetId == assetId
select rec;
var query =
from rec1 in records
from rec2 in records.Where(r => rec1.SequentialId > r.SequentialId).DefaultIfEmpty()
group new { rec1, rec2 } by new { rec1.SequentialId, rec1.CreationUtcTime, rec1.Speed } into g
orderby g.Key.SequentialId
select new
{
g.Key.CreationUtcTime,
g.Key.Speed,
Diff = EF.Functions.DateDiffDay(g.Max(p => p.rec2.CreationUtcTime), g.Key.CreationUtcTime)
};
var results = query.ToList();
Note: code above works with Pomelo.EntityFrameworkCore.MySql provider.

How to convert my SQL query to a LINQ statement

I am not familiar with linq complex queries, how can I write the following?
Three tables: Library,Batch,Plan
Library: BatchId ProcessingQuantity
Batch: BatchId
Plan: PlanNo Name Quantity ExecState Date
SELECT b.ProductionPlanBatchId,
a.ProductionPlanNo,
a.ProductConfigName,
sum(c.ProcessingQuantity) AS 'ProcessingQuantity',
sum(a.Quantity) AS 'Quantity',
a.ExecState,
round(CONVERT(float,sum(c.ProcessingQuantity))/CONVERT(float,sum(a.Quantity)), 2) AS 'Percent',
a.ProcessingCompletionDate
FROM ProductionPlan a,
ProductionPlan_Batch b,
ProductionLibrary c
WHERE a.ProductionPlanId = b.ProductionPlanId
AND b.ProductionPlanBatchId = c.ProductionPlanBatchId
AND a.ExecState <> 'Deleted'
GROUP BY b.ProductionPlanBatchId,
a.ProductionPlanNo,
a.ProductConfigName,
a.ProcessingCompletionDate,
a.ExecState
HAVING round(Convert(float,sum(c.ProcessingQuantity))/Convert(float,sum(a.Quantity)), 2) < 1
ORDER BY b.ProductionPlanBatchId DESC
According to your description, I suggest you could try to use below linq.
Class:
[Table("ProductionLibrary")]
public partial class ProductionLibrary
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ProductionPlanBatchId { get; set; }
public int? ProcessingQuantity { get; set; }
}
[Table("ProductionPlan")]
public partial class ProductionPlan
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ProductionPlanNo { get; set; }
[StringLength(10)]
public string ProductConfigName { get; set; }
public int? Quantity { get; set; }
[StringLength(10)]
public string ExecState { get; set; }
[StringLength(10)]
public string ProcessingCompletionDate { get; set; }
public int? ProductionPlanId { get; set; }
}
public partial class ProductionPlan_Batch
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ProductionPlanBatchId { get; set; }
public int? ProductionPlanId { get; set; }
}
Linq:
var re = from a in dbcontext.ProductionPlans
from b in dbcontext.ProductionPlan_Batch
from c in dbcontext.ProductionLibraries
where a.ProductionPlanId == b.ProductionPlanId
&& b.ProductionPlanBatchId == c.ProductionPlanBatchId
&& a.ExecState != "Deleted"
select new
{
a.ExecState,
a.ProcessingCompletionDate,
a.ProductConfigName,
a.ProductionPlanId,
a.ProductionPlanNo,
a.Quantity,
b.ProductionPlanBatchId,
bProductionPlanId = b.ProductionPlanId,
c.ProcessingQuantity,
cProductionPlanId = c.ProductionPlanBatchId
}
into p
group p by new {
p.ProductionPlanId,
p.ProductionPlanNo ,
p.ProductConfigName,
p.ProcessingCompletionDate,
p.ExecState,
p.ProductionPlanBatchId
} into grpre
where Math.Round(((decimal)grpre.Sum(x => x.ProcessingQuantity))/((decimal)grpre.Sum(x => x.Quantity)), 2) <1
orderby grpre.Key.ProductionPlanBatchId descending
select new {
grpre.Key.ProductionPlanBatchId,
grpre.Key.ProductionPlanNo,
grpre.Key.ProductConfigName,
ProcessingQuantity = grpre.Sum(x =>x.ProcessingQuantity) ,
Quantity = grpre.Sum(x => x.Quantity),
grpre.Key.ExecState,
Percent = Math.Round(((decimal)grpre.Sum(x => x.ProcessingQuantity)) / ((decimal)grpre.Sum(x => x.Quantity)), 2),
grpre.Key.ProcessingCompletionDate
};

Filter with Left Join in Entity Framework

I have User, Contact and ContactOfUser entities in an ASP.NET Core API project. I want to filter users based on input over these tables.
My entity classes are like this:
public class User
{
public int Id { get; set; }
[MaxLength(50)]
public string Name { get; set; }
[MaxLength(50)]
public string Surname { get; set; }
[MaxLength(60)]
public string Username { get; set; }
}
public class Contact
{
public int Id { get; set; }
[MaxLength(50)]
public string Value{ get; set; }
}
public class ContactOfUser
{
public int Id { get; set; }
public int UserId { get; set; }
[ForeignKey(nameof(UserId))]
public User User { get; set; }
public int ContactId { get; set; }
}
I want to get filtered users based on this FilterModel object:
public class FilterModel
{
public string Name { get; set; }
public string Surname { get; set; }
public string Username { get; set; }
public List<int> ContactId { get; set; }
}
How can I make this filtering process in Entity Framework with Linq methods considering that don't apply special filter data when that data will be accepted as null?
I did something like that method but it is not properly working:
List<User> GetFilteredUsers(FilterModel filter)
{
var query1 = dbContext.Users
.Where(u => u.Name.Contains(filter.Name ?? string.Empty) &&
u.Surname.Contains(filter.Surname ?? string.Empty) &&
u.Username.Contains(filter.Username ?? string.Empty));
var query2 = from u in query1
join cu in dbContext.ContactOfUsers on u.Id equals cu.UserId
into res
from item in res.DefaultIfEmpty()
where filter.Contacts.Contains(item.ContactId)
select new InitialUserModel
{
Id = u.Id,
Name = u.Name,
Surname = u.Surname,
Username = u.Username
};
}
You can achieve it in this way
Using GroupBy to get userId and ContactIds accordingly.
var userContactIds = _dbContext.ContactOfUser.GroupBy(p => p.UserId).Select(g => new { UserId = g.UserId, ContactIds = g.Select(p => p.ContactId).ToList() });
Get the result :
var result = _dbContext.User.Select(p => new FilterModel
{
Name = p.Name, Surname = p.Surname, Username = p.Username,
ContactId = userContactIds.Where(c => p.Id == c.UserId).ToList()
});
Updated
List<User> GetFilteredUsers(FilterModel filter)
{
return (from u in _dbContext.User
join c in _dbContext.ContactOfUser on u.Id equals c.UserId
join fContactId in filter.ContactId on c.ContactId equals fContactId
where u.Name == filter.Name && u.Surname == filter.Surname && u.Username == filter.Username
select u).ToList();
}

Convert CASE WHEN FROM SQL to NHIBERNATE

I have a SQL statement below that needs to convert it to NHibrnate QueryOver. I have searched the web but can't find a concrete solution. Anyone can help me on this?
SELECT
TABEL1.Id,
CASE WHEN EXISTS (SELECT Id FROM TABLE2 WHERE TABLE2.ID = TABLE1.ID)
THEN 'TRUE'
ELSE 'FALSE'
END AS NewFiled
FROM TABLE1
--Here is the real POCO
public class UserRole
{
[Required]
public virtual User User { get; set; }
[Required]
public virtual Role Role { get; set; }
}
public class UserTenant
{
[Required]
public virtual Tenant Tenant { get; set; }
[Required]
public virtual User User { get; set; }
}
public class Role
{
public int Id {get;set}
[StringLength(255), Required]
public virtual string RoleLabel { get; set; }
[StringLength(4000), Required]
public virtual string RoleDescription { get; set; }
}
public class User
{
public int Id {get;set}
[StringLength(255), Required]
public virtual string Firstname { get; set; }
[StringLength(255), Required]
public virtual string Lastname { get; set; }
}
public class Tenant
{
public int Id {get;set}
[StringLength(255), Required]
public virtual string Name { get; set; }
[StringLength(4000), Required]
public virtual string Description { get; set; }
}
public class AssignRoleUsersModel
{
public virtual int UserId { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstName { get; set; }
public virtual bool IsAssigned { get; set; }
}
--This is the method to get the users assigned or not for that particular role.
public RoleUsers GetRoleUsers(int Id)
{
UserRole userRolesAlias = null;
UserTenant userTenantsAlias = null;
-- This query will get the role depending the Id that have passed. Take note that I don't want to use this query that is why I am converting it to queryOver.
var role = (from r in RoleRepository.Queryable()
where r.Id == Id
select r).FirstOrDefault();
--This query will get all the users having the role result above.Take note that I don't want to use this query that is why I am converting it to queryOver.
var assignedUsers = UserRoleRepository.Queryable().Where(x => x.Role.Id == role.Id).Select(a => a.User.Id).ToArray();
--This is the condition to know if the user was assigned to the role
var projection = Projections.Conditional(Restrictions.Where(() => userRolesAlias.User.Id.IsIn(assignedUsers))
, Projections.Constant(true)
, Projections.Constant(false)
);
var users =
new List<AssignRoleUsersModel>(UnitOfWorkLocalData.CurrentUnitOfWork.Session.QueryOver(() => userTenantsAlias)
.Select(x => x.User.Id)
.Select(x => x.User.LastName)
.Select(x => x.User.FirstName)
.Select(x => x.User.UserName)
.Select(projection)
.TransformUsing(Transformers.AliasToBean<AssignRoleUsersModel>())
.List<AssignRoleUsersModel>());
}
EXTENDED based on the extended question, the way how to do CASE WHEN:
// the ID of searched role, coming as parameter id
int searchedRolId = ...
UserRole userRolesAlias = null;
// this is the SUBQUERY we need, the inner select
var subquery = QueryOver
.Of<UserRole>(() => userRolesAlias)
.Where(() => userRolesAlias.Role.Id == searchedRolId)
.Select(x => userRolesAlias.User.Id);
// here we use NHibernate built in Subqueries tools
var projection = Projections.Conditional(
Subqueries.Exists(subquery.DetachedCriteria) // this is the SUB-SELECT
, Projections.Constant(true)
, Projections.Constant(false)
);
ORIGINAL - This could look like this:
var projection = Projections.Conditional(
NHibernate.Criterion.Expression
.Sql("EXISTS (SELECT Id FROM TABLE2 WHERE TABLE2.ID = {alieas}.ID)")
, Projections.Constant(true)
, Projections.Constant(false)
);
var query = session.QueryOver<Table1>();
ResultDto result = null;
var list = query.SelectList(l => l
.Select(x => x.ID).WithAlias(() => result.ID)
.Select(projection).WithAlias(() => result.DoesExist)
)
.TransformUsing(Transformers.AliasToBean<ResultDto>())
.List<ResultDto>();
The list here contains the set of ResultDtos, with ID and decision if the subtabel TABLE2 record exists. The {alias} will be replaced by NHibernate with the alias of the outert table...
Where this is our DTO for projections:
public class ResultDto
{
public virtual int ID { get; set; }
public virtual bool DoesExist { get; set; }
}

RavenDB - How to merge related docs of same type into an index projection

Assuming the following class:
public class Thing
{
public string Id { get; set; }
public string Title{ get; set; }
public string KeyId { get; set; }
public CultureInfo Culture { get; set; }
}
and the following result class:
public class ProjectedThing
{
public string Id { get; set; }
public string Title{ get; set; }
public string KeyId { get; set; }
public CultureInfo Culture { get; set; }
public IEnumerable<Thing> Things { get; set; }
}
How can I build an index that holds the result class?
The closest I've come is with the following index definition:
public class ProjectedThings : AbstractIndexCreationTask<Thing,ProjectedThing>
{
public ProjectedThings()
{
Map = docs => from doc in docs
select new
{
Title = doc.Title,
KeyId = doc.KeyId,
Culture = doc.Culture,
Things = new[] {
new Thing{
Id = doc.Id,
Title = doc.Title,
KeyId = doc.KeyId,
Culture = doc.Culture,
TitlePluralized = doc.TitlePluralized
}
}
};
Reduce = results => from r in results
group r by r.KeyId into g
select new
{
Title = g.FirstOrDefault(x => x.Id == x.KeyId).Title,
KeyId = g.Key,
Culture = g.FirstOrDefault(x => x.Id == x.KeyId).Culture,
Things = from thing in g.SelectMany(x => x.Things).Where(x => x.Id != x.KeyId)
select new
{
Id = thing.Id,
Title = thing.Title,
KeyId = thing.Key,
Culture = thing.Culture
}
};
}
}
That's almost doing the trick, but I can't collect the Title, KeyId, and Culture in the reduction. Only the Things property is being populated.
Look at your code:
g.FirstOrDefault(x => x.Id == x.KeyId)
I don't understand this, but this is likely to be always false.
You probably want:
g.FirstOrDefault().Title,