Append string to linq-to-sql query - c#

I have a form with some indexes based on a document type.
I want to build my linq-to-sql query based on those index. The user might fill just some indexes or all of then.
I would need somenthing like that
Gedi.Models.OperacoesModel.indexMatrix[] IndexMatrixArr = (from a in context.sistema_Documentos
join b in context.sistema_Indexacao on a.id equals b.idDocumento
join c in context.sistema_Indexes on a.idDocType equals c.id
join d in context.sistema_DocType_Index on c.id equals d.docTypeId
where d.docTypeId == idTipo and "BUILT STRING"
orderby b.idIndice ascending
select new Gedi.Models.OperacoesModel.indexMatrix {
idDocumento = a.id,
idIndice = b.idIndice,
valor = b.valor
}).Distinct().ToArray();
This built string should be buit early in the code something like
field1 == a and field2 == b
Is this possible?

Your goal is to create expression dynamicaly, as far as I can see. And there are no way just to put string in linq query and make it work in simple linq world - that's the bad news. But I also have a good news for you - there are some way exist to create your query dynamicaly:expression tree, dynamic LINQ.

Related

Concatenating a LINQ (To SQL) Query

I am building a LINQ query, which will have comparisons attached to the 'where' section (the number of these comparisons depends on the user's selections).
In the code-behind, I want something like this:
var builtQuery =
from q in dc.Leads
join sr in dc.SalesReps on q.SalesRepID equals sr.SalesRepID
join co in dc.Companies on q.CompanyID equals co.CompanyID
join or in dc.Origins on q.OriginID equals or.OriginID
join pr in dc.Products on q.ProductID equals pr.ProductID
where
Here, in between the 'from' and 'select' parts, I will add a number of comparisons (depending on the user's selection of checkboxes).
And Finally:
select new { q.Ref, sr.Rep, q.Deposit, q.Sale, q.Title, q.Names, q.Surname, q.HomePhone, q.WorkPhone, q.Mobile, q.Address, q.Suburb, q.County, q.Postcode, co.CompanyName, or.OriginName, pr.ProductName, q.Telemarket, q.Entered };
In PHP (using MySQL) I could simply concatenate a number of strings, which make up the query. But, in c#/LINQ To SQL, the query is not a string and so I have no idea how to do this...There were a couple similar questions on SO, but they're not quite the same thing.
Any ideas??
Thanks!
I would do it in the following way
var intermediateQuery=
from q in dc.Leads
join sr in dc.SalesReps on q.SalesRepID equals sr.SalesRepID
join co in dc.Companies on q.CompanyID equals co.CompanyID
join or in dc.Origins on q.OriginID equals or.OriginID
join pr in dc.Products on q.ProductID equals pr.ProductID
select new { q.Ref, sr.Rep, q.Deposit, q.Sale, q.Title, q.Names, q.Surname, q.HomePhone, q.WorkPhone, q.Mobile, q.Address, q.Suburb, q.County, q.Postcode, co.CompanyName, or.OriginName, pr.ProductName, q.Telemarket, q.Entered };
and then add some filters considering user input
if(SomeUserProductFilter)
{
var result = intermediateQuery.Where(p=>p.ProductName = 'UserProductName');
}
Do not be afraid that this approach will retrieve all data and than filters it in memory. LINQ sends query to database only when you call ToList(), ToArray() or use result in foreach loop

Use Array in Linq query

My question got down voted and put on hold because it is not specific enough. Ill try to specify
Before linq I would do this query
sql="SELECT products.* FROM products INNER JOIN productaccess ON products.id=productaccess.productid"
Now with the entity framework and link I can do this
var products = (from lProducts in db.Products
join lProductAccess in db.ProductAccess on lProducts.ID equals lProductAccess.ProductID
select lProducts).ToList();
But what if I want the flexibilty to get all products or only get the accessible objects
In sql I can do this
sql="SELECT products.* FROM products "
if (useProductAccess) {
sql+=" INNER JOIN productaccess ON products.id=productaccess.productid"
}
In Linq I have to make a separate linq statement.
if (useProductAccess) {
var productsFiltered = (from lProducts in db.Products
join lProductAccess in db.ProductAccess on lProducts.ID equals lProductAccess.ProductID
select lProducts).ToList();
} else {
var productsAll = (from lProducts in db.Products select lProducts).ToList();
}
Now, I could just get all the lProducts and then filter it in an additional linq statement with lProductAccess but then I am using an unnecessary large amount of data.
Is it an option to use:
var productsAccecible = (from lProductAccess in db.ProductAccess where lProductAccess.CustID==custID select lProductAccess).toArray();
var products = (from lProducts in db.Products
where (useProductAccess ?
productsAccessible.Contains(lProducts.ID)
: true)
select lProducts).ToList();
Linq provider will not know how to transform the ternary operator (? and :) in a valid sql, you could try this:
var query = db.Products;
if (useProductAccess)
query = query.Where(p => productsAccessible.Contains(p.ID));
var result = query.ToList();
I used the express profiler to see how the linq statement is translated into sql. It shows that the
productsAccessible.Contains(lProducts.ID)
part gets translated as
products.id in (comma seperated list of values)
My conclusion is it will work fine.
Are there possible drawbacks
Sure - it may produce an inefficient query, or it may not even work.
One thing to note is that your conditional operator won't compile; you can't return a bool and an int from the ternary operator.
Maybe you mean:
var products = (from lProducts in db.Products
where (useProductAccess ?
productsAccessible.Contains(lProducts.ID)
: true)
select lProducts).ToList();
or build your query up using method syntax and only add the where clause if necessary.

C# linq query data table take method

I'm not able to call take method from below linq query
var data = from tb in table.AsEnumerable()
join ch in channelTable.AsEnumerable() on syskey equals (DateTime)ch["syskey"]
orderby Convert.ToDouble(tb[(string.Format("Channel{0}_data",Convert.ToInt32(ch["Channel_No"])))]) descending
select new
{
Channel_No = ch["Channel_No"],
Channel_data = tb[string.Format("Channel{0}_data", Convert.ToInt32(ch["Channel_No"]))],
};
How can I add Take(5) from above linq query?
As simply as:
var top5 = data.Take(5);
You can do it in the same statement, too, but it's a bit ugly:
var data = (from tb in table.AsEnumerable()
join ch in channelTable.AsEnumerable() on syskey equals (DateTime)ch["syskey"]
orderby Convert.ToDouble(tb[(string.Format("Channel{0}_data",Convert.ToInt32(ch["Channel_No"])))]) descending
select new
{
Channel_No = ch["Channel_No"],
Channel_data = tb[string.Format("Channel{0}_data", Convert.ToInt32(ch["Channel_No"]))],
}).Take(5);
Note that ordering by a string here probably doesn't do what you want, unless your values are all single digit - would you really want channel3, channel2, channel10, channel1?
It's a pretty odd query though - especially as your join doesn't use anything from the first table...

Ruby Sequel Equivalent to LINQ to SQL select anonymous objects

I've got some C# code with a LINQ query I'm trying to translate to Ruby and am using Sequel as my DB ORM. The linq query just performs some joins and then returns an anonymous object containing references to the joined entities. I've got the code translated and operating correctly but it just returns all of the columns from each table and I'd like to wrap each set of columns up in its own object similarly to how it is done in the C# code.
LINQ Query
from s in slots
join tu in _dbContext.table_usages on s.id equals tu.slot_id
join r in _dbContext.Reservations on tu.reservation_id equals r.ReservationID
join o in _dbContext.orders on r.OrderID equals o.OrderID
join c in _dbContext.Contacts on r.ContactID equals c.ContactID
where tu.reservation_id != null &&
r.state != ReservationStates.Cancelled
select new { SlotId = s.id, Reservation = r, Order = o, Contact = c, TableUsage = tu };
Ruby Code:
select(:slots__id, :reservations.*, :orders.*, :restaurant_customers.*, :table_usages.*)
.filter(slots__restaurant_id: restaurant_id, slots__removed: false)
.filter(slots__slot_time: start_time..end_time)
.join(:table_usages, slot_id: :id)
.join(:reservations, id: :table_usages__reservation_id)
.join(:orders, id: :reservations__order_id)
.join(:restaurant_customers, id: :reservations__contact_id)
.filter('table_usages.reservation_id is not null')
.filter('reservations.state != ?', ReservationStates.cancelled)
I'm unable to find a way of accomplishing this via the docs but I thought I would see if anyone has done something similar in a way that I haven't thought of yet.
Thanks!
I'm assuming you are just referring to the last two lines:
.filter('table_usages.reservation_id is not null')
.filter('reservations.state != ?', ReservationStates.cancelled)
Which you could handle via:
.exclude(:table_usages__reservation_id=>nil)
.exclude(:reservations__states=>ReservationStates.cancelled)
exclude operates as an inverse filter.

There has to be a better way to add this clause in linq

var result = from R in db.Clients.Where(clientWhere)
join RA in db.ClientAgencies on R.SysID equals RA.SysID
join A in db.Agencies.Where(agencyWhere) on RA.AgencyID equals A.AgencyID
join AC in db.AdCommittees on A.AgencyID equals AC.AgencyID into temp
from x in temp.DefaultIfEmpty().Distinct()
select new {R,RA,x};
If user enters CommitteeID this is what I do, but I feel there has to be a better way.
var query = (from R in result
where R.x.CommitteeID == params.CommitteeID
select R.R).Distinct();
return query;
Is there a better way?
How are you using the data. The joins could be hurting you depending on what you're trying to achieve (which is very difficult for us to view without context of your data structures).
I can't fault the linq other than to say that you appear to have a log of data being joined which you may or may not need.
The other problem I have is that you will execute the query when you call DefaultIfEmpty(). This means to do your filter you may hit the database again to calculate it's result.
Could you provide some info on your DB Schema and what you are trying to get from your query?
If you're not using your intermediate query for anything else, I would flip it (filter by committeeID first):
Client GetCommitteeClient(int committeeID)
{
return (
from AC in db.AdCommittees
where AC.CommitteeID == committeeID
join A in db.Agencies.Where(agencyWhere) on AC.AgencyID equals A.AgencyID
join RA in db.ClientAgencies on A.AgencyID equals RA.AgencyID
join R in db.Clients.Where(clientWhere) on RA.SysID equals R.SysID
select R
).SingleOrDefault();
}

Categories