Variable amount of OR, AND conditions on a lambda WHERE clause - c#

I have looked at similar questions but none have really been able to answer my question.
All I want to do is make a select using lambda but the trick is, there is a variable amount of OR/AND conditions for the selection. My function receives a list of AND conditions and it should select based on that.
Here is what I have right now and it supports up to 10 AND conditions passed as a string to compare, but this code is terrible.. in reality it should be able to accept an undefined/variable amount of conditions.
Not sure how to go about this..
ProductTags is a list of tags.. if the product has all of the tags then it is returned.
public static List<product> FilterProductsByTagsAll(List<string> tags)
{
List<product> products = new List<product>();
switch (tags.Count)
{
case 1:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()).ToList();
break;
case 2:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()).ToList();
break;
case 3:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()).ToList();
break;
case 4:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()).ToList();
break;
case 5:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[4]).Any()).ToList();
break;
case 6:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[4]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[5]).Any()).ToList();
break;
case 7:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[4]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[5]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[6]).Any()).ToList();
break;
case 8:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[4]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[5]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[6]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[7]).Any()).ToList();
break;
case 9:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[4]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[5]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[6]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[7]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[8]).Any()).ToList();
break;
case 10:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[4]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[5]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[6]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[7]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[8]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[9]).Any()).ToList();
break;
default:
break;
}
return products;
}
Thank you for trying to help out.

Try this query:
var allTagsProds = Database.Products.Values.Where(p => p.ProductTags != null && p.ProductTags.Select(pt => pt.Tag_name).Intersect(tags).Count() == tags.Count());
For each product, it selects the product tag names then intersects them with the tags list. This produces a list of product tag names that match the tags list.
Then it compares the count of this list with the count of the tags list and if they are the same, the product has all the tags. These are then returned.
Example using hard coded models:
public class Tag {
public string Tag_name {get; set;}
}
public class Product {
public ICollection<Tag> ProductTags {get; set;}
public string Name {get; set;}
}
public class Program
{
public static void Main()
{
List<string> tags = new List<string> {"a","b","c","d","e","f"};
var prodTags = new List<Tag>() {
new Tag() {Tag_name = "a"},
new Tag() {Tag_name = "b"},
new Tag() {Tag_name = "c"},
new Tag() {Tag_name = "d"}
};
var prodTags2 = new List<Tag>() {
new Tag() {Tag_name = "a"},
new Tag() {Tag_name = "b"},
new Tag() {Tag_name = "c"},
new Tag() {Tag_name = "d"},
new Tag() {Tag_name = "e"},
new Tag() {Tag_name = "f"}
};
var products = new List<Product>() {
new Product() { Name="Prod1", ProductTags = prodTags },
new Product() { Name="Prod2",ProductTags = prodTags2 }
};
var allTagsProds = products.Where(p => p.ProductTags != null && p.ProductTags.Select(pt => pt.Tag_name).Intersect(tags).Count() == tags.Count());
foreach(var prod in allTagsProds)
{
//Writes "Prod2"
Console.WriteLine(prod.Name);
}
}
}

Related

If result is < 0 in select new linq

