How to distinct by multiple columns with input parameter in Linq - c#

i have tre tables T020_CLIENTI,T021_SITI,T520_REL_STRUMENTI_SITI that i would join and then distinct by T020.Ragione_sociale,T520.DA_DATA,T520.A_DATA but obtain as return parameters T020.Ragione_sociale,T020.id_cliente,T520.cod_stumento,T520.DA_DATA,T520.A_DATA
my tables are
public partial class T020_CLIENTI
{
public decimal ID_CLIENTE { get; set; }
public Nullable<decimal> ID_COMUNE { get; set; }
public Nullable<decimal> ID_CONSORZIO { get; set; }
public string COD_LINEA_ATTIVITA { get; set; }
}
public partial class T021_SITI
{
public decimal ID_SITO { get; set; }
public Nullable<decimal> ID_FORNITORE { get; set; }
public Nullable<decimal> ID_CLIENTE { get; set; }
}
public partial class T520_REL_STRUMENTI_SITI
{
public string COD_STUMENTO { get; set; }
public decimal ID_SITO { get; set; }
public System.DateTime DA_DATA { get; set; }
public System.DateTime A_DATA { get; set; }
}
my linq query is
using (var cont = DALProvider.CreateEntityContext())
{
var query =
from cliente in cont.T020_CLIENTI
from sito
in cont.T021_SITI
.Where(s => s.ID_CLIENTE == cliente.ID_CLIENTE)
.DefaultIfEmpty()
from relStrumenti
in cont.T520_REL_STRUMENTI_SITI
.Where(s => s.ID_SITO == sito.ID_SITO)
.DefaultIfEmpty()
select new
{
clienteRec = cliente,
sitoRec = sito,
relStrumentiRec = relStrumenti
};
if (!string.IsNullOrEmpty(aiFiltro.RAGIONE_SOCIALE))
query = query.Where(i => i.clienteRec.RAGIONE_SOCIALE.ToUpper().Contains(aiFiltro.RAGIONE_SOCIALE.ToUpper()));
var vRes = (from clienteDef in query
select new ClienteFiltrato
{
RAGIONE_SOCIALE = clienteDef.clienteRec.RAGIONE_SOCIALE,
ID_CLIENTE = clienteDef.clienteRec.ID_CLIENTE,
COD_STRUMENTO = clienteDef.relStrumentiRec.COD_STUMENTO,
DATA_DA = clienteDef.relStrumentiRec.DA_DATA,
DATA_A = clienteDef.relStrumentiRec.A_DATA
}) ;
return vRes.AsQueryable();
}
but in my linq query i don't know where i can insert distinct and input parameter (:pPOD) to obtain my linq that in oracle query is:
SELECT DISTINCT t020.ragione_sociale,
da_data,
a_data,
t020.id_Cliente,
:pPOD
FROM t020_clienti t020, t021_siti t021, T520_REL_STRUMENTI_SITI t520
WHERE t020.id_cliente = t021.id_cliente
AND t021.id_sito = t520.id_sito
AND (:pPOD is null or t520.cod_stumento = :pPOD)
ORDER BY da_data
where :pPOD is an input parameter that i could have set or not.

