EF Core equivalent of ObjectContext.MetadataWorkspace - entity-framework

We previously (i.e., in EF 6) used the following code to obtain all enum properties which are used in any entity or complex type in our EF model:
var metadataWorkspace = ((IObjectContextAdapter) context).ObjectContext.MetadataWorkspace;
var enumTypes = metadataWorkspace
.GetItems<StructuralType>(DataSpace.OSpace)
.SelectMany(t => t.Members)
.OfType<EdmProperty>()
.Where(m => m.EnumType != null)
.Select(m => m.EnumType)
.Distinct()
.ToList();
What is the EF Core equivalent of this? How to access "all types" in the model?
Is the following correct and complete (i.e., not missing owned types or anything like that).
var enumTypes = context.Model.GetEntityTypes()
.SelectMany(et => et.GetProperties())
.Where(p => p.ClrType.IsEnum)
.Distinct()
.ToList();

Related

Entity Framework Core throws multiple columns are specified in an aggregated expression containing an outer reference

We are upgrading our .net framework into.net core and the following query was working:
var data = dbContext.CommitteeHouses
.Where(x => x.Committee.SeasonId == 1)
.Select(x => new
{
ApplicationsCountInClass = x.Committee.ApplicationForms
.GroupBy(a => a.ClassId)
.Where(g => x.ClassesLimits.Any(c => c.ClassId == g.Key))
.Select(g => new
{
ClassId = g.Key,
ApplicationCount = g.Count(ca => !ca.Suspended && ca.HouseId == x.HouseId)
}),
x.CommitteeId,
x.ViceSupervisorId
}).ToList();
Now using EntityFrameworkCore it throws the following exception:
Microsoft.Data.SqlClient.SqlException: 'Multiple columns are specified in an aggregated expression containing an outer reference. If an expression being aggregated contains an outer reference, then that outer reference must be the only column referenced in the expression.'
Why is this exception thrown and how can I solve it?

Is there an alternate for an EF Core where clause using List.Contains(object, IEqualityComparer)?

The following syntax will indeed not be translated by EF Core.
var books = await context.Books
.Where(c => detachedBooks.Contains(c, new BookEqualityComparer()))
.AsNoTrackingWithIdentityResolution()
.ToListAsync();
I wanted to use a separate BookEqualityComparer here in order not to inherit from IEquatable in Entity Book so as not to interfere with the regular working of EF Core.
detachedBooks is a list of detached Book entities, i.e. the Id are not available.
I doubt anything that complex would be ever supported in EF. Select your relevant details from your detached entities or DTOs and use those. For instance something like this would generally match rows based on their PKs or elements of a composite key:
var bookIds = detachedBooks.Select(x => x.BookId).ToList();
var books = await context.Books
.Where(c => bookIds.Contains(c.BookId))
.AsNoTrackingWithIdentityResolution()
.ToListAsync();

How to convert IQueryable complex type to generic list in entity framework

IQueryable<SystemGroup> systemGroupQuery;
systemGroupQuery = dbContext.SystemGroups.Select(x => new SystemGroup()
{
Id = x.Id,
Name = x.Name,
SmsAccountId = x.SmsAccountId,
SmsAccount = dbContext.SmsAccounts.Where(g => g.Id
== x.SmsAccountId).SingleOrDefault()
});
var systemGroups = systemGroupQuery.ToList();
While converting to list i am getting the error "The entity or complex type 'Models.Context.SystemGroup' cannot be constructed in a LINQ to Entities query."
Add .ToList() before .Select
or
use anonymous object and map it after .ToList()
Linq to entities doesnt allow constructing complex typed objects in the fly

Include Collection of Collection in Entity Framework

I'm using Entity Framework 4.3
I have 3 tables, Lender, Product and ProductDetail
A Lender has multiple Products and a Product has Multiple ProductDetail rows
Here's a chunk of code I'm trying to use:
Lender SingleOrDefault(Expression<Func<Lender, bool>> predicate)
{
using (var uow = new UnitOfWork(Connections.LoanComparision))
{
var r = new Repository<Lender>(uow.Context);
return r.Find(predicate)
.Where(x =>
x.IsPublished &&
x.Products.Any(y => y.IsPublished))
.Include(x => x.Products.SelectMany(y => y.ProductDetails))
.SingleOrDefault();
}
}
The issue is with the Include - I'm trying to get the Lender => Products => ProductDetails. I can't see the table in intellisense even though I know it is linked correctly. I thought the SelectMany might work but it gives me a runtime error.
Any ideas as to how this can be achieved?
You do selectmany however it is for flatten list of list to list.
To include relevant list you should do select as noted in comments noted by Developer user
Include(x => x.Products.Select(y => y.ProductDetails))

Where Clause With Null Object Using Entity Framework v5.0RC

I was trying to do the following
public IList<Category> GetMainCategories()
{
return _context.Category
.Where(x => x.ParentCategory == null)
.OrderBy(x => x.SortOrder)
.ToList();
}
However, no matter what I try this returns no results even though I can see in the collection that ALL ParentCategory's are null? I have read EF has problems with nulls like this and have also tried
.Where(x => x.ParentCategory.Equals(null))
And
.Where(x => Equals(x.ParentCategory.Id, null))
.Where(x => Equals(x.ParentCategory, null))
But still same result? I'm lost? How the heck do I check if an object it null? When I inspect it in VS2010 is clearly states its null?
Update
I can get it working doing this, BUT its insanely inefficient!!! MUST be able to do this in the query or I'm rather shocked by EF! Any help greatly appreciated?
public IList<Category> GetMainCategories()
{
var cats = _context.Category
.OrderBy(x => x.SortOrder)
.ToList()
.Where(cat => cat.ParentCategory == null)
.ToList();
return cats;
}
If the query ...
_context.Category
.Where(x => x.ParentCategory == null)
.OrderBy(x => x.SortOrder)
.ToList()
... returns an empty collection it means that all categories in the database have a ParentCategory or that the categories table is empty. That's all.
The fact that in the result collection of this query ...
_context.Category
.OrderBy(x => x.SortOrder)
.ToList()
... every category has no ParentCategory doesn't prove that every category has no ParentCategory in the database.
Do you know the basics of loading or not-loading related entities with EF? I suggest to read this introduction for EF >= 4.1/DbContext: http://blogs.msdn.com/b/adonet/archive/2011/01/31/using-dbcontext-in-ef-feature-ctp5-part-6-loading-related-entities.aspx
In your results it is not guaranteed that the references are actually null in the database even if you see null in your returned results.
Use this query to force EF to load the reference data:
public IList<Category> GetMainCategories()
{
return _context.Category
.Include(x => x.ParentCategory) // for the new EF versions
.Include("ParentCategory") // for older EF versions
// .Where(x => x.ParentCategory == null)
.OrderBy(x => x.SortOrder)
.ToList();
}
Note that the Include() method does not impact how the Where works, it just makes sure that when you view the ParentCategory property in debugger window (or access from code) you will have the data there.
It might be outdated but I guess this is the answer you were looking for:
public abstract class YourContext : DbContext
{
public YourContext()
{
(this as IObjectContextAdapter).ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior = true;
}
}
This should solve your problems as Entity Framerwork will use 'C# like' null comparison.