This might be a duplicate but nothing I've found up till now has solved this issue for me.
I'm trying to do a simple LINQ method
List<MyObject> unusedObject = _context.MyObjects.Where(o => o.CreatorUserId == null).ToList();
CreatorUserId is a nullable long.
In my database I'm seeing at least 10 objects with CreatorUserId = NULL but this call returns 0 objects.
I'm using EF6 in which I thought all such null issues were fixed
Edit - MyObject
[Table("MyObjects")]
public partial class MyObject
{
public MyObject()
{
}
[Key]
public long MyObjectId { get; set; }
public long? CreatorUserId { get; set; }
public virtual User CreatorUser { get; set; }
}
Edit 2 -trace log
SELECT
CAST(NULL AS bigint) AS [C1],
CAST(NULL AS bigint) AS [C2]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
WHERE 1 = 0
Try
List<MyObject> unusedObject = _context.MyObjects.Where(o => o.CreatorUserId.HasValue == false).ToList();
If it's still zero results then either MyObjects contains no data or CreatorUserId always has a value
Related
I have a class like below :
public class MasterTransaction
{
public int Id { get; set; }
public int EmployeeId { get; set; }
public int? SubTransactionId { get; set; }
[ForeignKey("SubTransactionId")]
public virtual MasterTransaction SubTransaction { get; set; }
public virtual ICollection<CommissionForManager> CommissionForManager { get; set; }
}
public class CommissionForManager
{
public int Id { get; set; }
public int ManagerId { get; set; }
public decimal CommissionMoney { get; set; }
public int MasterTransactionId { get; set; }
[ForeignKey("MasterTransactionId")]
public virtual MasterTransaction MasterTransaction { get; set; }
}
MasterTransaction will store all the master transactions.
CommissionForManager table stores data related to all the transactions from where the Manager is getting a commission.
Sample Data :
MasterTransaction:
Id EmployeeId SubTransactionId
50 100 null //100 is normal employee
51 101 50 //101 is a Manager
52 102 null
CommissionForManager:
Id ManagerId CommissionMoney MasterTransactionId
1 101 5000 50
2 101 6000 52
Now Manager creates transaction from a transaction of Employee and in that case "SubTransactionId" column will hold the TransactionId of that transaction.
For example: Manager 101 created a transaction from a transaction 50 hence SubTransactionId holds value 50.
So I want to get list of transactions where Manager is getting commission but those particular transactions shouldnt be referenced in "SubTransactionId" column.
For ex: Transaction Id = 50 and 51 because 51 is created from 50 so I want to ignore both. I only want Transaction 52 because it is not being referenced in "SubTransactionId" column in another Transaction.
Query :
string searchString;
int managerId;
var query = context.CommissionForManager.Where(c => c.CommissionMoney > 0)
.Where(c=> c.MasterTransaction.Employee.EmployeeName.Contains(searchString));
if (managerId > 0)
query = query.Where(c=>c.ManagerId == managerId);
return query.ToList();
But here, I am not getting how do I make another search of Transaction Id in the SubTransactionId of the same MasterTransaction table?
Can someone please help me or guide me through :)
This will select no rows from CommissionForManager where the MasterTransactionId appears in the SubTransactionId column of MasterTransaction
var query = context.CommissionForManager.Where(c => c.CommissionMoney > 0)
.Where(c=> c.MasterTransaction.Employee.EmployeeName.Contains(searchString))
.Where(c => !context.MasterTransaction.Where(row => row.SubTransactionId == c.MasterTransactionId).Any());
This code will do the same as above but generate a left outer join instead of a nested select:
var query = from c in context.CommissionForManagers
join m in context.MasterTransactions on c.MasterTransactionId equals m.SubTransactionId
into joined from j in joined.DefaultIfEmpty() // Without this a inner join will be performed instead of a left join
where c.CommissionMoney > 0
&& j == null // Select only rows that havent been joined to a MasterTransactions row by SubTransactionId
//&& c.MasterTransactions.Employee.EmployeeName.Contains(searchString)
select c;
Generated SQL:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[ManagerId] AS [ManagerId],
[Extent1].[CommissionMoney] AS [CommissionMoney],
[Extent1].[MasterTransactionId] AS [MasterTransactionId]
FROM [dbo].[CommissionForManager] AS [Extent1]
LEFT OUTER JOIN [dbo].[MasterTransaction] AS [Extent2] ON ([Extent1].[MasterTransactionId] = [Extent2].[SubTransactionId]) OR (([Extent1].[MasterTransactionId] IS NULL) AND ([Extent2].[SubTransactionId] IS NULL))
WHERE ([Extent1].[CommissionMoney] > 0) AND ([Extent2].[Id] IS NULL)
but those particular transactions shouldn't be referenced in "SubTransactionId" column
and
For ex: Transaction Id = 50 and 51 because 51 is created from 50 so I want to ignore both
The second doesn't really match the first requirement. Also SubTransactionId is poorly chosen name since it gives an impression of a pointer (reference) to some child, while in fact it seems to have parent reference semantics.
So if the second statement is correct, then the requirement can be formulated as follows: "include only transactions which have (1) no parent and (2) no child transactions".
The first condition is easy checked through navigation property, and the other needs subquery on the corresponding DbSet (remember it is queryable, so resolves to table access inside the LINQ to Entities query).
e.g. (skipping the initial part which applies other filters)
query = query.Where(c =>
c.MasterTransaction.SubTransctionId == null // (1)
&&
!context.Set<MasterTransaction>().Any(t => t.SubTransactionId == c.MasterTransactionId) // (2)
);
The dilemma/issue for the question seems to be because of the lack of the inverse navigation property in the model. If you have it (as you should, since it's helping understanding the relationship better and property querying it from both sides), i.e. something like
public class MasterTransaction
{
// ...
public virtual ICollection<MasterTransaction> ChildTransactions { get; set; }
}
then the second condition would be simply
!c.MasterTransaction.ChildTransactions.Any() // (2)
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.
This are the Tables
public class Purchase
{
public long Id { get; set; }
public string WareName { get; set; }
public int Count { get; set; }
public DateTime BuyTime { get; set; }
public IList<Inventory> Inventory { get; set; }
}
public class Inventory
{
public long Id { get; set; }
public long PurchaseId { get; set; }
[ForeignKey(nameof(PurchaseId))]
public Purchase Purchase { get; set; }
public int SaledCount { get; set; }
}
I try to do a Query like this:
SELECT SUM(x.[icout]) AS icount FROM
(
SELECT p.[Count] - ISNULL(
(SELECT SUM(i.SaledCount) FROM Inventory AS i WHERE i.PurchaseId = p.Id )
,0) AS [icout]
FROM Purchase AS p
WHERE p.WareName ='WareName5' AND
(
p.[Count] - ISNULL((SELECT SUM(i.SaledCount) FROM Inventory AS i WHERE i.PurchaseId = p.Id ),0) > 0
)
) AS x`
var left = _Db.Set<Purchase>().Include(p=>p.Inventory)
.Where(p=>p.WareName == WareName)
.Select(p => p.Count - p.Inventory.Sum(i => i.SaledCount)).Sum();
But it doesn't work when I target a real database (sqlite / sqlserver).
And it works fine when I use inMemoryDatabase.
Could anyone help me?
Ok this is just an attempt with the use of let, just tried it on my DNet Core site, and it ran nicely (I don't have the same entities as you do of course).
var left = from purchase in _Db.Set<Purchase>().Include(p=>p.Inventory)
where purchase != null && purchase.WareName == WareName
let sum = purchase.Inventory.Sum(i => i.SaledCount ?? 0)
select (purchase.Count - sum).Sum();'
Here is a straight forward solution that should not be giving you a N+1 problem.
It solves the "complex" solution in-memory. sometimes the cost has to be somewhere, and in memory sum is better than N+1
var left = (from purchase in _Db.Set<Purchase>().Include(p=>p.Inventory)
where purchase != null && purchase.WareName == WareName
select new ()
{
count = purchase.Count - sum,
invCounts = purchase.Inventory.where(a=> a.SaledCount!= null).Select(a=> a.SaledCount);
}).ToList().Select(a => a.count - invCounts.Sum());
Note
Use ICollection instead of IList as it's features translates better to SQL
Also in the constructor initialize the collections to a new HashSet<T>() so you don't end up with a null exception. Think of it like this, you cannot count the element of null but you can count the elements of a collection with 0 rows.
public class Purchase
{
public Purchase(){
Inventory = new HashSet<Inventory>();
}
public ICollection<Inventory> Inventory { get; set; }
}
I have an issue receiving the following error:
Conversion failed when converting the nvarchar value 'HolidayRequest' to data type int.
I have an inheritance structure within Entity Framework. My base Model is as follows:
public abstract class Request
{
public int ID { get; set; }
public int EmployeeID { get; set; }
public string Subject { get; set; }
[Display(Name = "Date Requested")]
public DateTime DateRequested { get; set; }
[Display(Name = "Start Date")]
public DateTime StartDateTime { get; set; }
[Display(Name = "Return To Work Date")]
public DateTime EndDateTime { get; set; }
public RequestStatus Status { get; set; }
public string Notes { get; set; }
public int? ResponseID { get; set; }
public RequestDiscriminator Discriminator { get; set; }
[ForeignKey("EmployeeID")]
public virtual Employee Employee { get; set; }
[ForeignKey("ResponseID")]
public virtual Response Response { get; set; }
}
When I attempt to retrieve data from the database as follows:
public IQueryable<Request> GetPendingHolidayRequestsByEmployeeId(int employeeId)
{
var list = _context.Requests.Where(p => p.Discriminator == RequestDiscriminator.Holiday && p.EmployeeID == employeeId && p.Status == RequestStatus.NotProcessed);
return list;
}
This is where the error occurs.
Given the context of the error I believe that it is an issue with this enum public RequestDiscriminator Discriminator { get; set; }
The structure of the Enum is:
public enum RequestDiscriminator
{
Holiday,
Absence
}
The SQL statement that is being sent by entity framework is:
SELECT
[Extent1].[ID] AS [ID],
CASE WHEN ([Extent1].[Discriminator1] = N'AbsenceRequest') THEN '0X0X' ELSE '0X1X' END AS [C1],
[Extent1].[EmployeeID] AS [EmployeeID],
[Extent1].[Subject] AS [Subject],
[Extent1].[DateRequested] AS [DateRequested],
[Extent1].[StartDateTime] AS [StartDateTime],
[Extent1].[EndDateTime] AS [EndDateTime],
[Extent1].[Status] AS [Status],
[Extent1].[Notes] AS [Notes],
[Extent1].[ResponseID] AS [ResponseID],
[Extent1].[Discriminator] AS [Discriminator]
CASE WHEN ([Extent1].[Discriminator1] = N'AbsenceRequest') THEN [Extent1].[ReasonCode] END AS [C2],
CASE WHEN ([Extent1].[Discriminator1] = N'AbsenceRequest') THEN [Extent1].[TakenPaid] END AS [C3],
CASE WHEN ([Extent1].[Discriminator1] = N'AbsenceRequest') THEN CAST(NULL AS float) ELSE [Extent1].[TotalDays] END AS [C4],
CASE WHEN ([Extent1].[Discriminator1] = N'AbsenceRequest') THEN [Extent1].[Employee_EmployeeID] END AS [C5],
CASE WHEN ([Extent1].[Discriminator1] = N'AbsenceRequest') THEN CAST(NULL AS int) ELSE [Extent1].[Employee_EmployeeID1] END AS [C6]
FROM [dbo].[Request] AS [Extent1]
WHERE ([Extent1].[Discriminator1] IN (N'AbsenceRequest',N'HolidayRequest')) AND (0 = [Extent1].[Discriminator]) AND (0 = [Extent1].[Status])
Any help would be greatly appreciated as i am completely stumped.
UPDATE
As per the suggestion in the answer below, I have removed both Discriminator columns from the database and readded mine. However, the SQL query still appears to be looking for the Discriminator1 column that now doesnt exist.
I have managed to solve this. The answer was to remove the discriminator column i created, and allow EF to determine the type by including the type in the linq query as follows:
var test = _context.Requests.Where(r => r.EmployeeID == employeeId).OfType<AbsenceRequest>();
The OfType<>() seems to tell EF to look at the Discriminator column for this type name and only return data of that type.
It looks like you have an extra column in there "Discriminator1". Did you originally have that field as a string, then tried to convert it to an enum? The best option might be to try dropping the field altogether and make sure it drops both Discriminator and Discriminator1. Then try adding it back. This can occur in when having custom mappings, so something may be off there.
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.