Try to add (s.COD_STUMENTO == pPod || pPod == null) to your Where clause, where you are filtering T520_REL_STRUMENTI_SITI entity. pPod should be a string variable.
Please have in mind that if you are using DefaultIfEmpty() in LINQ this will be translated to left join in SQL.
Modified query follows:
string pPod = null;
using (var cont = DALProvider.CreateEntityContext())
{
var query =
(from cliente in cont.T020_CLIENTI
from sito
in cont.T021_SITI
.Where(s => s.ID_CLIENTE == cliente.ID_CLIENTE)
.DefaultIfEmpty()
from relStrumenti
in cont.T520_REL_STRUMENTI_SITI
.Where(s => s.ID_SITO == sito.ID_SITO && (s.COD_STUMENTO == pPod || pPod == null))
.DefaultIfEmpty()
select new
{
clienteRec = cliente.Distinct(),
sitoRec = sito,
relStrumentiRec = relStrumenti
});
if (!string.IsNullOrEmpty(aiFiltro.RAGIONE_SOCIALE))
query = query.Where(i => i.clienteRec.RAGIONE_SOCIALE.ToUpper().Contains(aiFiltro.RAGIONE_SOCIALE.ToUpper()));
var vRes = (from clienteDef in query
select new ClienteFiltrato
{
RAGIONE_SOCIALE = clienteDef.clienteRec.RAGIONE_SOCIALE,
ID_CLIENTE = clienteDef.clienteRec.ID_CLIENTE,
COD_STRUMENTO = clienteDef.relStrumentiRec.COD_STUMENTO,
DATA_DA = clienteDef.relStrumentiRec.DA_DATA,
DATA_A = clienteDef.relStrumentiRec.A_DATA
}).Distinct() ;
return vRes.AsQueryable();
}
You can use:
string query =
((System.Data.Objects.ObjectQuery)query).ToTraceString();
This will show you the generated SQL from LINQ Queryable object.

Related

Linq group result to list of object

I'm trying group a collection of data by it's State but I'm stuck on the correct way to do this:
FileStateInfoDto
public class FileStateInfoDto : EntityDto<int>
{
public string StateName { get; set; }
public int StateNumber { get; set; }
public int FilesByStateCount { get; set; }
}
FileGroupDto
public class FileGroupDto : EntityDto<int>
{
public int CaseId { get; set; }
public string Name { get; set; }
public string ResourceKey { get; set; }
public bool IsFolder { get; set; }
public int SequenceNumber { get; set; }
public IList<FileStateInfoDto> FileStateInfo { get; set; }
public IList<FileGroupDto> FileGroups { get; set; }
public IList<FileInfoDto> Files { get; set; }
}
Here is the code I have:
return await Context.FileGroups
.Include(g => g.Case).Include(g => g.FileGroups).Include(g => g.Files)
.Where(g => g.Id == fileGroupId &&
g.CaseId == caseId &&
g.Case.CaseState != CaseState.Approved &&
g.Case.CaseState != CaseState.Submitted &&
(g.Case.CaseState != CaseState.Draft || g.Case.CreatorUserId == userId))
.OrderBy(g => g.SequenceNumber)
.Select(g => new FileGroup
{
Id = g.Id,
CaseId = g.CaseId,
Name = g.Name,
ResourceKey = g.ResourceKey,
IsFolder = g.IsFolder,
SequenceNumber = g.SequenceNumber,
FileGroups = g.FileGroups,
FileStateInfo = g.Files.GroupBy(f => f.State), <-- My problem
Files = g.Files.Where(f => f.IsActive && f.State != FileApprovalState.Approved).Select(
f => new File
{
Id = f.Id,
CreationTime = f.CreationTime,
CreatorUserId = f.CreatorUserId,
Title = f.Title,
FileName = f.FileName,
URL = f.URL,
Size = f.Size,
KeepOnPortal = f.KeepOnPortal,
CreatorUserName = Context.Users.FirstOrDefault(u => u.Id == (f.CreatorUserId ?? 0)).UserName,
CreatorUserRole = Context.CasePersons.Where(p => p.CaseId == caseId && p.UserId == f.CreatorUserId).Take(1).Select(p => p.CaseRoleType.Title).FirstOrDefault()
}
).ToList()
}).FirstOrDefaultAsync();
I'm trying to figure out how I should write this line FileStateInfo = g.Files.GroupBy(f => f.State) so it will give the expected result as below.
FileStateInfo = [{"StateName":"Approved","StateNumber":1, "FilesByStateCount":22},
{"StateName":"NotApproved","StateNumber":2, "FilesByStateCount":11}]
The State in g.Files.GroupBy(f => f.State) is an enum that contains Approved and NotApproved
StateName = Name of the State.
StateNumber = The Integer assinged.
FilesByStateCount = The files count by this state.
I hope it's possible because I've been trying to make this for a few days now.
I've tried things like this Post

