Use Sql View in EF 6.0 - c#

I have a CashFlowView:
CREATE VIEW [dbo].[CashFlowView]
AS
WITH CTE AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY RateDate) AS ID
, SUM(CASE WHEN C.CurrencyName = 'Br' THEN T.AmountMoney ELSE 0 END) AS AmountBYR
, SUM(CASE WHEN C.CurrencyName = 'Usd' THEN T.AmountMoney ELSE 0 END) AS AmountUSD
, CR.RateDate AS [DATE]
FROM Transactions AS T
INNER JOIN Accounts AS A ON A.AccountID = T.CurrentAccountID
INNER JOIN Currencies AS C ON C.CurrencyID = A.CurrencyID
RIGHT OUTER JOIN CurrencyRates AS CR ON CR.RateDate = T.ExecutionDate
GROUP BY CR.RateDate
)
SELECT
ID
, A.AmountBYR
, (SELECT SUM(B.AmountBYR) FROM CTE B WHERE B.ID<=A.ID) AS BalanceBYR
, A.AmountUSD
, (SELECT SUM(B.AmountUSD) FROM CTE B WHERE B.ID<=A.ID) AS BalanceUSD
, [Date]
FROM CTE AS A
Then I've added the Entity:
public class CashFlowView
{
[Key]
public int ID { get; set; }
public decimal AmountBYR { get; set; }
public decimal BalanceBYR { get; set; }
public decimal AmountUSD { get; set; }
public decimal BalanceUSD { get; set; }
public DateTime Date { get; set; }
}
And, as I understand, I need to add this code to my context:
public DbSet<CashFlowView> CashFlowView { get; set; }
And now I wanna to use my View:
IList<CashFlowView> listView;
using (var _db = new EconomicAppContext())
{
listView = _db.CashFlowView.ToList();
}
But listView is empty. How I may create correct mapping to View (maybe using migration) and use it?

I did it. Try to combine this article
http://www.paragon-inc.com/resources/blogs-posts/a-certain-point-of-view-part-1-ef-code-first
And use Entity Framework Power Tools to find needed result. And check connection. I've got problems with perfomance, so use dispose method carefully.

Related

Automapper generates a weird SQL query

