Ordering Included Entity - entity-framework

I am using entity framework v2.2.3. I am trying to order a sub-entity by using the following code but it did not work.
var result= _databaseContext.Movie.AsNoTracking().Include(p => p.Cast.OrderByDescending(c => c.Birthday)).ToList();
Error:
The Include property lambda expression 'p => {from Cast c in p.Casts orderby [c].Birthday desc select [c]}' is invalid. The expression should represent a property access: 't => t.MyProperty'. To target navigations declared on derived types, specify an explicitly typed lambda parameter of the target type, E.g. '(Derived d) => d.MyProperty'. For more information on including related data, see http://go.microsoft.com/fwlink/?LinkID=746393.
Entities:
public class Movie
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public List<Cast> Casts { get; set; }
}
public class Cast
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public DateTime Birthday { get; set; }
}
Do you have any idea?

There is no way to sort eager-loaded (.Include-queried) child collections as we have seen here and here.
You have to first load Movies and then sort their Casts-collections. Try this:
var result= _databaseContext.Movie.AsNoTracking().Include(p => p.Casts).ToList();
results.ForEach(x => x.Casts = x.Casts.OrderBy(y => y.BirthDay).ToList());

Related

one-to-many relationship foreign key count

public class User
{
[Key]
public int id { get; set; } //PK
public string emailAddress { get; set; }
public List<Task> tasks { get; set; }
}
public class Task
{
[Key]
public int id { get; set; } //PK
public string name { get; set; }
//Navigation Properties
public User user{ get; set; }
public int userId { get; set; }
}
I've got two models above configured following the MSDN tutorial. So how can I properly get the number of tasks associated with a user?
I tried context.users.Where(u => u.emailAddress == email).FirstOrDefaultAsync().tasks.count; but it gives me a null pointer reference on the tasks object.
Then I tried context.tasks.Where(o=>o.user.emailAddress==email).Count() gives me correct number so it works
so I am wondering why the List is a null reference instead of a list with some elements in? thanks for the advice
Try the following query:
var cnt = context.users
.Where(u => u.emailAddress == email)
.Select(u => u.tasks.Count())
.FirstOrDefault();
You have to use LINQ extension Count() instead of List.Count
I think you are using entity framework with Eager loading (description). In that case you should call explicitly Include() method to load all user tasks. Example:
await (context.users.Where(u => u.emailAddress == email).Include(u => u.Tasks).FirstOrDefaultAsync()).Tasks.Count();
UPD: Not for the Production

How to using AutoMapper and Entity Framework to Pass a Dynamic Parameter To Select A Child Object And Map

I've a requirement to map Company to CompanyDTO based on the user domain. I need to pass the Domain ID to the the Mapper and select CompanyDomain object
public class Company
{
public int CompanyID { get; set;}
public int Name { get; set;}
public List<CompanyDomain> Domains { get; set; }
}
public class CompanyDomain
{
public int DomainID { get; set; }
public string Analyst { get; set; }
}
public class CompanyDTO
{
public int CompanyID { get; set; }
public string Name { get; set; }
public string Analyst { get; set; }
}
You can do this by using the mapping options. For example, set up your map like this:
cfg.CreateMap<Company, CompanyDTO>()
.ForMember(
d => d.Analyst,
opts => opts.MapFrom((s, d, _, ctx) => //Use the 4 parameter version
s.Domains.Single(d => d.DomainID == (int)ctx.Items["DomainID"]).Analyst));
It looks a little more complicated than it really is, but it's just telling AutoMapper to search the company domains using a parameter that was passed in. You would then use it like this:
var result = mapper.Map<CompanyDTO>(company, opts => opts.Items["DomainID"] = 2);

Entity Framework core 2.0 HasColumnType throw run time exception

