This is a multi-progned question so please bear with me! I have two queries:
var dynamicResult = Repository.Select<Table1>()
.Where(b => b.InactivatedD == null)
.Select(b => b.Table2);
var staticResult = Repository.Select<Table2>()
.Where(b => b.column == "CONSTANT");
return dynamicResult.Union(staticResult).ToList();
This works fine. Now I have added an additional property to the the Table2 class and have instructed EF to ignore the field within my configuration like so:
Ignore(e => NewColumn);
This too is working well as I can set the field properly without EF throwing an exception. Now I don't know if there is an easy way to do what I want. In my first query Table1 has a column that I want to use to hydrate this new column on Table2 but I don't know of an easy way to do this. The only thing I have been able to come up with is:
var dynamicResult = Repository.Select<Table1>()
.Where(b => b.InactivatedD == null)
.Select(b => new Table2 { Column1 = b.Table2.Column1, NewColumn = b.SomeColumn ... <additional initialization> });
This is a little messy and the initialization would get pretty long since this entity has about 15 columns I'd need to hydrate. I could, of course, just traverse the association between Table2 and Table1 in my property rather than trying to set it in the above query but that seems like additional work and one more query to maintain. Additionally, when using the method above, my union no longer works. If my queries look like this:
var dynamicResult = Repository.Select<Table1>()
.Where(b => b.InactivatedD == null)
.Select(b => new Table2 { Column1 = b.Table2.Column1, NewColumn = b.SomeColumn })
var staticResult = Repository.Select<Table2>()
.Where(b => b.column == "CONSTANT")
.Select(b => new Table2 { Column1 = b.Table2.Column1, NewColumn = b.SomeColumn })
return dynamicResult.Union(staticResult).ToList();
I get an exception that the Entity or Complex type, Table 2, can not be constructed by an Entity Framework query which kind of has me at a loss. I understood why I was getting this error before I told EF to ignore the NewColumn but now I am not sure why this error is popping up.
In summation: is there a better way to hydrate my new column then what I have proposed above and can anyone identify why I am unable to union entities created using new from within a query?
Thanks!
It is never allowed to create an entity type in an EF query irrespective of which properties you address. The reason is that EF has no way to track such entities, because it did not materialize them itself.
You should define a type that looks like Table2, including the new column and project to that type in both queries. You will be able to union the queries.
Related
I have the following ORMLite query in which I wish to return the columns from the primary table, i.e. the one referenced by the From<T>() method, filtered by a join to a secondary table.
var query = conn
.From<SurveyQuestionOptionDTO>()
.Join<SurveyQuestionDTO>((o, q) => o.SurveyQuestionId == q.Id, conn.JoinAlias("q"))
.Where<SurveyQuestionDTO>(q => q.SurveyId == surveyId);
return conn.Select(query);
This generates the following SQL query
SELECT "Id", "SurveyQuestionId", "Option", "Selected", "Sequence"
FROM "dbo"."SurveyQuestionOptions"
INNER JOIN "dbo"."SurveyQuestions" q
ON ("dbo"."SurveyQuestionOptions"."SurveyQuestionId" = "q"."Id")
WHERE ("dbo"."SurveyQuestions"."SurveyId" = #0)
This would be fine except that both tables have Id and Sequence columns so the query fails with ambiguous column references. If I was hand-coding the SQL I would simply alias the SurveyQuestionOptions table, for instance with o and use that alias on each column in the select list, like o.Id, o.SurveyQuestionId, o.Option, o.Selected, o.Sequence or even just o.* as all columns are being returned. My question is, what is the best way to make ORMLite generate such code?
I have found a way to do it, by adding a Select<T>() method returning an anonymous class, as follows
var query = conn
.From<SurveyQuestionOptionDTO>()
.Join<SurveyQuestionDTO>(
(o, q) => o.SurveyQuestionId == q.Id && q.SurveyId == surveyId,
conn.JoinAlias("q"))
.Select<SurveyQuestionOptionDTO>(o => new
{
o.Id,
o.SurveyQuestionId,
o.Option,
o.Selected,
o.Sequence
});
return conn.Select(query);
This works, but it seems like a lot of extra code to achieve a simple result, and because columns are explicitly returned, requires this code to change if the table ever gets a new column and the DTO class is re-generated. Is there a better, simpler way?
I have found a simpler way that also resolves future impact of column changes. Instead of returning a new anonymous class from the Select<T>() method you can simply return the instance that's passed in. So the code now looks like this, and still works as expected.
var query = conn
.From<SurveyQuestionOptionDTO>()
.Join<SurveyQuestionDTO>(
(o, q) => o.SurveyQuestionId == q.Id && q.SurveyId == surveyId,
conn.JoinAlias("q"))
.Select<SurveyQuestionOptionDTO>(o => o);
return conn.Select(query);
I'am trying to write following in Dynamic-linq. I have following statement in ordinary linq
var result = DBContext.Report
.Include(h => h.ReportRoleMemberships)
.Join(DBContext.ReportRoleMemberships.Where(Rrm =>Rrm.ValidTo==null && Rrm.UserId==userId),
t=>t.Id,
y=>y.Report_Id,
(t,y) => new { Ha=t, Rrm=y })
.OrderBy(h => h.Rrm.ReportRoleValue);
userId is a int with the UserId in the code above.
I want to sort on ReportRoleValue and feels this feel a little bit over the top, but I havent a clue how I should write this is dynamic linq , since it is orderby on one-to-many parent-child relationship.
Assuming that there is a navigation property from ReportRoleMemberships to Reports, you can turn the query around and by that remove the separate Join, e.g.:
var result = DBContext.ReportRoleMemberships
.Include(h => h.Report)
.Where(Rrm => Rrm.ValidTo == null && Rrm.UserId == userId)
.OrderBy(h => h.ReportRoleValue);
This query selects the entries from ReportRoleMemberships and applies the conditions to them and also populates the Report part so that you retrieve both the ReportRoleMembership and Report information in one query.
I am relatively new to Entity Framework 6.0 and I have come across a situation where I want to execute a query in my C# app that would be similar to this SQL Query:
select * from periods where id in (select distinct periodid from ratedetails where rateid = 3)
Is it actually possible to execute a query like this in EF or would I need to break it into smaller steps?
Assuming that you have in your Context class:
DbSet<Period> Periods...
DbSet<RateDetail> RateDetails...
You could use some Linq like this:
var distincts = dbContext.RateDetails
.Where(i => i.rateId == 3)
.Select(i => i.PeriodId)
.Distinct();
var result = dbContext.Periods
.Where(i => i.Id)
.Any(j => distincts.Contains(j.Id));
Edit: Depending on your entities, you will probably need a custom Comparer for Distinct(). You can find a tutorial here, and also here
or use some more Linq magic to split the results.
Yes, this can be done but you should really provide a better example for your query. You are already providing a bad starting point there. Lets use this one:
SELECT value1, value2, commonValue
FROM table1
WHERE EXISTS (
SELECT 1
FROM table2
WHERE table1.commonValue = table2.commonValue
// include some more filters here on table2
)
First, its almost always better to use EXISTS instead of IN.
Now to turn this into a Lambda would be something like this, again you provided no objects or object graph so I will just make something up.
DbContext myContext = this.getContext();
var myResults = myContext.DbSet<Type1>().Where(x => myContext.DbSet<Type2>().Any(y => y.commonValue == x.commonValue)).Select(x => x);
EDIT - updated after you provided the new sql statement
Using your example objects this would produce the best result. Again, this is more efficient than a Contains which translates to an IN clause.
Sql you really want:
SELECT *
FROM periods
WHERE EXISTS (SELECT 1 FROM ratedetails WHERE rateid = 3 AND periods.id = ratedetails.periodid)
The Lamda statement you are after
DbContext myContext = this.getContext();
var myResults = myContext.DbSet<Periods>()
.Where(x => myContext.DbSet<RateDetails>().Any(y => y.periodid == x.id && y.rateid == 3))
.Select(x => x);
Here is a good starting point for learning about lamda's and how to use them.
Lambda Expressions (C# Programming Guide).
this is your second where clause in your query
var priodidList=ratedetails.where(x=>x.rateid ==3).DistinctBy(x=>x.rateid);
now for first part of query
var selected = periods.Where(p => p.id
.Any(a => priodidList.Contains(a.periodid ))
.ToList();
I'm trying to get a list that displays 2 values in a label from a parent and child (1-*) entity collection model.
I have 3 entities:
[Customer]: CustomerId, Name, Address, ...
[Order]: OrderId, OrderDate, EmployeeId, Total, ...
[OrderStatus]: OrderStatusId, StatusLevel, StatusDate, ...
A Customer can have MANY Order, which in turn an Order can have MANY OrderStatus, i.e.
[Customer] 1--* [Order] 1--* [OrderStatus]
Given a CustomerId, I want to get all of the Orders (just OrderId) and the LATEST (MAX?) OrderStatus.StatusDate for that Order.
I've tried a couple of attempts, but can seem to get the results I want.
private IQueryable<Customer> GetOrderData(string customerId)
{
var ordersWithLatestStatusDate = Context.Customers
// Note: I am not sure if I should add the .Expand() extension methods here for the other two entity collections since I want these queries to be as performant as possible and since I am projecting below (only need to display 2 fields for each record in the IQueryable<T>, but thinking I should now after some contemplation.
.Where(x => x.CustomerId == SelectedCustomer.CustomerId)
.Select(x => new Custom
{
CustomerId = x.CustomerId,
...
// I would like to project my Child and GrandChild Collections, i.e. Orders and OrderStatuses here but don't know how to do that. I learned that by projecting, one does not need to "Include/Expand" these extension methods.
});
return ordersWithLatestStatusDate ;
}
---- UPDATE 1 ----
After the great solution from User: lazyberezovsky, I tried the following:
var query = Context.Customers
.Where(c => c.CustomerId == SelectedCustomer.CustomerId)
.Select(o => new Customer
{
Name = c.Name,
LatestOrderDate = o.OrderStatus.Max(s => s.StatusDate)
});
In my hastiness from my initial posting, I didn't paste everything in correctly since it was mostly from memory and didn't have the exact code for reference at the time. My method is a strongly-typed IQueryabled where I need it to return a collection of items of type T due to a constraint within a rigid API that I have to go through that has an IQueryable query as one of its parameters. I am aware I can add other entities/attributes by either using the extension methods .Expand() and/or .Select(). One will notice that my latest UPDATED query above has an added "new Customer" within the .Select() where it was once anonymous. I'm positive that is why the query failed b/c it couldn't be turn into a valid Uri due to LatestOrderDate not being a property of Customer at the Server level. FYI, upon seeing the first answer below, I had added that property to my client-side Customer class with simple { get; set; }. So given this, can I somehow still have a Customer collection with the only bringing back those 2 fields from 2 different entities? The solution below looked so promising and ingenious!
---- END UPDATE 1 ----
FYI, the technologies I'm using are OData (WCF), Silverlight, C#.
Any tips/links will be appreciated.
This will give you list of { OrderId, LatestDate } objects
var query = Context.Customers
.Where(c => c.CustomerId == SelectedCustomer.CustomerId)
.SelectMany(c => c.Orders)
.Select(o => new {
OrderId = o.OrderId,
LatestDate = o.Statuses.Max(s => s.StatusDate) });
.
UPDATE construct objects in-memory
var query = Context.Customers
.Where(c => c.CustomerId == SelectedCustomer.CustomerId)
.SelectMany(c => c.Orders)
.AsEnumerable() // goes in-memory
.Select(o => new {
OrderId = o.OrderId,
LatestDate = o.Statuses.Max(s => s.StatusDate) });
Also grouping could help here.
If I read this correctly you want a Customer entity and then a single value computed from its Orders property. Currently this is not supported in OData. OData doesn't support computed values in the queries. So no expressions in the projections, no aggregates and so on.
Unfortunately even with two queries this is currently not possible since OData doesn't support any way of expressing the MAX functionality.
If you have control over the service, you could write a server side function/service operation to execute this kind of query.
I'm new to linq. I need to run a query that joins two columns (AnonymousUser.AnonymousId being uniqueidentifier and comment.UserId being nvarchar(100)), something like below:
using (CommentEntities db = new CommentEntities())
{
// filteredComments is a query that is not run until the next .ToList()
IQueryable<Comment> filteredComments = this.CommentGetList(...);
var query = from comment in filteredComments
// following line is the syntax error, because columns' types don't match
join user in db.AnonymousUsers on comment.UserId equals user.AnonymousId into gj
from userNull in gj.DefaultIfEmpty()
select new CommentWithName
{
Comment = comment,
UserId = comment.UserId,
FirstName = (userNull == null ? "" : userNull.Name),
LastName = "",
Email = (userNull == null ? "" : userNull.Email)
};
return query.ToList();
}
First I was happy writing the query with .ToString() ! As it turns out that entity framework doesn't know how to translate it to sql. The same is true for Guid.Parse(string). Also new Guid(string) cannot be used in linq to entities (only parameterless constructors allowed)!
So after searching, I found out it's not possible doing such thing in EF 4.0! I migrated my code to a stored procedure that I'm not really happy about it.
Is it possible to tell entity framework to use a CAST in SQL?
Is there any solutions to this problem? Is there any way that I can bring the logic in code?
NOTE: I meant to do it in one GO. Otherwise one possible solution is to get Entities from first table, and put the Ids in a list and get entities from second table.
call toList() before applying those methods. Like:
var Product = db.Products.Where(p => p.ProductId == Guid.Parse("B4E913F9-166C-49BA-AADE-6DB889D1756F")).Single();
Would throw a
c# LINQ to Entities does not recognize the method "System.Guid Parse" (System.String)' method, and this method cannot be translated into a store expression
But this works:
var Product = db.Products.ToList().Where(p => p.ProductId == Guid.Parse("B4E913F9-166C-49BA-AADE-6DB889D1756F")).Single()
p.s.: I think you will lose lazyloading but you can do eagerloading with .Include before calling .ToList().
If your list is object list you could convert it to the type which has Guid as identifier, first create new anonymous type and then filter it base on UserId, sure UserId which is of type int, wont include in join:
int output = 0;
var secondList = list.Where(x=>!int.TryParse(x.UserID, out output))
.Select(x=>new {Comment = x, ID = new Guid(x.UserID))
.ToList();
Now you could run your query on db by using secondList.