Add values to a list inside a list Linq

I am having a class like this.
public class CameraModel
{
public int JobId { get; set; }
public int ViewId { get; set; }
public Guid ViewGuid { get; set; }
public string Name { get; set; }
public int ViewNum { get; set; }
public int LayoutID { get; set; }
public List<CameraViewItemModel> CameraViewItems { get; set; }
}
The CameraViewItemModel class is like this:
public class CameraViewItemModel
{
public int JobID { get; set; }
public Guid ViewGuid { get; set; }
public int ViewID { get; set; }
public int CamNum { get; set; }
public Guid ChannelGuid { get; set; }
public string Name { get; set; }
public ActionType Action { get; set; }
}
Now, I am assigning the list of CameraViewItemModel like this:
// get all the cameramodel's
cameraModels = _unitOfWork.Context.CameraViews.Where(m => m.JobId == siteId)
.Select(m => new CameraModel
{
JobId = m.JobId,
ViewId = m.ViewId,
ViewGuid = m.ViewGuid,
Name = m.Name,
ViewNum = m.ViewNum,
LayoutID = m.LayoutId
}).ToList();
// get all the cameraviewitemmodels
cameraViewItemModels =
(from cameraView in _unitOfWork.Repository<CameraViews>().Get(x => x.JobId == siteId).Result
join cameraViewItem in _unitOfWork.Repository<CameraViewItems>().Get(x => x.JobId == siteId)
.Result on cameraView.ViewId equals cameraViewItem.ViewId into CameraViewItemResults
from cameraViewItemResult in CameraViewItemResults.DefaultIfEmpty()
join cameraChannel in _unitOfWork.Repository<CameraChannels>().Get(x => x.JobId == siteId)
.Result on (cameraViewItemResult == null ? new Guid() : cameraViewItemResult.ChannelGuid) equals cameraChannel.ChannelGuid into CameraChannelResults
from cameraChannelResult in CameraChannelResults.DefaultIfEmpty()
select new CameraViewItemModel
{
JobID = cameraView.JobId,
ViewID = cameraView.ViewId,
ViewGuid = cameraView.ViewGuid,
CamNum = cameraViewItemResult.CamNum,
ChannelGuid = cameraChannelResult.ChannelGuid,
Name = cameraChannelResult.Name
}).ToList();
// then do a 'join' on JobId, ViewId and ViewGuid and assign the list of cameraviewitemmodels to cameraModels.
foreach (var cameraModel in cameraModels)
{
cameraModel.CameraViewItems = (from cameraViewItem in cameraViewItemModels
where cameraModel.JobId == cameraViewItem.JobID
&& cameraModel.ViewId == cameraViewItem.ViewID
&& cameraModel.ViewGuid == cameraViewItem.ViewGuid
select cameraViewItem).ToList();
}
return cameraModels;
There are three tables in database:
CameraViews, CameraViewItems, CameraChannels.
CameraViews is the main table. It is left joined with CameraViewItems and CameraChannels to get the desired result. There may not be any data in CameraViewItems and CameraChannels for a corresponding CameraView.
Is it possible to assign the list of CameraViewItemModels to CameraModels in a single linq statement.
Here is a simple way to add values to a sub list, dunno if this is what you mean. You can keep selecting sub lists if that is necessary.
var parent_lst = new List<List<string>>(); // Root/parent list that contains the other lists
var sub_lst = new List<string>(); // Sub list with values
var selected_parent_lst = parent_lst[0]; // Here I select sub list, in this case by list index
selected_parent_lst.Add("My new value"); // And here I add the new value

Orderby on left join null value