I'm having the next issue, I have the next code
var creditos = from c in db.creditos
join s in db.solicitudDelCliente on c.SolicitudDelClienteID equals s.ID
join cl in db.cliente on s.ClienteID equals cl.ID
where c.Eliminado != true && cl.Eliminado != true && c.NegocioID == negocio_id
select new
{
c.ID,
cl.NumeroCliente,
c.Consecutivo,
NegocioID = negocio_id,
cl.NombreCompleto,
c.FechaAlta,
c.CapitalPrestado,
c.Vencido,
c.Quebranto,
c.Juridico,
c.Liquidado,
c.Reestructura,
c.Eliminado,
c.Estatus,
CapitalPagado = db.movimientos.Where(mm=>mm.CreditoID == c.ID && mm.Eliminado != true && mm.DepositoMovimientoID != null && mm.CategoriaMovimientosID == 2).Select(mm=>mm.Monto).DefaultIfEmpty(0).Sum(),
InteresesPagados = db.movimientos.Where(mm => mm.CreditoID == c.ID && mm.Eliminado != true && mm.DepositoMovimientoID != null && mm.CategoriaMovimientosID == 4).Select(mm => mm.Monto).DefaultIfEmpty(0).Sum(),
SaldoInsoluto = db.movimientos.Where(mm => mm.CreditoID == c.ID && mm.CategoriaMovimientosID == 1).Select(mm => mm.Monto).DefaultIfEmpty(0).Sum() -
db.movimientos.Where(mm => mm.CreditoID == c.ID && mm.Eliminado != true && mm.DepositoMovimientoID != null && mm.CategoriaMovimientosID == 2).Select(mm => mm.Monto).DefaultIfEmpty(0).Sum(),
SaldoDeudorTotal = (db.movimientos.Where(mm => mm.CreditoID == c.ID
&& mm.Eliminado != true
&& mm.DepositoMovimientoID == null
&& mm.CategoriaMovimientosID != 2)
.Select(mm => mm.Monto).DefaultIfEmpty(0).Sum()
- db.movimientos.Where(mm => mm.CreditoID == c.ID
&& mm.Eliminado != true
&& mm.DepositoMovimientoID != null
&& mm.CategoriaMovimientosID != 1)
.Select(mm => mm.Monto).DefaultIfEmpty(0).Sum()),
Migrado = c.Migracion
};
In some of the results of the query, the value of "SaldoDeudorTotal" is negative, I want to control the value, that if the value is -0 then return 0 zero.
var creditos = from c in db.creditos
join s in db.solicitudDelCliente on c.SolicitudDelClienteID equals s.ID
join cl in db.cliente on s.ClienteID equals cl.ID
where c.Eliminado != true && cl.Eliminado != true && c.NegocioID == negocio_id
let total = (db.movimientos.Where(mm => mm.CreditoID == c.ID
&& mm.Eliminado != true
&& mm.DepositoMovimientoID == null
&& mm.CategoriaMovimientosID != 2)
.Select(mm => mm.Monto).DefaultIfEmpty(0).Sum()
- db.movimientos.Where(mm => mm.CreditoID == c.ID
&& mm.Eliminado != true
&& mm.DepositoMovimientoID != null
&& mm.CategoriaMovimientosID != 1)
.Select(mm => mm.Monto).DefaultIfEmpty(0).Sum())
select new
{
c.ID,
cl.NumeroCliente,
c.Consecutivo,
NegocioID = negocio_id,
cl.NombreCompleto,
c.FechaAlta,
c.CapitalPrestado,
c.Vencido,
c.Quebranto,
c.Juridico,
c.Liquidado,
c.Reestructura,
c.Eliminado,
c.Estatus,
CapitalPagado = db.movimientos.Where(mm=>mm.CreditoID == c.ID && mm.Eliminado != true && mm.DepositoMovimientoID != null && mm.CategoriaMovimientosID == 2).Select(mm=>mm.Monto).DefaultIfEmpty(0).Sum(),
InteresesPagados = db.movimientos.Where(mm => mm.CreditoID == c.ID && mm.Eliminado != true && mm.DepositoMovimientoID != null && mm.CategoriaMovimientosID == 4).Select(mm => mm.Monto).DefaultIfEmpty(0).Sum(),
SaldoInsoluto = db.movimientos.Where(mm => mm.CreditoID == c.ID && mm.CategoriaMovimientosID == 1).Select(mm => mm.Monto).DefaultIfEmpty(0).Sum() -
db.movimientos.Where(mm => mm.CreditoID == c.ID && mm.Eliminado != true && mm.DepositoMovimientoID != null && mm.CategoriaMovimientosID == 2).Select(mm => mm.Monto).DefaultIfEmpty(0).Sum(),
SaldoDeudorTotal = total < 0 ? 0 : total,
Migrado = c.Migracion
};
you could use an extension
public static class MyExtension
{
public static int ToPositiveInt(this int value)
{
if (value < 0)
return 0;
else
return value
}
}
and call it at the end of your condition of SaldoDeudorTotal
SaldoDoeudorTotal = (db.movimientos.Where(mm => mm.CreditoID == c.ID
&& mm.Eliminado != true
&& mm.DepositoMovimientoID == null
&& mm.CategoriaMovimientosID != 2).ToPositiveInt()

Combine linq queries together

I have to linq queries which have only a small difference between them. I am trying to merge them both.
.Where(i =>
!i.Username.StartsWith("e-") &&
i.SSN != null && i.SSN != "" &&
i.DisplayName != null && i.DisplayName != "" &&
i.LastName != null && i.LastName != "" &&
i.FirstName != null && i.FirstName != "")
.ToList();
and the other one is
.Where(i =>
!i.Username.StartsWith("e-") &&
i.SSN != null && i.SSN != "" &&
i.DisplayName != null && i.DisplayName != "" &&
i.LastName != null && i.LastName != "" &&
i.FirstName != null && i.FirstName != "" &&
i.WhenChanged.HasValue && i.WhenChanged.Value > DateTime.UtcNow.Add(_whenChangedTimeSpan))
.ToList();
as you can see only the last item in where clause is different. Can they both be merge together?
If you choice of either of the Linq Queries is based on a "condition", you could do the following.
var result = list.Where(
i => !i.Username.StartsWith("e-")
&& i.SSN != null && i.SSN != ""
&& i.DisplayName != null && i.DisplayName != ""
&& i.LastName != null && i.LastName != ""
&& i.FirstName != null && i.FirstName != ""
&& (condition?
i.WhenChanged.HasValue && i.WhenChanged.Value > DateTime.UtcNow.Add(_whenChangedTimeSpan)
: true)).ToList();
Since the second query is just a subset of the first query, first execute the first query and then run the filter over that result:
var result = (...).Where(
i => !i.Username.StartsWith("e-")
&& i.SSN != null && i.SSN != ""
&& i.DisplayName != null && i.DisplayName != ""
&& i.LastName != null && i.LastName != ""
&& i.FirstName != null && i.FirstName != ""
).ToList();
var filteredResult = result.Where(i.WhenChanged.HasValue && i.WhenChanged.Value > DateTime.UtcNow.Add(_whenChangedTimeSpan)).ToList();
This will run the query only once on the database, and will do the second part in memory on your app server.
Maybe you are looking for something like this.
Create a method to do the common check
bool CommonCheck(TypeOfYourVariable i)
{
return !i.Username.StartsWith("e-") &&
i.SSN != null && i.SSN != "" &&
i.DisplayName != null && i.DisplayName != "" &&
i.LastName != null && i.LastName != "" &&
i.FirstName != null && i.FirstName != "";
}
Use it like this:
// first
.Where(i => CommonCheck(i))
.ToList();
// secpmd
.Where(i => CommonCheck(i) &&
i.WhenChanged.HasValue && i.WhenChanged.Value > DateTime.UtcNow.Add(_whenChangedTimeSpan))
.ToList();
Update, or you can do this:
var firstQueryResult = yourInput.Where(i =>
!i.Username.StartsWith("e-") &&
i.SSN != null && i.SSN != "" &&
i.DisplayName != null && i.DisplayName != "" &&
i.LastName != null && i.LastName != "" &&
i.FirstName != null && i.FirstName != "" &&
).ToList();
var secondQueryResult = firstQueryResult
.Where(i=> i.WhenChanged.HasValue && i.WhenChanged.Value > DateTime.UtcNow.Add(_whenChangedTimeSpan))
.ToList();

Include where clause on linq query when param is not null Npgsql

I have following method that registers a contact in database, but before register I check the contact exists or not:
bool RegisterContact(Contact contactInfo) {
bool entityExists =
_dbContext.Contacts.FirstOrDefault(
p => (p.FilesID.Equals(contactInfo.FilesID))
&& (p.EmailAddress ==
(string.IsNullOrEmpty(
contactInfo.EmailAddress)
? p.EmailAddress
: contactInfo.EmailAddress))
&&
(p.DisplayName ==
(string.IsNullOrEmpty(
contactInfo.DisplayName)
? p.DisplayName
: contactInfo.DisplayName)));
}
this query includes the fields that contain value (not null) in search condition (FilesID, EmailAddress, DisplayName)
this technique works fine in MSSQL, today i changed the database manager to PostgreSQL and use Npgsql.
All things work except above linq query, which raises an exception with message of : "could not determine data type of parameter $2"
I was forced to solve it in this way:
bool RegisterContact(Contact contactInfo)
{
Contact entityExists = null;
if (string.IsNullOrEmpty(contactInfo.EmailAddress) &&
(string.IsNullOrEmpty(contactInfo.DisplayName)))
entityExists =
_dbContext.Contacts.FirstOrDefault(
p => p.FilesID.Equals(contactInfo.FilesID));
if (!string.IsNullOrEmpty(contactInfo.EmailAddress) && string.IsNullOrEmpty(contactInfo.DisplayName))
entityExists =
_dbContext.Contacts.FirstOrDefault(
p =>
p.FilesID.Equals(contactInfo.FilesID) &&
p.EmailAddress == contactInfo.EmailAddress);
if (string.IsNullOrEmpty(contactInfo.EmailAddress) && !string.IsNullOrEmpty(contactInfo.DisplayName))
entityExists =
_dbContext.Contacts.FirstOrDefault(
p =>
p.FilesID.Equals(contactInfo.FilesID) &&
p.DisplayName == contactInfo.DisplayName);
if (!string.IsNullOrEmpty(contactInfo.EmailAddress) &&
!string.IsNullOrEmpty(contactInfo.DisplayName))
entityExists =
_dbContext.Contacts.FirstOrDefault(
p =>
p.FilesID.Equals(contactInfo.FilesID) &&
p.EmailAddress == contactInfo.EmailAddress &&
p.DisplayName == contactInfo.DisplayName);
}
Is this Npgsql bug or by design? any known solutions/workarounds for the problem?
I currently have the same cases. I think the problem is the lack of recognition, by NpgSQL, of string.IsNullOrEmpty.
I replaced the test with a check on empty string, always recognizing as not NULL the input parameter.
-- bad
var data = from art in _ctx.Set<Soleo.Model.DLAR>()
from iva in _ctx.Set<Soleo.Model.DLAI>().Where(k => k.DITTA == art.DITTA && k.COD == art.CIVA).DefaultIfEmpty()
from fam in _ctx.Set<Soleo.Model.DLFA>().Where(k => k.DITTA == art.DITTA && k.COD == art.FAM).DefaultIfEmpty()
from mar in _ctx.Set<Soleo.Model.DLMA>().Where(k => k.DITTA == art.DITTA && k.COD == art.MAR).DefaultIfEmpty()
from udm in _ctx.Set<Soleo.Model.DLUM>().Where(k => k.DITTA == art.DITTA && k.COD == art.UM).DefaultIfEmpty()
where art.DITTA == DLAUTH.Config.Current.DITTA && art.COD.Contains(sel_cod) && art.DES.Contains(sel_des)
&& (string.IsNullOrEmpty(sel_fam) || string.Compare(art.FAM, sel_fam, true) == 0)
&& (string.IsNullOrEmpty(sel_mar) || string.Compare(art.MAR, sel_mar, true) == 0)
&& (art.DIS >= sel_dis_da && art.DIS <= sel_dis_a)
select new
{
COD = art.COD,
DES = art.DES,
DES_UDM = udm.DES,
DES_MAR = mar.DES,
DES_FAM = fam.DES,
DES_CIVA = iva.DES,
MAG1 = art.MAG1,
MAG2 = art.MAG2,
DES_DIS = art.DIS == 1 ? "Si" : "No"
};
-- good:
var data = from art in _ctx.Set<Soleo.Model.DLAR>()
from iva in _ctx.Set<Soleo.Model.DLAI>().Where(k => k.DITTA == art.DITTA && k.COD == art.CIVA).DefaultIfEmpty()
from fam in _ctx.Set<Soleo.Model.DLFA>().Where(k => k.DITTA == art.DITTA && k.COD == art.FAM).DefaultIfEmpty()
from mar in _ctx.Set<Soleo.Model.DLMA>().Where(k => k.DITTA == art.DITTA && k.COD == art.MAR).DefaultIfEmpty()
from udm in _ctx.Set<Soleo.Model.DLUM>().Where(k => k.DITTA == art.DITTA && k.COD == art.UM).DefaultIfEmpty()
where art.DITTA == DLAUTH.Config.Current.DITTA && art.COD.Contains(sel_cod) && art.DES.Contains(sel_des)
&& (string.Compare(sel_fam, "", true) == 0 || string.Compare(art.FAM, sel_fam, true) == 0)
&& (string.Compare(sel_mar, "", true) == 0 || string.Compare(art.MAR, sel_mar, true) == 0)
&& (art.DIS >= sel_dis_da && art.DIS <= sel_dis_a)
select new
{
COD = art.COD,
DES = art.DES,
DES_UDM = udm.DES,
DES_MAR = mar.DES,
DES_FAM = fam.DES,
DES_CIVA = iva.DES,
MAG1 = art.MAG1,
MAG2 = art.MAG2,
DES_DIS = art.DIS == 1 ? "Si" : "No"
};
But I do not think this is the solution. I will report the case to NpgSQL.

Reduce the line of code for this LINQ query

I am using LINQ query in my code which need to be write multiple times with small changes in where condition. My query is
var sdata = from r in dt.AsEnumerable()
where r.Field<DateTime>("DAT_START").TimeOfDay.Hours < 20 &&
r.Field<DateTime>("DAT_START").TimeOfDay.Hours >= 4
group r by r["TXT_TARGET_CELL_ID"] into g
select new
{
CellID = g.Key,
TotalCommCount = g.Count(),
TotalDuration = g.Sum(r => r.Field<int>("LNG_DURATION")),
InSMSCount = g.Count(r => r.Field<Int16>("INT_DIRECTION") == 1 &&
r.Field<Int16>("INT_CALL_DATA_TYPE") == 5),
OutSMSCount = g.Count(r => r.Field<Int16>("INT_DIRECTION") == 2 &&
r.Field<Int16>("INT_CALL_DATA_TYPE") == 5),
InVoiceCount = g.Count(r => r.Field<Int16>("INT_DIRECTION") == 1 &&
r.Field<Int16>("INT_CALL_DATA_TYPE") == 1),
OutVoiceCount = g.Count(r => r.Field<Int16>("INT_DIRECTION") == 2 &&
r.Field<Int16>("INT_CALL_DATA_TYPE") == 1),
InVoiceDuration = g.Where(r => r.Field<Int16>("INT_DIRECTION") == 1 &&
r.Field<Int16>("INT_CALL_DATA_TYPE") == 1)
.Sum(r => r.Field<int>("lNG_DURATION")),
OutVoiceDuration = g.Where(r => r.Field<Int16>("INT_DIRECTION") == 2 &&
r.Field<Int16>("INT_CALL_DATA_TYPE") == 1)
.Sum(r => r.Field<int>("LNG_DURATION")),
Latitude = g.Any(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "") ? g.First(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "").Field<string>("TXT_LATITUDE") : "",
Longitude = g.Any(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "") ? g.First(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "").Field<string>("TXT_LONGITUDE") : "",
BTS_Address = g.Any(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "") ? g.First(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "").Field<string>("TXT_TARGET_BTS_LOCATION_ADDRESS") : "",
Azimuth = g.Any(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "") ? g.First(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "").Field<string>("TXT_AZIMUTH_DEG") : ""
} into summary
orderby summary.TotalCommCount descending
select summary;
Here i need to change where condition only every time, remaining part remain same i.e Select new part. Can i write this query once in code and make a call to it with change in where condition ?
You can break your predicate out into a separate method;
private static bool Where1(DT r)
{
return r.Field<DateTime>("DAT_START").TimeOfDay.Hours < 20 &&
r.Field<DateTime>("DAT_START").TimeOfDay.Hours >= 4
}
This will be assignable to a Func that you can use right in your expression;
Func<DT, bool> myWhere
if(whereCase1) // Decide which Where predicate to use
myWhere = Where1;
else
myWhere = Where2;
var sdata = from r in dt.AsEnumerable()
where myWhere(r) // Use the chosen Where predicate.
group r by r["TXT_TARGET_CELL_ID"]
into g
select new...
To build the Where condition in a slightly more dynamic way, you can make a function that returns the where condition instead of a bool;
private static Func<DT, bool> WhereHoursAreBetween(int min, int max)
{
return r => r.Field<DateTime>("DAT_START").TimeOfDay.Hours < max &&
r.Field<DateTime>("DAT_START").TimeOfDay.Hours >= min;
}
...which can then be used in the above example as;
myWhere = WhereHoursAreBetween(4, 20);
...which makes myWhere a condition that hours are between 4 and 20.
Just make a new function like this:
public dynamic MyLinq(IEnumerable r, Predicate<Object> whereClause)
{
return from r
where whereClause(r)
group r by r["TXT_TARGET_CELL_ID"] into g
select new
{
CellID = g.Key,
TotalCommCount = g.Count(),
TotalDuration = g.Sum(r => r.Field<int>("LNG_DURATION")),
InSMSCount = g.Count(r => r.Field<Int16>("INT_DIRECTION") == 1 &&
r.Field<Int16>("INT_CALL_DATA_TYPE") == 5),
OutSMSCount = g.Count(r => r.Field<Int16>("INT_DIRECTION") == 2 &&
r.Field<Int16>("INT_CALL_DATA_TYPE") == 5),
InVoiceCount = g.Count(r => r.Field<Int16>("INT_DIRECTION") == 1 &&
r.Field<Int16>("INT_CALL_DATA_TYPE") == 1),
OutVoiceCount = g.Count(r => r.Field<Int16>("INT_DIRECTION") == 2 &&
r.Field<Int16>("INT_CALL_DATA_TYPE") == 1),
InVoiceDuration = g.Where(r => r.Field<Int16>("INT_DIRECTION") == 1 &&
r.Field<Int16>("INT_CALL_DATA_TYPE") == 1)
.Sum(r => r.Field<int>("lNG_DURATION")),
OutVoiceDuration = g.Where(r => r.Field<Int16>("INT_DIRECTION") == 2 &&
r.Field<Int16>("INT_CALL_DATA_TYPE") == 1)
.Sum(r => r.Field<int>("LNG_DURATION")),
Latitude = g.Any(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "") ? g.First(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "").Field<string>("TXT_LATITUDE") : "",
Longitude = g.Any(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "") ? g.First(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "").Field<string>("TXT_LONGITUDE") : "",
BTS_Address = g.Any(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "") ? g.First(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "").Field<string>("TXT_TARGET_BTS_LOCATION_ADDRESS") : "",
Azimuth = g.Any(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "") ? g.First(s => s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS") != null && s.Field<string>
("TXT_TARGET_BTS_LOCATION_ADDRESS").Trim() != "").Field<string>("TXT_AZIMUTH_DEG") : ""
} into summary
orderby summary.TotalCommCount descending
select summary;
}
Furthermore you should really be using constants for things like "TXT_TARGET_BTS_LOCATION_ADDRESS" because it saves you from a simple mistake such as writing: "TXT_TARGET_BTS_LOCAITON_ADDRESS" and having it be compile time safe.
Edit: You would call this function with something like this:
var sdata = MyLinq(dt.AsEnumerable(), r => r.Field<DateTime>("DAT_START").TimeOfDay.Hours < 20 && r.Field<DateTime>("DAT_START").TimeOfDay.Hours >= 4)
you will probably need to change Object in Predicate<Object> to your actual type so that you can access the .Field values.
Create a function which receives a Predicate. Something like:
dynamic MyLinq(Predicate<Object> Check)
{
return from r in dt.AsEnumerable()
where Check(r)
select r;
}
Yes, you can refactor the expression by extracting the where part to a separate expression and then using it inside the bigger expression.

Handling null result

I have a db request that could return null:
Pony MyPony = db.Pony.Where(p => p.PonyOwnerId == user.UserId).First();
If there is no row in my db, there is an error message.
How to accept an empty query?
You can use FirstOrDefault
Pony myPony = db.Pony.Where(p => p.PonyOwnerId == user.UserId).FirstOrDefault();
if (myPony == null)
{
..
}
You can write:
Pony myPony = db.Pony.Where(p => p.PonyOwnerId == user.UserId).FirstOrDefault();
if( myPony != null ) {
// Do something
}
var MyPony = db.Pony.FirstOrDefault(p => p.PonyOwnerId != null && p.PonyOwnerId == user.UserId);
or
var MyPony = db.Pony.Where(p => p.PonyOwnerId != null && p.PonyOwnerId == user.UserId).FirstOrDefault();
or
if (db.Pony.FirstOrDefault(p => p.PonyOwnerId != null && p.PonyOwnerId == user.UserId) != null)
{
//Do stuff
}

Categories

Resources