I'm using Automapper version 10.0 with EF Core 5 and .NET 5.
It would seem that automapper causes a query that selects every property separately:
SELECT FALSE, a11."Avatar", ((
SELECT a0."Id"
FROM "AspNetUserRoles" AS a
INNER JOIN "AspNetRoles" AS a0 ON a."RoleId" = a0."Id"
WHERE a11."Id" = a."UserId"
ORDER BY a0."Order" DESC
LIMIT 1) IS NULL), (
SELECT a2."Color"
FROM "AspNetUserRoles" AS a1
INNER JOIN "AspNetRoles" AS a2 ON a1."RoleId" = a2."Id"
WHERE a11."Id" = a1."UserId"
ORDER BY a2."Order" DESC
LIMIT 1), (
SELECT a4."Id"
FROM "AspNetUserRoles" AS a3
INNER JOIN "AspNetRoles" AS a4 ON a3."RoleId" = a4."Id"
WHERE a11."Id" = a3."UserId"
ORDER BY a4."Order" DESC
LIMIT 1), (
SELECT a6."IsStaff"
FROM "AspNetUserRoles" AS a5
INNER JOIN "AspNetRoles" AS a6 ON a5."RoleId" = a6."Id"
WHERE a11."Id" = a5."UserId"
ORDER BY a6."Order" DESC
LIMIT 1), (
SELECT a8."Name"
FROM "AspNetUserRoles" AS a7
INNER JOIN "AspNetRoles" AS a8 ON a7."RoleId" = a8."Id"
WHERE a11."Id" = a7."UserId"
ORDER BY a8."Order" DESC
LIMIT 1), COALESCE((
SELECT a10."Order"
FROM "AspNetUserRoles" AS a9
INNER JOIN "AspNetRoles" AS a10 ON a9."RoleId" = a10."Id"
WHERE a11."Id" = a9."UserId"
ORDER BY a10."Order" DESC
LIMIT 1), 0), a11."Title", a11."UserName", t."Body", t."CommentsThreadId", t."DateTime", t."Id"
FROM (
SELECT c."Id", c."AuthorId", c."Body", c."CommentsThreadId", c."DateTime"
FROM "Comments" AS c
WHERE c."CommentsThreadId" = #__threadId_0
ORDER BY c."DateTime" DESC
LIMIT #__p_1 OFFSET 0
) AS t
INNER JOIN "AspNetUsers" AS a11 ON t."AuthorId" = a11."Id"
ORDER BY t."DateTime" DESC
As you can see, pretty much every single property of RoleDto is being SELECTed separately, instead of being selected just once and having its columns mapped using the AS keyword.
Mappings are done to the following DTOs, property names being true to source entities:
public class UserSimpleDto
{
public string UserName { get; set; }
public string Avatar { get; set; }
public string Title { get; set; }
public RoleDto Role { get; set; }
}
It seems the above and the below are the main culprits. OgmaUser, the source entity for the mapping of the above, contains a list of user roles, of which only one should be present in the target DTO.
OgmaUser.Roles is mapped using EF Core 5's many-to-many setup, but I did try to use an explicit join entity and the result was the exact same.
public class RoleDto
{
public long Id { get; set; }
public string Name { get; set; }
public string? Color { get; set; }
public bool IsStaff { get; set; }
public int Order { get; set; }
}
As you can see, each property of the above is being SELECT ... AS ... separately.
public class CommentDto
{
public long Id { get; set; }
public long CommentsThreadId { get; set; }
public UserSimpleDto Author { get; set; }
public DateTime DateTime { get; set; }
public string Body { get; set; }
}
I doubt this particular DTO has something to do with the result, since the issue occurs with other DTOs that contain UserSimpleDto, but I thought I should include it to present the fullest possible picture.
And the mappings are as follows:
CreateMap<OgmaUser, UserSimpleDto>()
.ForMember(
usd => usd.Role,
opts => opts.MapFrom(u => u.Roles.OrderByDescending(r => r.Order).FirstOrDefault())
);
CreateMap<OgmaRole, RoleDto>();
CreateMap<Comment, CommentDto>()
.ForMember(
cd => cd.Body,
opts => opts.MapFrom(c => Markdown.ToHtml(c.Body, null))
);
The query is generated from the following method:
public async Task<IEnumerable<CommentDto>> GetPaginated(long threadId, int page)
{
return await _context.Comments
.Where(c => c.CommentsThreadId == threadId)
.OrderByDescending(c => c.DateTime)
.ProjectTo<CommentDto>(_mapper.ConfigurationProvider)
.Skip(Math.Max(0, page - 1) * _config.CommentsPerPage)
.Take(_config.CommentsPerPage);
.AsNoTracking()
.ToListAsync();
}
Stack complains that my question is mostly code, and I suppose I do understand that. I've seen myself many people just posting their code, expecting to have it fixed, or even posting their homework and asking for it to be solved.
In this case, however, I believe that the code speaks louder than whatever explanation I could provide, so, true, non-code parts of this question are few and far between. That's the reason why I'm even writing those last paragraph, in fact, as SO will not let me submit my question otherwise.
I believe the best answer is to change UserSimpleDto to
public class UserSimpleDto
{
public string UserName { get; set; }
public string Avatar { get; set; }
public string Title { get; set; }
public IEnumerable<RoleDto> Roles { get; set; }
}
to load all user roles – there aren't all that many – and simply getting only the first one when it's just the first one that's needed. A negligible overhead in the application layer, so to speak, but the resulting query is much simpler which should negate that overhead.
Project after ToListAsync(). Don't pass IQueryable to ProjectTo method.
public async Task<IEnumerable<CommentDto>> GetPaginated(long threadId, int page)
{
return (await _context.Comments
.Where(c => c.CommentsThreadId == threadId)
.OrderByDescending(c => c.DateTime)
.Skip(Math.Max(0, page - 1) * _config.CommentsPerPage)
.Take(_config.CommentsPerPage);
.AsNoTracking()
.ToListAsync())
.ProjectTo<CommentDto>(_mapper.ConfigurationProvider);
}