Following situation:
Table of users
Table of addresses
The user has a single optional reference to the address table (=left join)
The query to fetch the data is:
IQueryable<User> query =
from u in _dbContext.Users
join a in _dbContext.Address on u.AddressId equals a.Id into address
from addresses in address.DefaultIfEmpty()
select new User(u, a);
Now I want to do a sorting on the query based on the municipality of the address
query = query.OrderBy(u => u.Address.Municipality);
The problem is that the Address can be a null value (as the address is optional) and for that reason it is throwing following exception.
NullReferenceException: Object reference not set to an instance of an object.
Is there a way to order on the municipality knowing that it can be null?
Already tried following things with same outcome:
query = query.OrderBy(u => u.Address.Municipality ?? "");
query = query.OrderBy(u => u.Address == null).ThenBy(u => u.Address.Municipality);
You can use
query = query.OrderBy(u => u.Address.Municipality.HasValue);
You can write your comparer like this:
public class One
{
public int A { get; set; }
}
public class Two
{
public string S { get; set; }
}
public class T
{
public One One { get; set; }
public Two Two { get; set; }
}
public class OrderComparer : IComparer<Two>
{
public int Compare(Two x, Two y)
{
if (((x == null) || (x.S == null)) && ((y == null) || (y.S == null)))
return 0;
if ((x == null) || (x.S == null))
return -1;
if ((y == null) || (y.S == null))
return 1;
return x.S.CompareTo(y.S);
}
}
static void Main(string[] args)
{
var collection = new List<T> {
new T{ One = new One{A=1}, Two = new Two{ S="dd" } },
new T{ One = new One{A=5}, Two = null },
new T{ One = new One{A=0}, Two = new Two{ S=null } },
new T{ One = new One{A=6}, Two = new Two{ S="aa" } },
};
var comparer = new OrderComparer();
collection = collection.OrderBy(e => e.Two, comparer).ToList();
}
But in your case you have to write var collection = query.AsEnumerable().OrderBy(x=>x.Address).
Also there is other method:
var result = query.Where(x=>x.Address==null || x.Address.Municipality==null)
.Union(query.Where(x.Address!=null && x.Address.Municipality!=null).OrderBy(x=>x.Address.Municipality));
I create a simple demo and it works well when I add nullable foreign key to the two tables.
Besides, I do not understabd what is select new User(u, a); in your code.
Below is my sample code:
Models:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("Address")]
public int? AddressId { get; set; }
public Address Address { get; set; }
}
public class Address
{
public int Id { get; set; }
public string AddressName { get; set; }
public string Municipality { get; set; }
}
Action:
IQueryable<User> query =
from u in _context.Users
join a in _context.Address on u.AddressId equals a.Id into address
from addresses in address.DefaultIfEmpty()
select new User
{
Id = u.Id,
Name = u.Name,
AddressId = u.AddressId,
Address = addresses
};
query = query.OrderBy(u => u.Address.Municipality);

Using LINQ for JOINs and Sum