I have a custom enum type EmployementState (complex type in EF 6 term, I think)
in OnModelCreating, the following code throw an run time exception.
modelBuilder.Entity<Employee>().Property(e => e.EmployementState.Value).HasColumnType("int");
The exception show below:
Message=The expression 'e => e.EmployementState.Value' is not a valid property expression. The expression should represent a property access: 't => t.MyProperty'.
cannot figure out how to get the syntax right or is there are something else I was missing?
Thank you for your help.
Assuming you have the following model for your EmployementState object that will hold the different states for your employee:
public class EmployementState
{
public int Id { get; set; }
public string Name { get; set; }
}
You can then add a reference like:
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
// All your user properties here
public int EmployementStateId { get; set; }
public virtual EmployementState EmployementState { get; set; }
}
I recommend this because is the best approach when you are working with states describing your objects.
Of course being two separate models they are configurable so configurations like this one below are easy to implement.
modelBuilder.Entity<Employee>().Property(e => e.EmployementStateId)
.HasColumnName("employement_state_ID");

EF7 Core Many to Many Reference object not populated

I am having difficulty getting EF7 to populate the objects referenced in a many to many join. I have followed the docs at https://docs.efproject.net/en/latest/modeling/relationships.html, but the object is still null. From what I can tell you don't have to do anything specific to get EF to populate them. I copied the sample code from the docs page as follows:
public class MyContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
public MyContext(DbContextOptions<MyContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PostTag>()
.HasKey(t => new { t.PostId, t.TagId });
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId);
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId);
}
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public string Title { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
I had to add a constructor to get it to run. I also added a Title field to the Tag class so it has more than just a key. Once I populated some data in the tables, I run the following code to retrieve from the database:
var results = _context.Posts.Include(s => s.PostTags).ToList();
When I examine the results in the debugger, the Tag objects are null even though the keys to obtain them are present. Notice that the Post objects are populated. It is always the second column of the two column key that is not joined:
This is the SQL generated by EF7:
SELECT [s].[PostId], [s].[Content], [s].[Title]
FROM [Posts] AS [s]
ORDER BY [s].[PostId]
SELECT [p].[PostId], [p].[TagId]
FROM [PostTag] AS [p]
WHERE EXISTS (
SELECT 1
FROM [Posts] AS [s]
WHERE [p].[PostId] = [s].[PostId])
ORDER BY [p].[PostId]
It doesn't appear to be fetching the Tag object at all. What am I missing here?
For completeness, I have included the sample data:
Thanks to #SOfanatic for pointing me in the right direction. I am not sure why EF doesn't automatically load the second reference class, but it doesn't. The following code will retrieve the Tag object (as well as the Post object even though we don't explicitly load it).
var results = _context.Posts.Include(s => s.PostTags).ThenInclude(t => t.Tag).ToList();
You are doing a many-to-many with what is known as Payload class. The PostTag class is technically not needed for EF to create a many-to-many relationship.
You are going to have to do something like this:
var results = _context.Posts.Include(s => s.PostTags.Select(pt => pt.Tag).ToList();
Right now your linq is loading the related entities, which are just the id's so it's of no use.
If your PostTags class is not going to have any other fields/properties you should look into creating a many-to-many without the payload

EF Code first parent child mapping

This may be a duplicate qn, but i couldnt get a proper answer to this scenario. I have the following table structure:
public class File
{
public int FileId { get; set; } //PK
public int VersionID { get; set; }
public virtual ICollection<FileLocal> FileLLocalCollection { get; set; }
}
public class FileLocal
{
public int FileId { get; set; } //PK, FK
public int LangID { get; set; } //PK,FK
public string FileName { get; set; }
}
I have not included the third table here(Its basically LangID (PK) & LangCode )
How do i specify this mapping in fluent Api so that i can load "FileLLocalCollection" with every File objects?
The first part of your mapping can be done this way:
modelBuilder.Entity<File>()
.HasMany(f => f.FileLocalCollection)
.WithRequired()
.HasForeignKey(fl => fl.FileId);
modelBuilder.Entity<FileLocal>()
.HasKey(fl => new {fl.FileId, fl.LangId});
And the second part depends on the way how your Lang is defined. For example if you add navigation property from FileLocal to Lang you can map it this way:
modelBuilder.Entity<FileLocal>()
.HasRequired(fl => fl.Lang)
.WithMany()
.HasForeignKey(fl => fl.LangId);