Custom Linq query for Entity Framework & ASP.NET MVC app

I have been working on an ASP.NET MVC app using Entity Framework. Also, it's my first time developing an ASP.NET MVC app. I have been struggling (close to a month of trying and googling) to write a linq query to display results in jQuery datatable for the below SQL query. It involves various left joins and some columns have null values. It would be great if someone could help me out on this. There are 3 tables as below
Assets
Category
Term
SELECT
Asset.Name AS Name,
Asset.Type AS Type,
Asset.Parent_Asset AS "Parent Asset",
Cat.Category AS Category,
Cat.Parent_Category AS "Parent Category",
T.BUSINESS_TERM AS "Business Term",
T.SHORT_DESCRIPTION AS Description
FROM
(SELECT
CH.DISPLAY AS Name,
CH.TYPE AS Type,
PA.DISPLAY AS Parent_Asset,
CH.CATEGORY_INT_ID
FROM
[Metadata].[dbo].[Asset] CH
LEFT JOIN
[Metadata].[dbo].[Asset] PA ON PA.PARENT_ASSET_ID = CH.ASSET_INT_ID) Asset
LEFT JOIN
(SELECT
CH.DISPLAY AS Category,
PA.DISPLAY AS Parent_Category,
CH.CATEGORY_INT_ID AS Category_Id
FROM
[METADATA].[dbo].[Category] CH
LEFT JOIN
[METADATA].[dbo].[Category] PA ON PA.PARENT_CATEGORY_ID = CH.CATEGORY_INT_ID) Cat ON Asset.CATEGORY_INT_ID = Cat.Category_Id
LEFT JOIN
[Metadata].[dbo].[Term] T ON T.CATEGORY_INT_ID = Cat.Category_Id
Create Stored Procedure in the database where the application is connected
CREATE PROCEDURE sp_GetAsset
AS
BEGIN
SELECT
Asset.Name AS Name,
Asset.Type AS Type,
Asset.Parent_Asset AS ParentAsset,
Cat.Category AS Category,
Cat.Parent_Category AS ParentCategory,
T.BUSINESS_TERM AS BusinessTerm,
T.SHORT_DESCRIPTION AS Description
FROM
(
SELECT
CH.DISPLAY AS Name,
CH.TYPE AS Type,
PA.DISPLAY AS Parent_Asset,
CH.CATEGORY_INT_ID
FROM
[Metadata].[dbo].[Asset] CH
LEFT JOIN
[Metadata].[dbo].[Asset] PA ON PA.PARENT_ASSET_ID = CH.ASSET_INT_ID) Asset
LEFT JOIN
(SELECT
CH.DISPLAY AS Category,
PA.DISPLAY AS Parent_Category,
CH.CATEGORY_INT_ID AS Category_Id
FROM
[METADATA].[dbo].[Category] CH
LEFT JOIN
[METADATA].[dbo].[Category] PA ON PA.PARENT_CATEGORY_ID = CH.CATEGORY_INT_ID) Cat ON Asset.CATEGORY_INT_ID = Cat.Category_Id
LEFT JOIN
[Metadata].[dbo].[Term] T ON T.CATEGORY_INT_ID = Cat.Category_Id
);
END
Create class to get data:
public class TestAsset
{
public string Name { get; set; }
public string Type { get; set; }
public string ParentAsset { get; set; }
public string Category { get; set; }
public string ParentCategory { get; set; }
public string BusinessTerm { get; set; }
public string Description { get; set; }
}
Get data in your Context
public class YourContext : DbContext
{
public List<TestAsset> GetAssets()
{
return this.Query<TestAsset>.FromSql("Exec sp_GetAsset").ToList();
}
}
Use GetAssets Method
using (YourContext context = new YourContext())
{
var list = context.GetAssets();
}

