I get an exception with DetachedLazyLoadingWarning:
Error generated for warning 'Microsoft.EntityFrameworkCore.Infrastructure.DetachedLazyLoadingWarning: An attempt was made to lazy-load navigation property 'Product' on detached entity of type 'DeliveryProxy'. Lazy-loading is not supported for detached entities or entities that are loaded with 'AsNoTracking()'.'. This exception can be suppressed or logged by passing event ID 'CoreEventId.DetachedLazyLoadingWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'.
while trying to query SQL database with Entity Framework Code 2.1
This is my query:
var orders =
_context
.Set<Order>()
.Where(v => v.CompanyId == companyId)
.Include(v => v.Details)
.ThenInclude(d => d.Delivery)
.ThenInclude(v => v.Product)
.OrderByDescending(v=> v.Details.FirstOrDefault().Delivery.Product.ProductId)
.ThenByDescending(v=> v.Details.FirstOrDefault().Delivery.Value)
.ThenByDescending(v => v.CreatedAt)
.Page(request.Page, request.RowsPerPage);
Here are entities and relationships:
public class Order : IEntity<int>
{
public int CompanyId { get; set; }
public virtual ICollection<OrderDetails> Details { get; set; }
[Required]
public DateTimeOffset CreatedAt { get; set; }
[Key]
public int Id { get; set; }
}
public class OrderDetails : IEntity<int>
{
public int OrderId { get; set; }
public int DeliveryId { get; set; }
[ForeignKey(nameof(OrderId))]
public virtual Order Order { get; set; }
[ForeignKey(nameof(DeliveryId))]
public virtual Delivery Delivery { get; set; }
[Key]
public int Id { get; set; }
}
public class Delivery : IEntity<int>
{
[Required]
public int ProductId { get; set; }
public int Value { get; set; }
[ForeignKey(nameof(ProductId))]
public virtual Product Product { get; set; }
[Key]
public int Id { get; set; }
}
[Table("Products")]
public class Product : IEntity<int>
{
[Required]
public byte ProductCategoryId { get; set; }
public virtual ICollection<Delivery> Deliveries { get; set; }
[Key]
public int Id { get; set; }
}
Looks like Details.FirstOrDefault() detaches the entity Delivery. The same solution worked with Entity Framework 6. How can I improve my query to get the date from database using only one query (suppressing the warining didn't help)?
You should also be seeing a lot of Client evaluation logging
warnings. And currently client evaluation doesn't play well with explicit/lazy loading.
The cause of the client evaluation in this case is the v.Details.FirstOrDefault() expression inside the ordering methods. And the challenge with the current stage of EF Core is to find the supported translatable equivalent LINQ construct.
In this particular scenario the solution (workaround) is to use intermediate SelectMany projection with Take(1). Replace the part starting from .OrderByDescending(..) up to Page(...) with the following:
.SelectMany(
o => o.Details.Select(d => d.Delivery).Take(1).DefaultIfEmpty(),
(o, d) => new { Order = o, Delivery = d })
.OrderByDescending(v => v.Delivery.ProductId)
.ThenByDescending(v => v.Delivery.Value)
.ThenByDescending(v => v.Order.CreatedAt)
.Select(v => v.Order) // restore the original projection
Related
I have stores with products, I want to get all stores even if the store doesn't have active products
here are the entity classes
class Store
{
[Key]
public Guid UId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime Created { get; set; }
public DateTime Updated { get; set; }
public bool Inactive { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
class Product
{
[Key]
public Guid Id { get; set; }
public Guid StoreUid { get; set; }
public virtual Store Store{ get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime Created { get; set; }
public DateTime Updated { get; set; }
public bool Inactive { get; set; }
}
the statement I'm using now is:
using (var context = new DbContext())
{
context.Stores.
.AsNoTracking()
.Where(store => !store.Inactive)
.Include(x => x.Products)
.ToList();
}
I tired
using (var context = new DbContext())
{
context.Stores.
.AsNoTracking()
.Where(store => !store.Inactive && store.Products.Any(p=>!p.Inactive))
.Include(x => x.Products)
.ToList();
}
but I didn't get the store without any linked product to it.
the think is that I want to be able to get the Store.Products as Null or empty collection
I want to avoid as much for each statement and try to do it SQLish.. because in SQL is much easier to do this but I need the Include for nesting
EF Core support filtered in include.
To retrieve all active stores and include active products, you can :
context.Stores.AsNoTracking()
.Where(store => !store.Inactive)
.Include(x => x.Products.Where(p=>!p.Inactive))
.ToList();
Also, EF Core support Global Query Filters. Very useful to manage soft delete.
I'm trying to make an insert in a SQL database using Entity Framework 6 and I'm stuck on this issue that I cannot solve.
The error that I keep getting is :
UpdateException: Entities in 'Connect.CompanyFinancialDetails' participate in the 'Company_CompanyFinancialDetails' relationship. 0 related 'Company_CompanyFinancialDetails_Source' were found. 1 'Company_CompanyFinancialDetails_Source' is expected
I have these 2 entities:
public class Company
{
public long CUI { get; set; }
public string UserName { get; set; }
public string CompanyName { get; set; }
public string Symbol { get; set; }
public int? SharesCount { get; set; }
public decimal? SharePrice { get; set; }
public virtual Account Account { get; set; }
public virtual CompanyFinancialDetails CompanyFinancialDetails { get; set; }
}
public class CompanyFinancialDetails
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
// other properties
public decimal? NumberOfEmployees { get; set; }
public virtual Company Company { get; set; }
}
This is the Fluent API configuration:
public DbSet<Account> SignUpModels { get; set; }
public DbSet<Company> Companies { get; set; }
public DbSet<CompanyFinancialDetails> CompanyFinancialDetails { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Account>()
.HasKey(k => k.Id)
.HasOptional(s => s.Company)
.WithRequired(d => d.Account);
modelBuilder.Entity<Company>()
.HasKey(k => k.CUI)
.HasOptional(s => s.CompanyFinancialDetails)
.WithRequired(d => d.Company);
}
The relationship that I want to have is 1-many (one Company has many CompanyFinancialDetails).
This is the code where I add the objects to the database:
Company co = Context.Find(username);
foreach (CompanyFinancialDetails s in c)
{
s.Company = co;
}
a.CompanyFinancialDetails.AddRange(c);
a.SaveChanges();
I get a list of CompanyFinancialDetails and I add them using the AddRange method. I had this issue before and what I did was to add the virtual property object to the object that I wanted to insert in the database and it worked. This is what I tried to do here: the Find() method gets the company object that is related to the CompanyFinancialDetails and for each CompanyFinancialDetails object an Company virtual property is adding the related company object.
Well, it didn't work, when the SaveChanges() method is called, I get that error. Any help would be appreciated.
I am using Entity Framework Core 2.0.1 and I have the following models
public class Article
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
[Required]
public string Title { get; set; }
public string Slug { get; set; }
public int Approved { get; set; }
public DateTime ArticleDate { get; set; }
// ... some other fields
public virtual ICollection<ArticleCategoryRelation> ArticleCategoryRelations { get; set; }
}
public class ArticleCategory
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
//... soem other fields
[ForeignKey("ArticleCategoryParent")]
public int? ArticleCategoryParentID { get; set; }
public virtual ArticleCategory ArticleCategoryParent { get; set; }
public virtual ICollection<ArticleCategory> SubCategories { get; set; }
public virtual ICollection<ArticleCategoryRelation> ArticleCategoryRelations { get; set; }
}
public class ArticleCategoryRelation
{
[Column(Order = 0)]
public int ArticleId { get; set; }
public Article Article { get; set; }
[Column(Order = 1)]
public int ArticleCategoryId { get; set; }
public ArticleCategory ArticleCategory {get; set;}
}
Every article belongs to one or more categories. Categories might have parent category.
I want to get from database last two articles (where Approved = 1) with related category details, for each category that belongs to a parent category which id is given as input.
I have tried but with no success. I can't filter results of an .Include() entity. Is it possible... or I don't know how to do it?
All my data are accessed through entity framework with appContext (the context used to get entities from database). Can I achieve what I want through entity framework core (lambda expression is preferred over Linq if possible), or should I use ADO.NET library (which I know how to execute custom queries).
P.S. I want to get data only to show in the view... no edit is needed.
You don't actually need to include here at all, as far as I can tell. Whenever you use data from a nav property, EF will go get the data from that table, as best it can filter it.
var CategoriesUnderParent = AppContext.ArticleCategories
.Where(c => c.ArticleCategoryParent == {parent});
foreach(var category in CategoriesUnderParent)
{
var ArticlesAllowed = category.ArticleCategoryRelations
.Where(acr => acr.Article.Approved == 1).Select(a => a.Article);
var ArticlesPicked = ArticlesAllowed
.OrderByDescending(ar => ar.ArticleDate)
.Take(2);
// Do something with your data
}
I'm using EntityFramework for my Microsoft Sql Data Base.
First entity is Product:
public class Product
{
public Product()
{
ProductStories = new HashSet<ProductStory>();
}
public int ProductId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool Deleted { get; set; }
public HashSet<ProductStory> ProductStories { get; set; }
}
And another entity is ProductStory, which stores story about income or outcome of Products.
public class ProductStory
{
public int ProductStoryId { get; set; }
public virtual Product.Product Product { get; set; }
public int Count { get; set; }
public DateTime DateTime { get; set; }
}
So one Product could be in mane ProductStories, or in none.
I will not show all code(too big), so when I firstly create a single Product instance and save it in DB. Then I create a single ProductStory and reference to property Product to that instance of Product.
Then I save this ProductStory, there becomes 2 instances of ProductStory.
As I read, and I made this as virtual property:
public virtual Product.Product Product { get; set; }
How this problem could be solved?
I'm using EntityTypeConfiguration for tables configuration.
public class ProductMap : EntityTypeConfiguration<Product>
{
public ProductMap()
{
ToTable("Products").HasKey(x => x.ProductId);
Property(x => x.ProductId).IsRequired();
Property(x => x.Name).IsRequired().HasMaxLength(255).HasColumnName("Name");
//.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("IX_Name") { IsUnique = true }));
Property(x => x.Description).IsOptional().HasColumnName("Description");
Property(x => x.Deleted).HasColumnName("Deleted");
}
}
And for ProductStory:
class ProductStoryMap: EntityTypeConfiguration<ProductStory>
{
public ProductStoryMap()
{
ToTable("ProductStories").HasKey(ps => ps.ProductStoryId);
Property(ps => ps.ProductStoryId).IsRequired();
//Property(ps => ps.ProductId).IsRequired().HasColumnName("ProductId");
Property(ps => ps.Count).HasColumnName("Count");
Property(ps => ps.DateTime).HasColumnName("DateTime");
}
}
You have some errors in your code:
//Change this:
public HashSet<ProductStory> ProductStories { get; set; }
//For this (virtual is needed here, also use ICollection rather than any specific implementation)
public virtual ICollection<ProductStory> ProductStories { get; set; }
//Change this:
public virtual Product.Product Product { get; set; }
//For this (virtual makes no sense here)
public Product.Product Product { get; set; }
And lastly, ProductStory needs a way to keep the reference to its parent Product. This is what creates the Foreign Key relationship in your database and allows Entity Framework to link the tables. So add this to ProductStory:
public int ProductId { get; set; }
If you are still getting a duplicated object (which may happen), ensure you are setting the ProductId to the ProductStory you are saving.
The solution was about Entity Framework "bug/feature".
As I add new ProductStory into DataBase, it attaches the whole graph(including all other entities references and recreates them).
So before commiting new ProductStory, I have to set to null all it's navigation properties to avoid recreating.
I have two entities
public class ProductEntity
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<PriceScheduleEntity> PriceSchedules { get; set; }
}
public class PriceScheduleEntity
{
public virtual Guid Id { get; set; }
public virtual DateTime Date{get;set;}
public virtual ProductEntity Product { get; set; }
}
One to Many mapping have been done.
One product may have many priceschedules
When i do the query
IList<ProductEntity> entityList = NHSession.QueryOver<ProductEntity>()
.Where(x => x.Name.IsLike("%" + matchString + "%"))
.OrderBy(x => x.Name).Asc.List();
It gives me the priceschedules as they were added.
I want them sorted through the effective date.
Please help me with the query.
in mapping (e.g. FLuentNHibernate mapping)
HasMany(x => x.PriceSchedules).OrderBy(s => s.Date)
you should do an ordered insert in code so it won't break this sorted contract after adding an item in code.