I wonder if anyone can shed some light on what may be happening here. I'm using C#, MVC, with entity framework.
So I run these two lines of code:
var booboo = _context.AppItems.Where(ai => ai.id == 101);
var sql = booboo.ToString();
And I get some strange behavior. The booboo.ToString() method hangs, thus failing. Nothing about the booboo DbQuery object works properly in fact.
I'm having similar problems all over the code with my AppItem entity (AppItems is DbSet as you might guess). Entity Framework appears to be unable to construct a query for the AppItem entity.
Edit:
I wasn't patient enough! After leaving it for a very long time, I do get the following exception:
"Message=Internal error: An expression services limit has been reached. Please look for potentially complex expressions in your query, and try to simplify them."
Interestingly that's a Sql.Client exception, which I wasn't expecting.
Here's what the AppItem class looks like:
public class AppItem : Domain.Item
{
public int? UserProfileId { get; set; }
public virtual UserProfile UpdatedByUser { get; set; }
[MaxLength(50)]
public String Type { get; set;}
public DateTime UpdatedDate { get; set;}
// flags
public virtual ICollection<ItemFlag> Flags { get; set; }
// actions
public virtual ICollection<ItemAction> Actions { get; set; }
// notes
public virtual ICollection<Note> Notes { get; set; }
}
Domain Item contains a primary key field (id) and a few other fields.
The Note / ItemAction / ItemFlag Classes there all inherit from AppItem, so perhaps some sort of circular referencing is to blame?
Other items can be queried just fine. For example, I have numerous classes that inherit from AppItem (like ItemFlag, ItemAction and Note) and I can query all of these just fine.
So, where Members is DbSet and Member inherits from AppItem:
var foofoo = _context.Members.Where(ai => ai.id = 101);
var sql = foofoo.ToString();
This Works fine; foofoo.ToString() returns the constructed SQL and everything appears to be in order.
It seems really bizarre to me, there's no error message or anything, the application just hangs when it tries to query AppItems. The table exists in the database, but that doesn't matter because we aren't getting as far as querying the database, we are failing to construct a query in the first place.
Thanks in advance for any help.
I found what the problem was.
I'm using Table-per-Type for inheritance. With AppItem being a base type, the SQL query it generates for querying it is huge (several thousand lines long in this case) and causes problems.
So basically, you need to avoid querying on base types that have more than a few types inheriting from them when using Table-per-Type.
I am assuming that your query is meant to return 1 item.
Add .FirstOrDefault(); onto the end of your query to only return one item (your current query returns an IQueriable of type AppItems)
The Entity Framework does not execute the query until needed, so in your code it will execute the query when the .ToString() method is called.
Try this:
var booboo = _context.AppItems.Where(ai => ai.id == 101).FirstOrDefault();
if (booboo != null)
{
var sql = booboo.ToString();
//etc
}
Related
I have two pieces of code which seems have same functionality but one of them lead to exception but another one is works like a charm. I want to know can you imagine why this happens?
I have below line in my web application which leads to this exception:
LINQ to Entities does not recognize the method 'System.Object
FilterDeliveryAddressFields(WebApplication1.Models.DeliveryAddress)'
dynamic deliveryAddresses = (from address in db.DeliveryAddress
select filterDeliveryAddressFields(address)).ToList();
And here is filterDeliveryAddressFields:
private dynamic filterDeliveryAddressFields(DeliveryAddress address)
{
return new { address.address, address.deliverTo, address.deliverToPhoneNumber, address.id };
}
And here is Linq-2-Sql generated Model for DeliveryAddress which have foreign key relationship with Subscriber:
public partial class DeliveryAddress
{
public int id { get; set; }
public int fkSubscriberId { get; set; }
public string address { get; set; }
public string deliverTo { get; set; }
public string deliverToPhoneNumber { get; set; }
public virtual Subscriber Subscriber { get; set; }
}
But when I change db.DeliveryAddress items to list first and then run code again as below everything goes well and no exception occurs again. I want to know what wrong with first code snippet which does not happen in below snippet?
List<DeliveryAddress> addresseList = db.DeliveryAddress.ToList(); //magic trick?!
dynamic deliveryAddresses =
(from address in addresseList
select filterDeliveryAddressFields(address)).ToList();
Actually, your method couldn't be translated to T-SQL, Linq to Entities couldn't recognize every method, the magic behind the .ToList() method which you are looking for is, after data is loaded, any further operation (such as select) is performed using LINQ to Objects, on the data already in memory.
However the performance is not guaranteed in this approach, as you have to load
your data into memory, so imagine you have a lot of data in your db, what will be happened next?
Agree with #Salah . In LINQ to Entities, it first try to convert your query to command tree and execute against your ORM. Please read here you can find more details.
In your first approach Linq tries to convert your filterDeliveryAddressFields(address)) method to command tree. That is why it complains that LINQ to Entities does not recognize the method.
In your second approach you execute against list or IEnumerable<T>, which means you use LINQ to Object. You can read more about it here.
For your first solution you can try another implementation. Simply try to use aggregate method to filter your result. Then you don't need filterDeliveryAddressFields(address)) method. You can find example here
Something like this, (Sorry I didn't try this my self. This is only for you to get an idea.)
from address in db.DeliveryAddress
select new { address.address, address.deliverTo, address.deliverToPhoneNumber, address.id };
I am using Entity Framework Core 2.2.6. I'm going to try and make this question concise and apologies in advance if it ends up being a wall of text.
The error I am seeing is an ambiguous column name in the SQL Entity Framework Core generates.
So my situation is this: I have two entities with a many-to-one relationship. The "parent" entity implements
an interface that has a property that is of type IChildEntity. Here are the interfaces:
public interface IParentEntity
{
IChildEntity Child { get; set; }
string Prop1 { get; set; }
string Prop2 { get; set; }
}
public interface IChildEntity
{
string ChildProp1 { get; set; }
string ChildProp2 { get; set; }
}
I am using ef core's fluent api and in order to set up the relationship between parent and child
I am using a concrete type of ChildEntity and defining a IChildEntity property to conform to the
interface and just passing things through to the concrete type:
public class ChildEntity : IChildEntity
{
public long ID {get; set;}
public string ChildProp1 { get; set; }
public string ChildProp2 { get; set; }
}
public class ParentEntity : IParentEntity
{
public long ID { get; set; }
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public long ChildID { get; set; }
// Navigation property so EF Core can create the relationship
public ChildEntity MappedChild { get; private set; }
// this is to adhere to the interface
// just pass this through to the backing concrete instance
[NotMapped]
public IChildEntity Child
{
get => MappedChild;
set => MappedChild = (ChildEntity)value;
}
}
Then in OnModelCreating I set up the relationship like so:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ParentEntity>()
.HasOne(e => e.MappedChild)
.WithMany()
.HasForeignKey(e => e.ChildID);
}
This works and the relationship gets set up as expected, however I am finding when I do a query it can generate
some SQL that can result in an ambigous column error in some database engines. Here is the example query:
MyContext.ParentEntity
.Include(p => p.MappedChild)
.Where(p => p.Prop1.Equals("somestring")
.FirstOrDefault()
The SQL that gets generated is similar to:
SELECT p."ID", p."ChildID", p."Prop1", p."Prop1", "p.MappedChild"."ID", "p.MappedChild"."ChildProp1", "p.MappedChild"."ChildProp2"
FROM "ParentEntity" AS p
INNER JOIN "ChildEntity" AS "p.MappedChild" ON p."ChildID" = "p.MappedChild"."ID"
WHERE p."Prop1" = 'somestring'
ORDER BY "p.MappedChild"."ID"
LIMIT 1
The problem here is we are selecting two columns with the name ID and not aliasing. Some databases will be ok with this
but some will not. A work around I can do for this is to do two separate queries to get the entity and the child entity:
var parent = MyContext.ParentEntity
.Where(p => p.Prop1.Equals("somestring")
.FirstOrDefault()
MyContext.Entry(parent).Reference(p => s.MappedChild).Load();
But this is less than ideal since it does multiple queries and is a bit less elegant than just using Include()
Because this seems like such a common use case and I couldn't find any bug reports against EF Core for this type of
behavior it is my suspicion that I am doing something wrong here that is resulting in EFCore not aliasing column names
for this type of query. I was thinking it could be the bit of trickery I have to do to ensure my entity implements it's interface
(this is something I can't due to constraints in the codebase and other integrations) but the more I look at it the less likely that
seems to me since we are directly dealing with the "mapped" property in EF related code and it's completely unaware of the interface.
My questions are - can anyone see something in my implementation that would cause this? Could anyone
suggest a better workaround than what I have here? Any advice here would be appreciated. Thanks much.
This is an old Entity framework bug with the Oracle company products bug including the MySQL database and Oracle database (12.1 and older).
I see the
ORA-00918: column ambiguously defined
error mostly when:
Selecting one entity with including parent entity.
Selecting one entity with value object own one command
This error appears when using Find, First, FirstOrDefault, Last, Single and all single entity selector commands.
I tested many solutions and check generated sql statement to find out a very unique way without any performance overhead:
// This the way of getting one entity from oracle 12.1 without throwing Oracle exception => ORA-00918: column ambiguously defined without any extra overhead
var entities = await dbSet.Where(x => x.Id == id).Take(1).ToListAsync();
var entity = entities.FirstOrDefault();
Another Sample:
var entities = await dbSet.OrderByDescending(x => x.Id).Take(1).ToListAsync();
var entity = entities.FirstOrDefault();
At the end of your IQueryable Linq add Take(1) and get all with .ToList() or .ToListAsync() to execute the statement and fetch a list with one record. Then use Enumerable Single Entity Selector to change the list to an entity.
That’s all.
Disclaimer: these requirements are not set by me, unless this is an impossible task I cannot convince my boss otherwise.
Let's say we have two entities: Item and ItemTranslation.
public class Item
{
public int Id { get; set; }
public string Description { get; set; }
public virtual ICollection<Item> Children { get; set; }
public virtual Item Parent { get; set; }
public virtual ICollection<ItemTranslation> Translations { get; set; }
}
public class ItemTranslation
{
public int Id { get; set; }
public string CultureId { get; set; }
public string Description { get; set; }
public virtual Item Item { get; set; }
}
The requirement is that Item.Description should be filled in based on a language selected by default, but also allowing it to be specified based on what the user wants. The Item.Description column doesn't actually exist in the database.
In SQL this would be easy: all you have to do is query both tables like so
SELECT [Item].[Id], [ItemTranslation].[Description], [Item].[ParentId]
FROM [Item]
LEFT JOIN [ItemTranslation] ON [Item].[Id] = [ItemTranslation].[ItemId]
WHERE [CultureId] = {cultureId}
Or use an OUTER APPLY depending on your implementation. I have added this query to the .FromSql() function built in Entity Framework.
Put this all together in an OData API and this all works fine for one Item. However as soon as you start using $expand (which behind the scenes is a sort of .Include()) it no longer works. The query being sent to the database for the related entities no longer holds the SQL which I specified in .FromSql(). Only the first query does. On top of this when you would query an Item from a different controller e.g. ItemTranslation this would also no longer work since .FromSql() is only applied in the other controller.
I could write a query interceptor which simply replaces the generated SQL by Entity Framework and replaces FROM [Item] with FROM [Item] LEFT JOIN [ItemTranslation] ON [Item].[Id] = [ItemTranslation].[ItemId] WHERE [CultureId] = {cultureId} but I wonder if there is a better implementation than that. Perhaps even a redesign in models. I'm open to suggestions.
FromSql has some limitations. I suspect this is the reason why Include won't work.
But once you use EF, why are you messing with SQL? What difficulties does that query have which prevents you from doing it in LINQ? Left join maybe?
from item in ctx.Items
from itemTranslation in ctx.ItemTranslations.Where(it => it.Item.Id == item.Id).DefaultIfEmpty()
where itemTranslation.CultureId == cultureId
select new { item.Id, itemTranslation.Description, ParentId = item.Parent.Id };
Update
Going over the issue again, I see a further problem. Include will only work on an IQueryable<T> where T is an entity whose navigation properties are mapped properly. Now, from this perspective, it doesn't matter if you use FromSql or LINQ if it produces an IQueryable of some projection instead of an entity, Include won't work for obvious reasons.
To be able to include ItemTranslation entities, your action method should look something like this:
[Queryable]
public IQueryable<Item> GetItems()
{
return db.Items;
}
So the framework can perform $expand on the IQueryable<Item> you return. However, this will include all item translations, not just the ones with the desired culture. If I get it correctly, this is your core issue.
It's obvious as well that you cannot apply this culture filter to an IQueryable<Item>. But you shouldn't do that as this is achieved by $filter in OData:
GET https://.../Items/$expand=Translations&$filter=Translations/CultureId eq culture
I have a search model class that searches different entity sets with the entity itself implementing a IAssignable interface. The code looks like this.
public void Search()
{
List<T> lessons = new List<T>();
List<T> courses = new List<T>();
if (ShowLessons)
lessons = db.Set<Lesson>()
.Where(IAssignableExtensions.SearchPredicate(q))
.Select(LessonMapping).ToList();
if (ShowCourses)
courses = db.Set<Course>()
.Where(IAssignableExtensions.SearchPredicate(q))
.Select(CourseMapping).ToList();
Results = lessons.Union(courses).ToList<T>();
}
The static extension is irrelevant, it just searched based on the query. I would prefer to bust this into it's own rather than static extension but eh. Now this works as expected. I am pulling to memory two datasets, lessons and courses, I am unioning them into a IEnumerable of a generic type based on teh Course Mapping or Lesson Mapping Expressions.
public Expression<Func<IAssignable, T>> LessonMapping { get; set; }
public Expression<Func<IAssignable, T>> CourseMapping { get; set; }
The problem is when I want to do any type of paging. As you can see the lessons and courses are searched, brought into memory and then unioned and returned. If I do any paging using an IPagedList for example, it is bringing back ALL lessons and courses then it is only using a subset of the total data in the list for the pages.
If Entity Framework supported interfaces I would just do a cast on the interface and union right at the db call. I haven't changed this code yet but I feel I might have to create a custom stored procedure or use the Query call on the datacontext, but if I use a stored procedure I have to make sure to update it on any changes to the domain, and if I use the Query I have to re-jig the selects, interfaces and still have to worry about inline sql...
Anyone have any ideas?
UPDATE
The solution that I ended up using after thinking about Erik's solution was to just use a projected object that implemented IAssignable.
public class SomeProjection : IAssignable
{
public int ID { get; set; }
public string Name { get; set; }
public string Description {get;set;}
public string Privacy {get;set;}
}
And then used it within the union call queryable
Results = db.Set<Lesson>().Select(p => new SomeProjection() { Privacy = p.Privacy, ID = p.ID, Name = p.Name, Description = p.Description })
.Union(db.Set<Course>().Select(p => new SomeProjection() { Privacy = p.Privacy, ID = p.ID, Name = p.Name, Description = p.Description }))
.Where(IAssignableExtensions.SearchPredicate(q))
.Select(Mapping).ToList<T>();
If Entity Framework supported interfaces I would just do a cast on the interface and union right at the db call.
It has nothing to do with what Entity Framework supports. If you create an interface, it is independent of the SQL technology in the back end and you want EF to somehow magically select properties based on an interface with no mappings or configuration? Not going to happen.
Instead you could simply use inheritance if there are some properties that are the same between objects, then you don't even need to union them, unless you are where-ing on properties that don't exist between both.
Okay, I've seen some similar questions to this, but the answers either confused me or seemed completely over-engineered, so I'd like to ask my own question.
I have a class called Tree, which has an object property from the class Plot, which has an object property from the class Year, which has an object property from the class Series, which has a string property called Id. This is summarized below.
public class Tree {
public virtual Plot Plot { get; set; }
// other properties...
}
public class Plot {
public virtual Year Year { get; set; }
// other properties...
}
public class Year {
public virtual Series Series { get; set; }
// other properties...
}
public class Series {
public virtual string Id { get; set; }
// other properties...
}
Each of these classes corresponds to the table of a database, and properties correspond to foreign key fields (for example, the Trees table has a field called PlotKey, which refers to a record in the Plots table). All I want to do is load all trees from the database whose corresponding Series have the Id "Adrian_2012" or "IPED Sample". I thought this would be a pretty easy taking using the following code:
IList<Tree> trees = session.CreateCriteria<Tree>()
.Add(Expression.Or(
Expression.Eq("Plot.Year.Series.Id", "Adrian_2012")
Expression.Eq("Plot.Year.Series.Id", "IPED Sample")
))
.List<Tree>();
But this is throwing: "NHibernate.Exceptions.GenericADOException : could not execute query". I have tried using Expression.Disjunction, I have tried using Aliases, Restrictions, and SimpleExpressions, and I know that nothing stupid like unmapped properties or misspelled criteria is occurring. The only other thing I've seen that might help is the ISession.QueryOver<>() function, but I get very confused by lambda expressions. Does anyone have a solution for me that would use just a simple CreateCriteria<> statement like that above?
Thanks in advance!
One not nice side of the Criteria queries is, that we have to define associations chain explicitly. I.e. we have to introduce JOIN:
15.4. Associations (cite:)
You may easily specify constraints upon related entities by navigating associations using CreateCriteria().
So to have a JOIN we need syntax like this
var trees = session
.CreateCriteria<Tree>()
.CreateCriteria("Plot", "p")
.CreateCriteria("Year", "y")
.CreateCriteria("Series", "s")
.Add(Expression.Or(
Expression.Eq("s.Id", "Adrian_2012")
Expression.Eq("s.Id", "IPED Sample")
))
.List<Tree>();
Also, check this:
NHibernate - CreateCriteria vs CreateAlias