How to properly use nested queries in EntityFramework?

I'm playing around EntityFrameworkCore with WebAPI while building voting app exercise.
I want to make the code in async way where is possible.
So should I have to use the nested query in async way somehow(// Problem 1, // Problem 2)?
/* The target of the question - the query*/
var pollResults =
await _context.Polls
.Select(poll => new PollDto
{
Id = poll.Id,
Question = poll.Question,
CreatedAt = poll.CreatedAt,
Options = poll.Options
.Select(option => new OptionDto
{
Id = option.Id,
Value = option.Value,
VotesCount = option.Votes.Count() // Problem 1
})
.ToList(), // Problem 2
LastVotedAt = _context.PollVotes.Where(vote=>vote.PollId == poll.Id).Select(vote => vote.VoteDate).SingleOrDefault()
})
.ToListAsync();
/* Domain classes */
public class Poll
{
public int Id { get; set; }
public ICollection<PollOption> Options { get; set; } = new List<PollOption>();
public ICollection<PollVote> Votes { get; set; } = new List<PollVote>();
}
public class PollOption
{
public int Id { get; set; }
public string Value { get; set; }
public int PollId { get; set; }
public Poll Poll { get; set; }
public ICollection<PollVote> Votes { get; set; } = new List<PollVote>();
}
public class PollVote
{
public int Id { get; set; }
public int PollId { get; set; }
public Poll Poll { get; set; }
public int OptionId { get; set; }
public PollOption Option { get; set; }
public DateTime VoteDate { get; set; }
}
/* Dto classes */
public class PollDto
{
public int Id { get; set; }
public string Question { get; set; }
public ICollection<OptionDto> Options { get; set; } = new List<OptionDto>();
public DateTime LastVotedAt { get; set; }
}
public class OptionDto
{
public int Id { get; set; }
public string Value { get; set; }
public int VotesCount { get; set; }
}
So in not nested queries Count and SingleOrDefault would make request to the database and it should be executed in async way. But in my case the whole query is a single request.
Should I have to modify something to done the methods Count and SingleOrDefault in async way ? Or calling ToListAsync at end is enough?
I believe the answer is that 1 request to the database goes in 1 async call. But I didn't find any solution in the internet.
ToListAsync() at the end is enough. Expressions inside the query are used by EF to compose the query. They are not "executed" as SQL like they would have been as stand-alone statements against the DbSets.
For instance when I run something similar:
var parents = await context.Parents
.Select(x => new
{
x.ParentId,
x.Name,
Children = x.Children.Select(c => new { c.ChildId, c.Name }).ToList(),
ChildCount = x.Children.Count()
}).ToListAsync();
in a test and set a breakpoint with a profiler running. The statement produces a single SQL statement:
SELECT
[Project2].[ParentId] AS [ParentId],
[Project2].[Name] AS [Name],
[Project2].[C2] AS [C1],
[Project2].[C1] AS [C2],
[Project2].[ChildId] AS [ChildId],
[Project2].[Name1] AS [Name1]
FROM ( SELECT
[Project1].[ParentId] AS [ParentId],
[Project1].[Name] AS [Name],
[Extent3].[ChildId] AS [ChildId],
[Extent3].[Name] AS [Name1],
CASE WHEN ([Extent3].[ChildId] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1],
[Project1].[C1] AS [C2]
FROM (SELECT
[Extent1].[ParentId] AS [ParentId],
[Extent1].[Name] AS [Name],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[Children] AS [Extent2]
WHERE [Extent1].[ParentId] = [Extent2].[ParentId]) AS [C1]
FROM [dbo].[Parents] AS [Extent1] ) AS [Project1]
LEFT OUTER JOIN [dbo].[Children] AS [Extent3] ON [Project1].[ParentId] = [Extent3].[ParentId]
) AS [Project2]
ORDER BY [Project2].[ParentId] ASC, [Project2].[C1] ASC
go
Not 3 queries that you might be concerned would block. This was when looking at the navigation properties for related records.
The bigger question I saw when looking at your example to double-check was this line:
LastVotedAt = _context.PollVotes.Where(vote=>vote.PollId == poll.Id).Select(vote => vote.VoteDate).SingleOrDefault()
As this would go back directly to the Context rather than access votes through a collection on the Poll. But I tried that as well and it too still resulted in a single query.
Children = x.Children.Select(c => new { c.ChildId, c.Name }).ToList(),
ChildCount = x.Children.Count(),
YoungestChild = context.Children.OrderBy(c=>c.BirthDate).Where(c=>c.ParentId == x.ParentId).FirstOrDefault()
In my test example I go back to the context to retrieve the Youngest child for the parent record rather than the Children navigation property. In this case it still executes as 1 query.
For questions like this I definitely recommend creating an EF experimentation sandbox project with a local database, then leverage and SQL profiler tool to watch the SQL statements being produced and when they are executed. Async is useful for queries that are expected to take a while to run, but should be used sparingly as they can lower the overall performance of the queries being run when used on every trivial query.

