In this query here, is there any way to reduce the
.Include( c => c.EducationCredential)
.ThenInclude(e => e.Concentration)
.Include( c => c.EducationCredential)
.ThenInclude(e => e.School)
.Include(c => c.EducationCredential)
.ThenInclude( e => e.SecondConcentration)
into something like
.Include(c => c.EducationCredential and c.Concentration and c. e.SecondConcentration)
Here is the full version:
var cred = await _context.Credentials
.Where( c => c.CredentialId == credentialId)
.Include( c => c.EducationCredential)
.ThenInclude(e => e.Concentration)
.Include( c => c.EducationCredential)
.ThenInclude(e => e.School)
.Include(c => c.EducationCredential)
.ThenInclude( e => e.SecondConcentration)
.Include(c => c.LocationCredential)
.ThenInclude(lc => lc.Location)
.Include( c => c.LifeCredential)
.ThenInclude(c => c.Topic)
.Include(c => c.EmploymentCredential)
.ThenInclude(e => e.Company)
.FirstOrDefaultAsync();
return cred.Title;
This one is generating unnecessary joins like shown below in the sql query (notice e0, e1):
SELECT "c"."CredentialId", "c"."CredentialType", "c"."SorarakUserId", "c"."Title", "e"."EducationCredentialId", "e"."ConcentrationId", "e"."CredentialId", "e"."DegreeType", "e"."GraduationYear", "e"."SchoolId", "e"."SecondConcentrationId", "t"."TopicId", "t"."Category", "t"."Description", "t"."IconUrl", "t"."QuestionId", "t"."Title", "t"."TotalFollowers", "t"."UrlSlug", "e0"."EducationCredentialId", "e0"."ConcentrationId", "e0"."CredentialId", "e0"."DegreeType", "e0"."GraduationYear", "e0"."SchoolId", "e0"."SecondConcentrationId", "t0"."TopicId", "t0"."Category", "t0"."Description", "t0"."IconUrl", "t0"."QuestionId", "t0"."Title", "t0"."TotalFollowers", "t0"."UrlSlug", "e1"."EducationCredentialId", "e1"."ConcentrationId", "e1"."CredentialId", "e1"."DegreeType", "e1"."GraduationYear", "e1"."SchoolId", "e1"."SecondConcentrationId", "t1"."TopicId", "t1"."Category", "t1"."Description", "t1"."IconUrl", "t1"."QuestionId", "t1"."Title", "t1"."TotalFollowers", "t1"."UrlSlug", "l"."LocationCredentialId", "l"."CredentialId", "l"."EndYear", "l"."IsCurrentlyLivingThere", "l"."LocationId", "l"."StartYear", "t2"."TopicId", "t2"."Category", "t2"."Description", "t2"."IconUrl", "t2"."QuestionId", "t2"."Title", "t2"."TotalFollowers", "t2"."UrlSlug", "l0"."LifeCredentialId", "l0"."CredentialId", "l0"."TopicId", "t3"."TopicId", "t3"."Category", "t3"."Description", "t3"."IconUrl", "t3"."QuestionId", "t3"."Title", "t3"."TotalFollowers", "t3"."UrlSlug", "e2"."EmploymentCredentialId", "e2"."CompanyId", "e2"."CredentialId", "e2"."EndYear", "e2"."IsCurrentlyWorkingThere", "e2"."PositionTitle", "e2"."StartYear", "t4"."TopicId", "t4"."Category", "t4"."Description", "t4"."IconUrl", "t4"."QuestionId", "t4"."Title", "t4"."TotalFollowers", "t4"."UrlSlug"
FROM "Credentials" AS "c"
LEFT JOIN "EducationCredentials" AS "e" ON "e"."CredentialId" = "c"."CredentialId"
LEFT JOIN "Topics" AS "t" ON "e"."ConcentrationId" = "t"."TopicId"
LEFT JOIN "EducationCredentials" AS "e0" ON "e0"."CredentialId" = "c"."CredentialId"
LEFT JOIN "Topics" AS "t0" ON "e0"."SecondConcentrationId" = "t0"."TopicId"
LEFT JOIN "EducationCredentials" AS "e1" ON "e1"."CredentialId" = "c"."CredentialId"
LEFT JOIN "Topics" AS "t1" ON "e1"."SchoolId" = "t1"."TopicId"
LEFT JOIN "LocationCredentials" AS "l" ON "l"."CredentialId" = "c"."CredentialId"
LEFT JOIN "Topics" AS "t2" ON "l"."LocationId" = "t2"."TopicId"
LEFT JOIN "LifeCredentials" AS "l0" ON "l0"."CredentialId" = "c"."CredentialId"
LEFT JOIN "Topics" AS "t3" ON "l0"."TopicId" = "t3"."TopicId"
LEFT JOIN "EmploymentCredentials" AS "e2" ON "e2"."CredentialId" = "c"."CredentialId"
LEFT JOIN "Topics" AS "t4" ON "e2"."CompanyId" = "t4"."TopicId"
WHERE "c"."CredentialId" = $1
LIMIT 1
What happens if you do this instead?
.Include( c => c.EducationCredential.Concentration)
.Include( c => c.EducationCredential.School)
.Include(c => c.EducationCredential.SecondConcentration)
This is an issue with Entity Framework Core and no work around for now. See https://github.com/aspnet/EntityFramework/issues/4900
Related
I would like to generate this SQL query in entity framework
SELECT FunctionalAssets.Name, FunctionalAssetStructurePath.Path
FROM FunctionalAssets
LEFT JOIN FunctionalAssetStructurePath ON FunctionalAssets.Id =
FunctionalAssetStructurePath.FunctionalAssetId AND
FunctionalAssetStructurePath.StructureConfigurationId = 'A8A41B14-0A35-45D3-2A2B-08D904A3CD0B'
ORDER BY FunctionalAssetStructurePath.Path, FunctionalAssets.Name
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
I try with this code (but I know that it won't work)
var result = context.FunctionalAssets
.Include(x => x.FunctionalAssetsStructurePaths.Any(y => y.StructureConfigurationId == configurationId))
.OrderBy(x => x.FunctionalAssetsStructurePaths.Select(y => y.Path))
.ThenBy(x => x.Name)
.Skip(0)
.Take(100)
.AsNoTracking()
.Select(x => x.Name)
.ToList();
Have you an idea how to do this ?
Thank you
I found a solution.
var result = context.FunctionalAssets
.GroupJoin(context.FunctionalAssetStructurePathModel.Where(y => y.StructureConfigurationId == 'A8A41B14-0A35-45D3-2A2B-08D904A3CD0B'),
fa => fa.Id,
fasp => fasp.FunctionalAssetId,
(fa, fasp) => new { fa, fasp })
.SelectMany(x => x.fasp.DefaultIfEmpty(), (x, p) => new { x.fa, p.Path })
.OrderBy(x => x.Path)
.Skip(0)
.Take(100)
.ToList();
And the generated SQL query is :
SELECT [f].[Id], [f].[Name], [t].[Path]
FROM [FunctionalAssets] AS [f]
LEFT JOIN (
SELECT [f0].[FunctionalAssetId], [f0].[Path]
FROM [FunctionalAssetStructurePath] AS [f0]
WHERE [f0].[StructureConfigurationId] = 'A8A41B14-0A35-45D3-2A2B-08D904A3CD0B'
) AS [t] ON [f].[Id] = [t].[FunctionalAssetId]
ORDER BY [t].[Path]
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
I have a problem: I have this table
ID
Title
GenreID
Genre
Duration
1
Movie1
1,2
Cartoon, Family
80
2
Movie2
3,4
Horror, Drama
76
3
Movie3
4
Drama
110
4
Movie4
1,2
Cartoon, Family
200
I need to filter by Genre, I make my query in this way, For example if I want all movies with Genre Cartoon (2), I make:
request.genre = 2
var query1 = from q in Movies
select new Response.MovieResponse
{
MovieId = q.MovieId,
Name = q.Title,
Genres = q.Genre,
GenreIds = q.GenreID
};
if (request != null)
{
if (!string.IsNullOrEmpty(request.Title))
query1 = query1.Where(co => co.Name.StartsWith(request.name));
if (!string.IsNullOrEmpty(request.genre))
if (int.Parse(request.genre) > 0)
{
query1.AsEnumerable().Where(ca =>
request.genre .Any(x => ca.GenreIds.Contains(x)));
}
}
List<Response.StoreResponse> stores = new List<Response.StoreResponse>();
stores = await query1.ToListAsync();
I expected 2 records inside but the filter on genre does not work. I always have back all movies. The filter by title run
I tried
if (!string.IsNullOrEmpty(request.category))
if (int.Parse(request.category) > 0)
{
string[] cat = { request.category };
var q1 = query1.Where(ca => ca.CategoriesIds.Contains(cat.ToString()));
l = q1.ToList();
}
but I have error:
The LINQ expression 'DbSet<Store>()
.Join(
inner: DbSet<Country>(),
outerKeySelector: s => s.CountryId,
innerKeySelector: c => (Nullable<int>)c.CountryId,
resultSelector: (s, c) => new TransparentIdentifier<Store, Country>(
Outer = s,
Inner = c
))
.Join(
inner: DbSet<City>(),
outerKeySelector: ti => ti.Outer.CityId,
innerKeySelector: c0 => (Nullable<long>)c0.CityId,
resultSelector: (ti, c0) => new TransparentIdentifier<TransparentIdentifier<Store, Country>, City>(
Outer = ti,
Inner = c0
))
.Where(ti0 => ti0.Outer.Outer.StatusId == (Nullable<int>)2)
.Where(ti0 => DbSet<Operator>()
.Where(o => EF.Property<Nullable<Guid>>(ti0.Outer.Outer, "StoreId") != null && object.Equals(
objA: (object)EF.Property<Nullable<Guid>>(ti0.Outer.Outer, "StoreId"),
objB: (object)EF.Property<Nullable<Guid>>(o, "StoreId")))
.Count() > 0)
.Where(ti0 => string.Join<long>(
separator: ",",
values: DbSet<StoresCategory>()
.Where(s0 => EF.Property<Nullable<Guid>>(ti0.Outer.Outer, "StoreId") != null && object.Equals(
objA: (object)EF.Property<Nullable<Guid>>(ti0.Outer.Outer, "StoreId"),
objB: (object)EF.Property<Nullable<Guid>>(s0, "StoreId")))
.Select(s0 => s0.CategoryId)
.ToList()).Contains(__ToString_0))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
This is my query
public async Task<IEnumerable<Menu>> GetMenuByRolesAsync(string[] roles)
{
var result= await _context.Menus//.Include(o => o.Parent)
.Include(m => m.Childrens)
.ThenInclude(m => m.Childrens)
.Include(m => m.Roles.Where(r => roles.Contains(r.Name))) --it is not filtering basd on roles
.Where(m => m.ParentId == null)
.ToListAsync();
}
It is generating below query
-- #__roles_0='System.String[]' (DbType = Object)
SELECT m.id, m.icon, m.name, m.parent_id, m.url, t.role_id, t.menu_id, t.id, t.concurrency_stamp, t.name, t.normalized_name
FROM security.menu AS m
LEFT JOIN (
SELECT r.role_id, r.menu_id, r0.id, r0.concurrency_stamp, r0.name, r0.normalized_name
FROM security.role_menu AS r
INNER JOIN security.role AS r0 ON r.role_id = r0.id
WHERE r0.name = ANY (#__roles_0) OR ((r0.name IS NULL) AND (array_position(#__roles_0, NULL) IS NOT NULL))
) AS t ON m.id = t.menu_id
WHERE (m.parent_id IS NULL)
ORDER BY m.id, t.role_id, t.menu_id, t.id
This is Many to many configuration
// many to many
builder.HasMany(r => r.Menus)
.WithMany(r => r.Roles)
.UsingEntity<RoleMenu>(
j => j
.HasOne(rm => rm.Menu)
.WithMany(m => m.RoleMenus)
.HasForeignKey(rm => rm.MenuId),
j => j
.HasOne(rm => rm.Role)
.WithMany(r => r.RoleMenus)
.HasForeignKey(rm => rm.RoleId),
j =>
{
j.ToTable("role_menu", schema: "security");
j.HasKey(rm => new { rm.RoleId, rm.MenuId });
});
i need to filter menus based on roles..But it is not filtering based on roles..Am getting all the roles..I checked generated query..Please let me know what is the issue..
You are mixing filtered include with entity filtering.
Filtered include
.Include(m => m.Roles.Where(r => roles.Contains(r.Name)))
just filters the items in the related collection (menu roles in this case).
In order to filter the entity set (menus in this case), you need to replace it with the usual Where oparator, which for the desired filtering will be
.Where(m => m.Roles.Any(r => roles.Contains(r.Name)))
If possible, please guide me how to convert my SQL command to lambda expression
select d.* from takcontractdet d where d.contractid=pubcontractid and d.personid in
(
select p.id from personel p where p.parentid=pubparentid)
)
Two query
var personelIds = Personels.Where(p => p.ParentId == pubparentid)
.Select(e => e.Id).ToList();
var result = Takcontractdets.Where(d => d.contractid == pubcontractid &&
personelIds.Contains(d.PersonId)).ToList();
One query
var result = Takcontractdets.Where(d => d.contractid == pubcontractid &&
Personels.Where(p => p.ParentId == pubparentid)
.Select(e => e.Id).ToList().Contains(d.PersonId))
.ToList();
I got a huge problem with the SQL generation in my REST-Service:
The following Code is generating 2 different SQL-Statements (PC Win8 vs Server 2008 R2):
private void GetData()
{
ctPostBox = new CTPostBox(GetDBConnection(DatabaseKind.dkGlobal));
var lQry = (from d in ctPostBox.CONTACTUSER.Include("CONTACT").Include("CONTACT.DBLINK").Include("CONTACT.CONTACTLASTUSED").Include("CONTACT.EMAILACCOUNT")
where ((d.CONTACT.ID_DBLINK == 0 || d.CONTACT.ID_DBLINK == null) || (d.CONTACT.DBLINK.MANDNR == UserConfig.mandNr))
select new
{
READDATE = d.READDATE,
ID = d.CONTACT.ID,
DBID = d.CONTACT.DBID,
DATEINSERT = d.CONTACT.DATEINSERT,
FROMUSER = d.CONTACT.FROMUSER,
FILENAME = d.CONTACT.FILENAME,
KIND = d.CONTACT.KIND,
MSGID = d.CONTACT.MSGID,
ID_DBLINK = d.CONTACT.ID_DBLINK,
DBID_DBLINK = d.CONTACT.DBID_DBLINK,
SUBJECT = d.CONTACT.SUBJECT,
STATE = d.CONTACT.STATE,
DATEINCOME = d.CONTACT.DATEINCOME,
DATESEND = d.CONTACT.DATESEND,
ID_EMAILACCOUNT = d.CONTACT.ID_EMAILACCOUNT,
DBID_EMAILACCOUNT = d.CONTACT.DBID_EMAILACCOUNT,
GESCHST = d.CONTACT.DBLINK.GESCHST,
d.CONTACT.DBLINK.KEYTYP,
KONTO = d.CONTACT.EMAILACCOUNT.NAME
});
WriteFile(#"C:\Temp\log.log",lQry.ToString());
}
SQL Development PC (everything is fine):
SELECT
"C"."ID_CONTACT" AS "ID_CONTACT",
"C"."READDATE" AS "READDATE",
"C"."DBID_CONTACT" AS "DBID_CONTACT",
"D"."DATEINSERT" AS "DATEINSERT",
"D"."FROMUSER" AS "FROMUSER",
"D"."FILENAME" AS "FILENAME",
"D"."KIND" AS "KIND",
"D"."MSGID" AS "MSGID",
"D"."ID_DBLINK" AS "ID_DBLINK",
"D"."DBID_DBLINK" AS "DBID_DBLINK",
"D"."SUBJECT" AS "SUBJECT",
"D"."STATE" AS "STATE",
"D"."DATEINCOME" AS "DATEINCOME",
"D"."DATESEND" AS "DATESEND",
"D"."ID_EMAILACCOUNT" AS "ID_EMAILACCOUNT",
"D"."DBID_EMAILACCOUNT" AS "DBID_EMAILACCOUNT",
"F"."GESCHST" AS "GESCHST",
"F"."KEYTYP" AS "KEYTYP",
"H"."NAME" AS "NAME"
FROM "CONTACTUSER" AS "C"
INNER JOIN "CONTACT" AS "D" ON ("C"."ID_CONTACT" = "D"."ID") AND ("C"."DBID_CONTACT" = "D"."DBID")
LEFT OUTER JOIN "DBLINK" AS "F" ON ("D"."ID_DBLINK" = "F"."ID") AND ("D"."DBID_DBLINK" = "F"."DBID")
INNER JOIN "EMAILACCOUNT" AS "H" ON ("D"."ID_EMAILACCOUNT" = "H"."ID") AND ("D"."DBID_EMAILACCOUNT" = "H"."DBID")
WHERE ((0 = "D"."ID_DBLINK") OR ("D"."ID_DBLINK" IS NULL)) OR ("F"."MANDNR" = #p__linq__0)
SQL Server (multible JOINS on DBLINK, very slow):
SELECT
"C"."ID_CONTACT" AS "ID_CONTACT",
"C"."READDATE" AS "READDATE",
"C"."DBID_CONTACT" AS "DBID_CONTACT",
"F"."DATEINSERT" AS "DATEINSERT",
"F"."FROMUSER" AS "FROMUSER",
"F"."FILENAME" AS "FILENAME",
"F"."KIND" AS "KIND",
"F"."MSGID" AS "MSGID",
"F"."ID_DBLINK" AS "ID_DBLINK",
"F"."DBID_DBLINK" AS "DBID_DBLINK",
"F"."SUBJECT" AS "SUBJECT",
"F"."STATE" AS "STATE",
"F"."DATEINCOME" AS "DATEINCOME",
"F"."DATESEND" AS "DATESEND",
"F"."ID_EMAILACCOUNT" AS "ID_EMAILACCOUNT",
"F"."DBID_EMAILACCOUNT" AS "DBID_EMAILACCOUNT",
"J"."GESCHST" AS "GESCHST",
"L"."KEYTYP" AS "KEYTYP",
"N"."NAME" AS "NAME"
FROM "CONTACTUSER" AS "C"
INNER JOIN "CONTACT" AS "D" ON ("C"."DBID_CONTACT" = "D"."DBID") AND ("C"."ID_CONTACT" = "D"."ID")
LEFT OUTER JOIN "CONTACT" AS "F" ON ("C"."DBID_CONTACT" = "F"."DBID") AND ("C"."ID_CONTACT" = "F"."ID")
LEFT OUTER JOIN "DBLINK" AS "H" ON ("F"."DBID_DBLINK" = "H"."DBID") AND ("F"."ID_DBLINK" = "H"."ID")
LEFT OUTER JOIN "DBLINK" AS "J" ON ("F"."DBID_DBLINK" = "J"."DBID") AND ("F"."ID_DBLINK" = "J"."ID")
LEFT OUTER JOIN "DBLINK" AS "L" ON ("F"."DBID_DBLINK" = "L"."DBID") AND ("F"."ID_DBLINK" = "L"."ID")
LEFT OUTER JOIN "EMAILACCOUNT" AS "N" ON ("F"."DBID_EMAILACCOUNT" = "N"."DBID") AND ("F"."ID_EMAILACCOUNT" = "N"."ID")
WHERE ((0 = "D"."ID_DBLINK") OR ("F"."ID_DBLINK" IS NULL)) OR ("H"."MANDNR" = #p__linq__0)
And here the code first data:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove();
modelBuilder.Entity<CONTACT>()
.HasOptional(b => b.DBLINK)
.WithMany()
.HasForeignKey(b => new { b.ID_DBLINK, b.DBID_DBLINK });
modelBuilder.Entity<CONTACT>()
.HasKey(d => new { d.ID, d.DBID })
.HasMany(d => d.CONTACTUSER)
.WithRequired(d => d.CONTACT)
.HasForeignKey(l => new { l.ID_CONTACT, l.DBID_CONTACT });
modelBuilder.Entity<CONTACT>()
.HasRequired(b => b.EMAILACCOUNT)
.WithMany()
.HasForeignKey(b => new { b.ID_EMAILACCOUNT, b.DBID_EMAILACCOUNT });
modelBuilder.Entity<CONTACT>().HasKey(a => new { a.ID, a.DBID });
modelBuilder.Entity<DBLINK>().HasKey(a => new { a.ID, a.DBID });
modelBuilder.Entity<CONTACTUSER>().HasKey(a => new { a.ID, a.DBID });
modelBuilder.Entity<EMAILACCOUNT>().HasKey(a => new { a.ID, a.DBID });
base.OnModelCreating(modelBuilder);
}
I'm searching for days now. How can the same code generate different SQL-Statements?
IIS Version (Development PC: IIS 8, Server IIS7.5)
Both environments are using the same Database-Server (Firebird 2.5)
I copied the whole project to the server, no changes...
The Projekt is set to .NET 4.5
I created a sample WPF-Projekt with this function and it resulted using the RIGHT SQL on the server
FirebirdSql.Data.FirebirdClient.dll Version 3.0.2.0 EntityFramework.dll 5.0.0
Do you have any idea what can infuence the query creation this way?