LINQ - Join only one attribute with whole schema onf another entity - linq

I have two entities smtracks and tracks_registration I write the following linq
var track = from tracksData in sqlEntities.smtracks
join track_registrationData in sqlEntities.tracks_registration on tracksData.TracksID equals track_registrationData.FkTrackId
where tracksData.TracksID == 35 && track_registrationData.TuneCode == 5982234E
select new
{
Tunecode = track_registrationData.TuneCode
};
now i just need this one attribute Tunecode from the other table and rest i want to have the whole schema of smtracks selected. The only way i know is that I select all the attributes in the LINQ above like
select new
{
Tunecode = track_registrationData.TuneCode
TracksID = smtracks.TracksID
SongTitle = smtracks.SongTitle
.
.
.
.
.
};
and there are a lot of attributes, isn't there a simpler way to select the entire schema of one table and the just one attribute from other.

If you don't mind have extra parameter to hold the smtracks, then you can write like this :-
select new
{
smtracks=tracksData ,
Tunecode = track_registrationData.TuneCode
};
Later on you can get the value like smtracks.TracksID and so on.

Related

Dynamic Linq core

Hi I am using a Jqwidgets Grid to display my data. It has a build in possibility to use filters but if you filter your records on the server side you have to build your own query. As I am working with Linq I thought to use the Dynamic Linq Library for Asp net core. Problem is there are not many examples or explanations how to do this. But I am busy for days now and not getting very far.The way I am setup; I have a normal Linq query:
var Mut = from M in _DB.Mutations
join S in _DB.Shifts on M.ShiftId equals S.ShiftId
join U in _DB.RoosterUsers on M.UserId equals U.RoosterUserId
join D in deps on M.UserId equals D.UserId
join DD in _DB.Departements on D.DepartementID equals DD.DepartementId
select new MutationModel
{
MutId=M.MutationId,
Naam=U.FirstName + " " + U.LastName,
UserId=M.UserId,
Departement= DD.DepartementName,
MutationType = S.publicName,
MutationGroup = S.ShiftType.ToString(),
DateTot =M.DateTill,
TijdVan=M.DateStartOn,
TijdTot=M.DateTill,
Status=CreateStatus(M.Tentative, M.ApprovedOn, M.Processed, M.CancelRefId, M.Deleted)
};
This query is running OK and gives me all the data I need for the Grid.
Then for the filter I would like to add a dynamic Linq Query using the System.Linq.Dynamic.Core library
But this is as far as I get things working until now:
var outQuery = Mut.Where("Status = #0 and UserId = #1", "Nieuw", "KLM22940").Select("Status");
My questions now :
1. In the where clause If I make the fieldname variable I get an error. how to do this??
2. In the Select Clause, how to add multiple Columns? (actually I just like to output all columns.)
Best would be to see an example. has somebody used Dynamic Linq to build a dynamic linq query for the JQWidgets Grid?
Thank you very much.
In what way you are trying to use fieldname variable in where clause ?
If you want to output all columns you can use ToList()
like
var outQuery = Mut.Where("Status = #0 and UserId = #1", "Nieuw", "KLM22940").ToList();
If you want to get some specific columns you can use Select clause like this
var outQuery = Mut.Where("Status = #0 and UserId = #1", "Nieuw", "KLM22940").Select("new(Status,UserId )");
This Select clause creates data class which contains Status and UserId properties and returns a sequence of instances of that data class.

NHibernate querying with WHERE conditions in pairs