I just started working with LINQ. How can I use SUM and LEFT JOIN using LINQ. I am trying to build the query below in LINQ. Is it possible?
SELECT t.TenantID, t.TenantFName, t.TenantLName, t.RentalAmount, t.PetRent, t.HousingAmount, t.UtilityCharge, t.TVCharge, t.SecurityDeposit, t.HOAFee,
t.ParkingCharge, t.StorageCharge, t.ConcessionAmount, t.ConcessionReason, t.TenantEmail, t.TenantPhone, t.CellPhoneProviderID, t.MoveInDate,
p.PropertyID, p.PropertyName,
TotalDebit, HousingDebit, TotalCredit, HousingCredit
FROM Tenants t
JOIN Properties p ON t.PropertyID = p.PropertyID
LEFT JOIN (
Select
TenantID,
SUM(CASE WHEN TransactionTypeID = 1 AND ChargeTypeID != 6 AND TenantTransactionDate <= Now() THEN TransactionAmount ELSE 0 END) AS TotalDebit,
SUM(CASE WHEN TransactionTypeID = 1 AND ChargeTypeID = 6 AND TenantTransactionDate <= Now() THEN TransactionAmount ELSE 0 END) AS HousingDebit,
SUM(CASE WHEN TransactionTypeID = 2 AND ChargeTypeID != 6 AND TenantTransactionDate <= Now() THEN TransactionAmount ELSE 0 END) AS TotalCredit,
SUM(CASE WHEN TransactionTypeID = 2 AND ChargeTypeID = 6 AND TenantTransactionDate <= Now() THEN TransactionAmount ELSE 0 END) AS HousingCredit
From TenantTransactions
Group By TenantID
) sums ON sums.TenantID = t.TenantID
Where t.Prospect = 2
AND t.PropertyID = 1
Thanks
Roughing out an answer and making a few assumptions about your object model, I'd start off by calculating each of the sums individually with something akin to this statement:
var tenantsTotalDebit = tenantTransactions.Where(tt.TenantId == requestedTenantId && tt.TransactionTypeID == 1 && tt.ChargeTypeID != 6 && tt.TenantTransactionDate <= DateTime.Now).Select(tt => tt.TransactionAmount).Sum();
After you've got all the sums, you can create another query that queries the Tenants and, assuming the Tenants object has it's associated Properties as a member, you could combine them in something like this:
var tenantQuery = tenants.Where(t.Prospect == 1 && t.PropertyID ==1).Select(t.TenantID, t.TenantFName, ..., tenantsTotalDebit, tenantsHousingDebit, tenantsTotalCredit, tenantsHousingCredit);
You can include values beyond the object type that you're querying in a Select() method, so you can include the precalculated sums after determining them separately.
I used classes to model you database. See code below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication53
{
class Program
{
static void Main(string[] args)
{
List<Tenants> tenants = new List<Tenants>();
List<Properties> properties = new List<Properties>();
List<TenantTransactions> transactions = new List<TenantTransactions>();
var tenantTransactions = transactions.GroupBy(x => x.TenantID).Select(x => new
{
id = x.Key,
totalDebit = x.Where(y => (y.TransactionTypeID == 1) && (y.ChargeTypeID != 6) && (y.TenantTransactionDate <= DateTime.Now)).Sum(y => y.TransactionAmount),
housingDebit = x.Where(y => (y.TransactionTypeID == 1) && (y.ChargeTypeID == 6) && (y.TenantTransactionDate <= DateTime.Now)).Sum(y => y.TransactionAmount),
totalCredit = x.Where(y => (y.TransactionTypeID == 2) && (y.ChargeTypeID != 6) && (y.TenantTransactionDate <= DateTime.Now)).Sum(y => y.TransactionAmount),
housingCredit = x.Where(y => (y.TransactionTypeID == 2) && (y.ChargeTypeID == 6) && (y.TenantTransactionDate <= DateTime.Now)).Sum(y => y.TransactionAmount)
}).ToList();
var results2 = (from t in tenants
join p in properties on t.PropertyID equals p.PropertyID
join tt in tenantTransactions on t.TenantID equals tt.id into ps
from tt in ps.DefaultIfEmpty()
select new { t = t, p = p, tt = tt })
.Where(x => (x.t.PropertyID == 1) && (x.t.Prospect == 1))
.GroupBy(x => x.t.TenantID)
.Select(x => new {
tenantID = x.Key,
tenantFirstName = x.FirstOrDefault().t.TenantFName,
tenantLastName = x.FirstOrDefault().t.TenantLName,
tenantEmail = x.FirstOrDefault().t.TenantEmail,
tenantPhone = x.FirstOrDefault().t.TenantPhone,
tenantCellPhoneProvider = x.FirstOrDefault().t.CellPhoneProviderID,
properties = x.Select(y => new {
propertyID = y.p.PropertyID,
propertyName = y.p.PropertyName,
rentalAmount = y.t.RentalAmount,
petRent = y.t.PetRent,
houseingAmount = y.t.HousingAmount,
utilityCharge = y.t.UtilityCharge,
tvCharge = y.t.TVCharge,
sercurityDeposit = y.t.SecurityDeposit,
hoaFee = y.t.HousingAmount,
parkingCharge = y.t.ParkingCharge,
storageCharge = y.t.StorageCharge,
concessionAmount = y.t.ConcessionAmount,
concessionReason = y.t.ConcessionReason,
tenantMoveInDate = y.t.MoveInDate
}).ToList(),
totalDebit = x.FirstOrDefault().tt.totalDebit,
housingDebit = x.FirstOrDefault().tt.housingDebit,
totalCredit = x.FirstOrDefault().tt.totalCredit,
housingCredit = x.FirstOrDefault().tt.housingCredit,
}).ToList();
}
}
public class TenantTransactions
{
public int TenantID { get; set; }
public int TransactionTypeID{ get;set;}
public int ChargeTypeID { get;set;}
public DateTime TenantTransactionDate { get;set;}
public decimal TransactionAmount { get;set;}
}
public class Tenants
{
public int PropertyID { get; set; }
public int Prospect { get; set; }
public int TenantID { get; set; }
public string TenantFName { get; set; }
public string TenantLName { get; set; }
public decimal RentalAmount { get; set; }
public decimal PetRent { get; set; }
public decimal HousingAmount { get; set; }
public decimal UtilityCharge { get; set; }
public decimal TVCharge { get; set; }
public decimal SecurityDeposit { get; set; }
public decimal HOAFee { get; set; }
public decimal ParkingCharge { get; set; }
public decimal StorageCharge { get; set; }
public decimal ConcessionAmount { get; set; }
public string ConcessionReason { get; set; }
public string TenantEmail { get; set; }
public string TenantPhone { get; set; }
public string CellPhoneProviderID { get; set; }
public DateTime MoveInDate { get; set; }
}
public class Properties
{
public int PropertyID { get; set; }
public string PropertyName { get; set; }
}
}

