This is mostly to see if I can find a way to work around this limitation.
Let's say I have the following query:
var query = (from a in db.Table
where a.CustomFieldId == FieldID && a.ListingId == listingID
select a.SomeTypeValue);
The table I am querying is set for custom fields that may vary in type, so it has several columns but only uses the appropriate column to store the value based on the field's selected type.
The table looks somewhat like this:
I want to be able to choose which column I select without rewriting the whole query. Is this possible?
Thanks in advance,
Your query can be rewrited to use "Method Call LINQ":
db.Table
.Where(a => a.CustomFieldId == FieldID && a.ListingId == listingID)
.Select(x => x.SomeType);
You may split query into Where and Select parts then:
var result = whereQuery.Select(x => x.BoolValue);
or
var result = whereQuery.Select(x => x.IntValue);
You may even encapsulate that logic into method:
IEnumerable<T> GetValues<T>() {
var query = db.Table
.Where(a => a.CustomFieldId == FieldID && a.ListingId == listingID);
if (typeof(T)==typeof(bool)) {
return query.Select(x => x.BoolColumn);
}
else if (typeof(T) == typeof(int)) {
return query.Select(x => x.IntColumn);
}
// other types here
}
Related
I've looked at several possible solutions to this problem, and the ones I have tried do not seem to work. One solution was to use if statements for the optional filters, which doesn't work because I have multiple joins and the where clause is in the last join.
The optional parameters are: roleId, disciplineId, resourceId, and projectName.
try
{
IQueryable<ProjectPlanHeader> bob =
(
from h in context.ProjectPlanHeaders
join r in context.ProjectPlanRevisions on h.ProjectPlanHeaderId equals r.ProjectPlanHeaderId
join a in context.PlanActivityLineItems on r.PlanRevisionId equals a.PlanRevisionId
where ((roleId == null || a.RequiredRoleId == roleId) &&
(disciplineId == null || a.DisciplineId == disciplineId) &&
(resourceId == null || a.ActualResourceId == resourceId) &&
(h.ProjectPlanName.ToLower().Contains(projectName.ToLower()) || projectName == String.Empty))
select h
)
.Include(x => x.ProjectPlanRevisions)
.ThenInclude(y => y.PlanActivityLineItem)
.ThenInclude(z => z.PlannedHours)
.Include(x => x.ActualPlanRevisions)
.ThenInclude(y => y.ActualPlanActivities)
.ThenInclude(z => z.ActualHours);
var john = bob.ToList();
return bob;
}
catch (Exception ex)
{
return null;
}
I added the try/catch so I could see what was happening, as it was silently failing. What I found was a "Object not set to an instance of an object". That's never helpful, because I don't know what object it's talking about. Can someone please show me how to do this the right way?
UPDATE: Thanks for the responses I got, but unfortunately they don't work. The problem is that I end up getting multiple headers back when I filter. This happens because there are multiple revisions for each header, and I really only need the max rev. I tried changing the initial query so that only the max rev was included, and that still did not help. There does not appear to be a solution for this issue, so I will have to do it another way.
Rewrite query to do not use explicit joins, because you have navigation properties. Also because of JOINS you have duplicated records, you will discover it later.
var query = context.ProjectPlanHeaders
.Include(x => x.ProjectPlanRevisions)
.ThenInclude(y => y.PlanActivityLineItem)
.ThenInclude(z => z.PlannedHours)
.Include(x => x.ActualPlanRevisions)
.ThenInclude(y => y.ActualPlanActivities)
.ThenInclude(z => z.ActualHours)
.AsQueryable();
if (!string.IsNullOrEmpty(projectName))
{
// here we can combine query
query = query
.Where(h => h.ProjectPlanName.ToLower().Contains(projectName.ToLower()));
}
// check that we have to apply filter on collection
if (roleId != null || disciplineId != null || resourceId != null)
{
// here we have to do filtering as in original query
query = query
.Where(h => h.ProjectPlanRevisions
.Where(r => roleId == null || r.PlanActivityLineItem.RequiredRoleId == roleId)
.Where(r => disciplineId == null || r.PlanActivityLineItem.DisciplineId == disciplineId)
.Where(r => resourceId == null || r.PlanActivityLineItem.ActualResourceId == resourceId)
.Any()
);
}
var result = query.ToList();
Let me clarify my comment with an example:
So: An IQueryable is used to build up an expression tree. They are not evaluated until enummerated (e.g. ToList or FirstOrDefault). I.e. you can conditional add Where and Includes with little to no cost before ennumerating`
Thus you could do this,
IQueryable<ProjectPlanHeader> bob =
context.ProjectPlanHeader
.Include(x => x.ProjectPlanRevisions)
.ThenInclude(y => y.PlanActivityLineItem);
if (roleId != null) {
bob =
from h in bob
join r in context.ProjectPlanRevisions on h.Id equals r.ProjectPlanHeaderId
join a in context.PlanActivityLineItems on r.Id equals a.ProjectPlanRevisionId
where a.RequiredRoleId == roleId
select h;
}
// same for the rest.
var john = bob.ToList();
writing the chained filer is not easiest, but it works
Ok, so I have a model that looks like this:
public int idA
public int idB
public int total
public virtual TableA TableA { get; set; }
public virtual TableB TableB { get; set; }
The models for Table A and B are similar to each other, they both tie to this with something like
public virtual List<Association> Assocation { get; set; }
I am now trying to query this, and it is working but I want to be able to filter the results when idB equals a certain integer, for example:
var results = db.TableA
.Where(t => t.idA == id)
.Where(t => t.Association.Where(m => m.idB == 1));
This returns the following exceptions:
Cannot implicitly convert to 'bool'
Cannot convert lambda expression to delegate type 'System.Func' because some of the return types in the block are not implicitly convertible to the delegate return type
Thank you so much for your help!
Update
So I have implemented the following:
var results = db.TableA
.Where(t => t.idA == id)
.Where(t => t.Association.Any(m => m.idB == 1));
Since this association table uses a compound primary key there should only be 1 result returned. There are about 200 results that match the given t.idA == id and that is what I am getting back. It is not only returning the 1 result.
Just for thoroughness here is the query being created, I omitted the fields themselves to simplify it some:
SELECT ... fields here ...
WHERE ([Extent1].[id] = #p__linq__0) AND (#p__linq__0 IS NOT NULL)
AND ( EXISTS (SELECT ... fields here ....
WHERE ([Extent1].[id] = [Extent2].[idA]) AND (1 = [Extent2].[idB])
)
)
Update 2
So the problem with .Any() is it will return the entire collection IF it contains a value that matches 1, all I was wanting was it to return the value that matches 1. So because of this, the only thing I could think of to do was to take the extra 118 rows and then filter the list returned. Luckily upon profiling, this hasn't impacted the SQL server as I initially expected so it was not necessary to do pre-optimization. However, if anyone does know how to filter a list within the initial SQL query using LINQ I would still love to know as I'm sure I could use this in the future where the impact on the database may be more severe, thus the optimization warranted.
The '.Where' lambda function needs to return a boolean value. Currently, you are returning the results of a '.Where' against another recordset. Instead, you probably intended something like this:
var results = db.TableA
.Where(t => t.idA == id)
.Where(t => t.Association.Any(m => m.idB == 1));
The '.Any' function will return true if 't.Association' contains any records that match the condition.
I think what you want to do is use the Any method. Something like this should work:
var results = db.TableA
.Where(t => t.idA == id)
.Where(t => t.Association.Any(m => m.idB == 1));
This will return any Table with the idA equal to id and at least on Association with idB equal to 1.
Or if you prefer query syntax:
var results =
from a in TableA
where a.idA == id && a.Association.Any(m => m.idB == 1)
select a;
This should work:
var results = db.TableA
.Where(t => t.idA == id)
.Select(t => new {
Item = t
, AssociatedItem = t.Association.SingleOrDefault(m => m.idB == 1)
})
.Where(p => p.Associated != null)
.ToList();
This code produces a list of objects of anonymous type with two fields - the Item field with the item, and the AssociatedItem containing its associated item that has idB of 1.
Note that the above code assumes that there is at most one associated item with idB of 1; otherwise, SingleOrDefault would fail.
I have the following setup:
Table ShoeAreas that has columns ShoeId and MaterialId.
Table Shoes that has columns ID and Status.
I have a method that takes one argument - materialId and the goal is to determine if there is a record in ShoeAreas with a MaterialId equal to the one passed like an argument. And if such a record (or records most probably) exist if they are relateed to shoe from Shoes withStatus` = Production.
I tried this :
return shoeService.All().
Join(shoeAreaService.All(),
s => s.ID,
sa => sa.ShoeId,
(s, sa) => (sa.MaterialId == matId)).
Any(s => (s.Status == (byte)EntityStatusProd.Production)));
But I get error on the Any.. line saying } expected and also this is my second Linq to Entity query that I write so I have doubts if it's syntax problem or the query is wrong itself.
You are returning IEnumerable<bool> from Join method (values of condition sa.MaterialId == matId). Create anonymous type which will hold both joined entities instead:
return shoeService.All()
.Join(shoeAreaService.All(),
s => s.ID,
sa => sa.ShoeId,
(s, sa) => new { s, sa }) // here
.Any(x => (x.sa.MaterialId == matId) &&
(x.s.Status == (byte)EntityStatusProd.Production)));
you can try this: (linq )
from shoe in Shoes
join shoeArea in ShoesArea on shoe.ID equals shoeArea.ShoeID
where shoeArea.MeterialID == matID && shoe.Status == (byte)EntityStatusProd.Production
select new {shoe.ID,shoe.Status};
return shoeService.All().Any(s => shoeAreaService.All()
.Any(sa => sa.MaterialId == matId
&& s.Id == sa.ShoeId)
&& s.Status == (byte)EntityStatusProd.Production);
I have a lambda 'where' query, querying an Order table like this:
List<Order> returnedOrders = _session.Query<Script>()Where(s => s.orderId == orderIdParam).ToList();
I want to also check the value of a column in the related OrderDetails table. So returnedOrders has a collection of OrderDetails, i.e. returnedOrders.orderDetails
So the SQL query would look something like:
Where OrderId = 12345 and Order.OrderDetail.CreatedDate = '01-Jan-2013'
Can anyone help me with the correct syntax please?
You can use a logical AND (&&) inside the Where method:
var date = new Date(2013,1,1);
List<Order> returnedOrders =
_session.Query<Script>()
.Where(s =>
s.orderId == orderIdParam &&
s.OrderDetails.Any(d => d.CreatedDate == date))
.ToList();
You can alternatively append another Where method.
var date = new Date(2013,1,1);
List<Order> returnedOrders =
_session.Query<Script>()
.Where(s => s.orderId == orderIdParam)
.Where(s => s.OrderDetails.Any(d => d.CreatedDate == date))
.ToList();
Since you know Id of order it seems useless but something like this
from order in orders
from detail in order.Details
where
order.Id = orderId &&
order.Id == detail.OrderId &&
detail.CreateDate == createDate
select order
I'm have a SQL statement which I am trying to transform in a LINQ statement...
SELECT DISTINCT mc.*
FROM ManufractorCategories mc
WHERE mc.Active = 'true'
AND mc.Folder = 'false'
AND (mc.Id not in (SELECT Category_id FROM Manufractor_Category
WHERE Manufractor_id = 3));
That's my last, not working LINQ statement
(IQueryable<object>)db.ManufractorCategories
.Where(o => o.Active == active)
.Where(o => o.Folder == folder)
.Select(i => new { i.Id, i.Folder }).Except(db.Manufractor_Categories.Where(t => t.Manufractor_id == id).Select(t => new { t.Category_id })).Distinct();
I've tried the whole Sunday on that, but the Except statement won't work.
Thanks in advances for any help!
The Except method requires two sets of the same type - this means that you would have to select objects of type ManufractorCategory in the nested query as well as in the outer query - then it would select all categories that are in the first one and not in the second one.
An easier alternative is to use the Contains method to check whether the current ID is in a list of IDs that you want to filter. The following should work:
var q =
db.ManufractorCategories
.Where(o => o.Active == active)
.Where(o => o.Folder == folder)
.Select(i => new { i.Id, i.Folder })
.Where(o =>
!db.Manufractor_Categories
.Select(t => t.Manufractor_id)
.Contains(o.Id)
.Distinct();
And a simplified version using query syntax:
var q =
from o in db.ManufractorCategories
where o.Active == active && o.Folder == folder &&
db.Manufractor_Categories
.Select(t => t.Manufractor_id)
.Contains(o.Id)
select new { i.Id, i.Folder };
The Except statement is going to get a list of objects with the Category_id property. However, you're query has a result that contains objects with the Id and Folder properties. The query will most likely be unable to see where these objects are equal, and so, the Except clause won't take effect.