I have a collection of NHibernate objects ConcurrentBag<Event> with properties project_id and name. I want to a set of unrelated (schema wise) objects from another table which also match these properties.
The SQL I would expect would look something like:
SELECT * FROM table WHERE (project_id = 1 AND name = 'foo')
OR (project_id = 2 AND name = 'foo')
OR (project_id = 1 AND name = 'bar')
... etc
The pairs of values in the WHERE clause are based on the values from each Event in the ConcurrentBag<Event>.
I am not sure how to query this with NHibernate (ideally with LINQ). Is this even possible?
This would be difficult with LINQ I think, but if you use QueryOver it's easy to build a WHERE clause dynamically using Restrictions.Disjunction:
var disjunction = Restrictions.Disjunction();
foreach (Event evt in events)
{
disjunction.Add(Restrictions.Where<Table>(
t => t.project_id == evt.project_id && t.name == evt.name);
}
var rows = session.QueryOver<Table>()
.Where(disjunction)
.List<Table>();

Combining LINQ Queries to reduce database calls

I have 2 queries that work, I was hoping to combine them to reduce the database calls.
var locations = from l in db.Locations
where l.LocationID.Equals(TagID)
select l;
I do the above because I need l.Name, but is there a way to take the above results and put them into the query below?
articles = from a in db.Articles
where
(
from l in a.Locations
where l.LocationID.Equals(TagID)
select l
).Any()
select a;
Will I actually be reducing any database calls here?
This seems a bit complicated because Locations appears to be a multi-value property of Articles and you want to only load the correct one. According to this answer to a similar question you need to use a select to return them separately in one go so e.g.
var articles = from a in db.Articles
select new {
Article = a,
Location = a.Locations.Where(l => l.LocationId == TagId)
};
First failed attempt using join:
var articlesAndLocations = from a in db.Articles
join l in a.Locations
on l.LocationID equals TagID
select new { Article = a, Location = l };
(I usually use the other LINQ syntax though so apologies if I've done something stupid there.)
Could you not use the Include() method here to pull in the locations which are associated with each article, then select both the article and location object? or the properties you need from each.
The include method will ensure that you don't need to dip into the db twice, but will allow you to access properties on related entities.
You would need to use a contains method on an IEnumerable I believe, something like this:
var tagIdList = new List() { TagID };
var articles = from a in db.Articles.Include("Locations")
where tagIdList.Contains(from l in a.Locations select l.LocationID)
select new { a, a.Locations.Name };
(Untested)

Binding LINQ query to DataGridView

This is very confusing, I use AsDataView to bind query result to a dgv and it works fine with the following:
var query = from c in myDatabaseDataSet.Diamond where c.p_Id == p_Id select c;
dataGridView1.DataSource = query.AsDataView();
However, this one results in an Error:
var query = from item in myDatabaseDataSet.Items
where item.p_Id == p_Id
join diamond in myDatabaseDataSet.Diamond
on item.p_Id equals diamond.p_Id
join category in myDatabaseDataSet.DiamondCategory
on diamond.dc_Id equals category.dc_Id
select new
{
Product = item.p_Name,
Weight = diamond.d_Weight,
Category = category.dc_Name
};
dataGridView1.DataSource = query.AsDataView();
Error:
Instance argument: cannot convert from
'System.Collections.Generic.IEnumerable<AnonymousType#1>' to
'System.Data.DataTable'
AsDataView doesn't show up in query.(List). Why is this happen? How to bind the query above to the dgv then?.
The signature of the AsDataView is as follows:
public static DataView AsDataView(
this DataTable table
)
The only parameter is the DataTable.
The query you have is returning an IEnumerable of an anonymous type which doesn't have an implicit conversion to a DataTable (or a sequence of DataRow instances, in which case you could use that to help you create a DataTable).
You need to get the results back into a DataTable or something you can convert into a DataTable and then it will work.
In your particular case, it seems that you were (or are) using typed DataSets. If that is the case, then you should be able to take the values that were selected and then create new typed DataRow instances (there should be factory methods for you) which can then be put into a typed DataTable, which AsDataView can be called on.
just simply convert the result to a list and bind it to your grid.
var query = from item in myDatabaseDataSet.Items
where item.p_Id == p_Id
join diamond in myDatabaseDataSet.Diamond
on item.p_Id equals diamond.p_Id
join category in myDatabaseDataSet.DiamondCategory
on diamond.dc_Id equals category.dc_Id
select new
{
Product = item.p_Name,
Weight = diamond.d_Weight,
Category = category.dc_Name
}.ToList();
dataGridView1.DataSource = query;

Help required to optimize LINQ query

I am looking to optimize my LINQ query because although it works right, the SQL it generates is convoluted and inefficient...
Basically, I am looking to select customers (as CustomerDisplay objects) who ordered the required product (reqdProdId), and are registered with a credit card number (stored as a row in RegisteredCustomer table with a foreign key CustId)
var q = from cust in db.Customers
join regCust in db.RegisteredCustomers on cust.ID equals regCust.CustId
where cust.CustomerProducts.Any(co => co.ProductID == reqdProdId)
where regCust.CreditCardNumber != null && regCust.Authorized == true
select new CustomerDisplay
{
Id = cust.Id,
Name = cust.Person.DisplayName,
RegNumber = cust.RegNumber
};
As an overview, a Customer has a corresponding Person which has the Name; PersonID is a foreign key in Customer table.
If I look at the SQL generated, I see all columns being selected from the Person table. Fyi, DisplayName is an extension method which uses Customer.FirstName and LastName. Any ideas how I can limit the columns from Person?
Secondly, I want to get rid of the Any clause (and use a sub-query) to select all other CustomerIds who have the required ProductID, because it (understandably) generates an Exists clause.
As you may know, LINQ has a known issue with junction tables, so I cannot just do a cust.CustomerProducts.Products.
How can I select all Customers in the junction table with the required ProductID?
Any help/advice is appreciated.
The first step is to start your query from CustomerProducts (as Alex Said):
IQueryable<CustomerDisplay> myCustDisplay =
from custProd in db.CustomerProducts
join regCust in db.RegisteredCustomers
on custProd.Customer.ID equals regCust.CustId
where
custProd.ProductID == reqProdId
&& regCust.CreditCardNumber != null
&& regCust.Authorized == true
select new CustomerDisplay
{
Id = cust.Id,
Name = cust.Person.Name,
RegNumber = cust.RegNumber
};
This will simplify your syntax and hopefully result in a better execution plan.
Next, you should consider creating a foreign key relationship between Customers and RegisteredCustomers. This would result in a query that looked like this:
IQueryable<CustomerDisplay> myCustDisplay =
from custProd in db.CustomerProducts
where
custProd.ProductID == reqProdId
&& custProd.Customer.RegisteredCustomer.CreditCardNumber != null
&& custProd.Customer.RegisteredCustomer.Authorized == true
select new CustomerDisplay
{
Id = cust.Id,
Name = cust.Person.Name,
RegNumber = cust.RegNumber
};
Finally, for optimum speed, have LINQ compile your query at compile time, rather than run time by using a compiled query:
Func<MyDataContext, SearchParameters, IQueryable<CustomerDisplay>>
GetCustWithProd =
System.Data.Linq.CompiledQuery.Compile(
(MyDataContext db, SearchParameters myParams) =>
from custProd in db.CustomerProducts
where
custProd.ProductID == myParams.reqProdId
&& custProd.Customer.RegisteredCustomer.CreditCardNumber != null
&& custProd.Customer.RegisteredCustomer.Authorized == true
select new CustomerDisplay
{
Id = cust.Id,
Name = cust.Person.Name,
RegNumber = cust.RegNumber
};
);
You can call the compiled query like this:
IQueryable<CustomerDisplay> myCustDisplay = GetCustWithProd(db, myParams);
I'd suggest starting your query from the product in question, e.g. something like:
from cp in db.CustomerProducts
join .....
where cp.ProductID == reqdProdID
As you have found, using a property defined as an extension function or in a partial class will require that the entire object is hydrated first and then the select projection is done on the client side because the server has no knowledge of these additional properties. Be glad that your code ran at all. If you were to use the non-mapped value elsewhere in your query (other than in the projection), you would likely see a run-time exception. You can see this if you try to use the Customer.Person.DisplayName property in a Where clause. As you have found, the fix is to do the string concatenation in the projection clause directly.
Lame Duck, I think there is a bug in your code as the cust variable used in your select clause isn't declared elsewhere as a source local variable (in the from clauses).

Resources