Why different T-SQL generated with almost same table structure

This really make me crazy and i cant figure out why hope someone could give me a little hint why it's behave so. I have 4 tables
1st group of these 2 tables and is able to give me a clean and nice T-SQL (sample from this link)
public class Standard
{
public Standard()
{
Students = new List<Student>();
}
public int StandardId { get; set; }
public string StandardName { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class Student
{
public Student() { }
public int StudentId { get; set; }
public string StudentName { get; set; }
public virtual Standard Standard { get; set; }
}
With Above tables and i use this
LINQ
List<Student> student = context.student.ToList();
var r = from ord in context.student.Include("standard")
select ord;
Ouput
SELECT
[Extent1].[StudentId] AS [StudentId],
[Extent1].[StudentName] AS [StudentName],
[Extent2].[StandardId] AS [StandardId],
[Extent2].[StandardName] AS [StandardName],
[Extent2].[Description] AS [Description]
FROM [dbo].[Students] AS [Extent1]
LEFT OUTER JOIN [dbo].[Standards] AS [Extent2] ON [Extent1].[Standard_StandardId] = [Extent2].[StandardId]
But with 2nd Group
public partial class Cust_ProfileTbl
{
public Cust_ProfileTbl()
{
balance = new List<BP_BalanceTbl>();
}
[Key]
public virtual long bintAccountNo { get; set; }
public string varCardNo { get; set; }
public virtual ICollection<BP_BalanceTbl> balance { get; set; }
}
public class BP_BalanceTbl
{
public BP_BalanceTbl() { }
public virtual long bintAccountNo { get; set; }
[Key]
public int intid { get; set; }
public virtual Cust_ProfileTbl profile { get; set; }
}
with this LINQ
List<Cust_ProfileTbl> profile = context.profile.ToList();
var rs = from ord in context.profile.Include("balance")
select ord;
Output
SELECT
[Project1].[C1] AS [C1],
[Project1].[bintAccountNo] AS [bintAccountNo],
[Project1].[varCardNo] AS [varCardNo],
[Project1].[C2] AS [C2],
[Project1].[intid] AS [intid],
[Project1].[bintAccountNo1] AS [bintAccountNo1]
FROM ( SELECT
[Extent1].[bintAccountNo] AS [bintAccountNo],
[Extent1].[varCardNo] AS [varCardNo],
1 AS [C1], --Why it generate this>?
[Extent2].[intid] AS [intid],
[Extent2].[bintAccountNo] AS [bintAccountNo1],
CASE WHEN ([Extent2].[intid] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2] --Why it generate this>?
FROM [dbo].[Cust_ProfileTbl] AS [Extent1]
LEFT OUTER JOIN [dbo].[BP_BalanceTbl] AS [Extent2] ON [Extent1].[bintAccountNo] = [Extent2].[bintAccountNo]
) AS [Project1]
ORDER BY [Project1].[bintAccountNo] ASC, [Project1].[C2] ASC
Questions
Why in 2nd LINQ it's generate C1?
Why in 2nd LINQ have this line CASE WHEN ([Extent2].[intid] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2] --Why it generate this>?
Why the 2nd output is so complex?
The C1 column doesn't appear to be relevant to the query - it might be an optimisation or protection that happens automatically so that LINQ can't accidentally create something invalid - or perhaps so that the first row can't inadvertently have NULL values.
The C2 column is generated as a protection against a null value since the value is attributed as a Primary Key (which means that it cannot be empty). Since you are doing a LEFT OUTER JOIN, the values on the left may not have joining records - but must still display a valid row for the LEFT information.
The query only looks more complex because it's constructing this extra information in a temporary table before selecting the results. It might be laying the query out in this way just because that's the only way it knows how to generate it through code - or maybe it's smart enough to know that this query is slightly more optimal for a query engine (I probably wouldn't bet on that).
In first case you are doing Include for simple navigation property
(thus it can be done with simple left outer join and each row in response will be materialized as entity in result),
in second case collection is included thus several rows from result should be merged into single entity and its collection property. Thus SQL query have to be written in following way that:
1. All rows to be merged in single entity will be fetched sequentially
2. Facilitate process of detection group bounds
3. Reduce data duplication
Some parts of generated SQL can be eliminated in this simple case, but they are used in more complex queries when several collection properties are included e.t.c.

Entity Framework Code First - Get blog posts which have certain tags

I a missing something here but I am not sure what is that. So I need a pair of eyes. I want to get blog posts which has certain tags associated with it. My model structure looks like as below:
public partial class BlogPost : IEntity {
public BlogPost() {
this.BlogPostComments = new HashSet<BlogPostComment>();
this.BlogPostUrls = new HashSet<BlogPostUrl>();
this.TagsForBlogPosts = new HashSet<TagsForBlogPost>();
}
public System.Guid Key { get; set; }
public System.Guid LanguageKey { get; set; }
public Nullable<int> SecondaryKey { get; set; }
public string Title { get; set; }
//...
public virtual ICollection<BlogPostComment> BlogPostComments { get; set; }
public virtual Language Language { get; set; }
public virtual ICollection<BlogPostUrl> BlogPostUrls { get; set; }
public virtual ICollection<TagsForBlogPost> TagsForBlogPosts { get; set; }
}
public partial class Tag : IEntity {
public Tag() {
this.TagsForBlogPosts = new HashSet<TagsForBlogPost>();
this.TagsForDynamicPages = new HashSet<TagsForDynamicPage>();
}
public System.Guid Key { get; set; }
public System.Guid LanguageKey { get; set; }
public string TagName { get; set; }
//...
public virtual Language Language { get; set; }
public virtual ICollection<TagsForBlogPost> TagsForBlogPosts { get; set; }
public virtual ICollection<TagsForDynamicPage> TagsForDynamicPages { get; set; }
}
public partial class TagsForBlogPost : IEntity {
public System.Guid Key { get; set; }
public System.Guid BlogPostKey { get; set; }
public System.Guid TagKey { get; set; }
public virtual BlogPost BlogPost { get; set; }
public virtual Tag Tag { get; set; }
}
As input I have string[] tags which I need for a blog posts to have. For now, I can have the following code working:
public void Get(string[] tags) {
var posts = dbConxtext.BlogPosts.Where(x =>
x.TagsForBlogPosts.Any(y => tags.Contains(y.Tag.TagName)));
//
}
But it generates an IN Clause which is not what I want. Here is the T-SQL which the above code generates:
SELECT
[Extent1].[Key] AS [Key],
[Extent1].[LanguageKey] AS [LanguageKey],
[Extent1].[SecondaryKey] AS [SecondaryKey],
[Extent1].[Title] AS [Title],
[Extent1].[BriefInfo] AS [BriefInfo],
[Extent1].[Content] AS [Content],
[Extent1].[ImagePath] AS [ImagePath],
[Extent1].[IsApproved] AS [IsApproved],
[Extent1].[CreationIp] AS [CreationIp],
[Extent1].[CreatedOn] AS [CreatedOn],
[Extent1].[LastUpdateIp] AS [LastUpdateIp],
[Extent1].[LastUpdatedOn] AS [LastUpdatedOn]
FROM [dbo].[BlogPosts] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM [dbo].[TagsForBlogPosts] AS [Extent2]
INNER JOIN [dbo].[Tags] AS [Extent3] ON [Extent2].[TagKey] = [Extent3].[Key]
WHERE ([Extent1].[Key] = [Extent2].[BlogPostKey]) AND ([Extent3].[TagName] IN (N'nuget',N'mvc'))
)
What I want is to exact match to those tags. Any idea how I can achieve that?
Edit:
What I need is as below:
The Post A has tag1, tag2 and tag3. The post B has tag1, tag3. If the string array includes tag1 and tag2, only the Post A should be selected because it has both tag1 and tag2.
Answer:
I managed to get it working thanks to #msarchet. Here is the LINQ query:
public void Get(string[] tags) {
var posts = dbConxtext.BlogPosts
.Where(x => tags.All(t => x.TagsForBlogPosts.Any(y => y.Tag.TagName == t)));
//
}
And generated T-SQL:
SELECT
[Extent1].[Key] AS [Key],
[Extent1].[LanguageKey] AS [LanguageKey],
[Extent1].[SecondaryKey] AS [SecondaryKey],
[Extent1].[Title] AS [Title],
[Extent1].[BriefInfo] AS [BriefInfo],
[Extent1].[Content] AS [Content],
[Extent1].[ImagePath] AS [ImagePath],
[Extent1].[IsApproved] AS [IsApproved],
[Extent1].[CreationIp] AS [CreationIp],
[Extent1].[CreatedOn] AS [CreatedOn],
[Extent1].[LastUpdateIp] AS [LastUpdateIp],
[Extent1].[LastUpdatedOn] AS [LastUpdatedOn]
FROM [dbo].[BlogPosts] AS [Extent1]
WHERE NOT EXISTS (SELECT
1 AS [C1]
FROM (SELECT
N'nuget' AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
UNION ALL
SELECT
N'razor' AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1]
WHERE ( NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[TagsForBlogPosts] AS [Extent2]
INNER JOIN [dbo].[Tags] AS [Extent3] ON [Extent2].[TagKey] = [Extent3].[Key]
WHERE ([Extent1].[Key] = [Extent2].[BlogPostKey]) AND ([Extent3].[TagName] = [UnionAll1].[C1])
)) OR (CASE WHEN ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[TagsForBlogPosts] AS [Extent4]
INNER JOIN [dbo].[Tags] AS [Extent5] ON [Extent4].[TagKey] = [Extent5].[Key]
WHERE ([Extent1].[Key] = [Extent4].[BlogPostKey]) AND ([Extent5].[TagName] = [UnionAll1].[C1])
)) THEN cast(1 as bit) WHEN ( NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[TagsForBlogPosts] AS [Extent6]
INNER JOIN [dbo].[Tags] AS [Extent7] ON [Extent6].[TagKey] = [Extent7].[Key]
WHERE ([Extent1].[Key] = [Extent6].[BlogPostKey]) AND ([Extent7].[TagName] = [UnionAll1].[C1])
)) THEN cast(0 as bit) END IS NULL)
)
So what your trying to do per your comment
yes. Assuming: the Post A has tag1, tag2 and tag3. The post B has tag1, tag3. If the string array includes tag1 and tag2, the Post A should be selected.
Is
var posts = dbConxtext.BlogPosts.Where(x => tags.All(t =>
x.TagsForBlogPost.Any(y => y.Tag.TagName == t)));
So make sure that All of the tags are contained in TagsForBlogPost
Warning, this may produce terrible SQL

Categories