How to write Lambda expression for this SQL query?

I have the following SQL query
Select cLedgerName,dDateFrom,cPeriodType,nPeriodFrom,nPeriodTo
from sys_Account_Ledger a,sys_Log_Deposits_Interest_Master b
where a.cGLCode=b.cGLCode and b.dDateFrom='08-11-2012' and b.cPeriodType='Days'
I wanted to write this query using Lambda expression.This is where I am stuck.
public IList<ListViewData> GetDepositsListViewData(string glCode, string effectDate, string periodType)
{
using (var db = new DataClasses1DataContext())
{
var data=db.sys_Account_Ledgers.Join(db.sys_Log_Deposits_Interest_Masters,
ledger=>ledger.cGLCode,
deposits=>deposits.cGLCode,
(ledger,deposits)=>new {db.sys_Account_Ledgers =ledger,db.sys_Log_Deposits_Interest_Masters =deposits})
}
}
I have created a class which will be the return type of my query.
Here is the class
public class ListViewData
{
public string LedgerName { get; set; }
public string DateFrom { get; set; }
public string PeriodType { get; set; }
public int PeriodFrom { get; set; }
public int PeriodTo { get; set; }
}
Can anyone help me out with the lambda expression?
var result = dataContext.SysAccountLedger
.Join(dataContext.SysLogDepositsInterestMaster,
a => a.cGlCode,
b => b.cGlCode,
(a, b) => new ListViewData
{
LedgerName = a.LedgerName,
DateFrom = b.DateFrom,
PeriodType = b.PeriodType
// other properties
})
.Where(item => item.DateFrom = Convert.ToDateTime("08-11-2012") &&
item.PeriodType == "Days")
.ToList();
//Direct translation into Linq:
var query = from a in db.sys_Account_Ledger
join b in db.sys_Log_Deposits_Interest_Master on a.cGLCode equals b.cGLCode
where b.dDateFrom == Convert.ToDateTime("08-11-2012") && b.cPeriodType == "Days"
select new { a, b };
//Lambda of this:
var query = db.sys_AccountLedger
.Join(db.sys_Log_Deposits_Interest_Master,
a => a.cGLCode,
b => b.cGLCode,
(a, b) => new {a , b})
.Where(w => w.dDateFrom == Convert.ToDateTime("08-11-2012") && w.cPeriodType == "Days");

Categories