C# Entity Framework Error Converting nvarchar to int by enum - c#

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.

Related

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.

Linq query not returning expected number of results

I have two data models:
public class SSC {
public int Id { get; set; }
public string Name { get; set; }
//other irrelevent properties removed for brevity
public virtual ICollection<SpecReference> SpecReferences { get; set; }
}
public class SpecReference {
public int Id { get; set; }
public string Name { get; set; }
//other irrelevent properties removed for brevity
public virtual ICollection<SSC> SSCs { get; set; }
}
I have defined a many-to-many relationship between the two in my data context as:
modelBuilder.Entity<SSC>().HasMany(a => a.SpecReferences)
.WithMany(b => b.SSCs)
.Map(c => {
c.MapRightKey("SpecReference_Id");
c.MapLeftKey("SSC_Id");
c.ToTable("SpecReferenceSSCs");
});
At one point in my site, I have an advanced search page from which users can search for SSCs by a combination of any field in the SSC or any navigation field attached to the SSC. Every search is working except when a user specifies a SpecReference. The query code (abbreviated to show only relevant code) is:
var query = _dbContext.SSCs.Where(x => !x.IsDeleted);
if (designSpecificationIds != null && designSpecificationIds.Any()) {
var designSpecificationIdsHash = new HashSet<int>(designSpecificationIds);
query = query.Where(x => x.SpecReferences.Any(s => designSpecificationIdsHash.Contains(s.Id)));
}
where designSpecificationIds is an array of integers passed from the web form.
When I run the application and step through the search code, the SQL generated from the query is:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[SSCId] AS [SSCId],
[Extent1].[Name] AS [Name],
[Extent1].[SystemFunction] AS [SystemFunction],
[Extent1].[Remarks] AS [Remarks],
[Extent1].[IsSystem] AS [IsSystem],
[Extent1].[IsGrouping] AS [IsGrouping],
[Extent1].[IsConfiguration] AS [IsConfiguration],
[Extent1].[FieldTag] AS [FieldTag],
[Extent1].[ParentId] AS [ParentId],
[Extent1].[IPlantParentId] AS [IPlantParentId],
[Extent1].[BuildingId] AS [BuildingId],
[Extent1].[IsOperable] AS [IsOperable],
[Extent1].[IsAvailable] AS [IsAvailable],
[Extent1].[DutyAreaId] AS [DutyAreaId],
[Extent1].[IsDeleted] AS [IsDeleted]
FROM [dbo].[SSCs] AS [Extent1]
WHERE ([Extent1].[IsDeleted] <> 1) AND ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[SpecReferenceSSCs] AS [Extent2]
WHERE ([Extent1].[Id] = [Extent2].[SSC_Id]) AND ([Extent2].[SpecReference_Id] IN (4))
))
If I run this SQL against the database, I get the one result that I expect. However, when I examine the Linq query and attempt to enumerate the results, I get "Enumeration yielded no results." How is it possible that the SQL generated by a Linq query is returning different results than the query itself?
Edit:
To return the values, I'm using ExpressMapper to convert the Model to a DTO. The conversion is simply:
return Mapper.Map<IEnumerable<SSC>, IEnumerable<SSCIndexDto>>(query);
The DTO is:
public class SSCIndexDto {
public int Id { get; set; }
public string Name { get; set; }
//Other properties omitted for brevity
public List<SpecReferenceIndexDto> SpecReferences { get; set; }
}
Again, the mapping appears to be working correctly for all other properties, including navigation properties that are written exactly like SpecReferences. It's the query itself that's not returning any data.

Finding where nullable long == null in Entity Framework 6

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

Why does EF 6.1.3 persist in generating the string value as Unicode?

I have the following classes defined:
private class Entity
{
public int? Number { get; set; }
[Column(TypeName = "VARCHAR")]
[StringLength(50)]
public string Type { get; set; }
public int Id { get; set; }
[Column(TypeName = "VARCHAR")]
[StringLength(255)]
public string Name { get; set; }
}
Entity is not a Model class which exists in the database, rather I want to map output to it instead of an anonymous type.
public static class EntityTypeName
{
public const string Dealer = "DEALER";
}
Later, in my code I have the following Entity Framework query:
IRepository<DealerMostCurrent> repoDealer = new Repository<DealerMostCurrent>(context);
IRepository<DealerContact> repoDealerContact = new Repository<DealerContact>(context);
IQueryable<Entity> dealerEntity;
dealerEntity = from dealerRow in repoDealer.GetAsQueryable(dealerWhere).AsNoTracking()
join dealerContactRow in repoDealerContact.GetAsQueryable(dealerContactWhere).AsNoTracking() on dealerRow.Dealer_Number equals dealerContactRow.Dealer_Number
group dealerRow by new
{
dealerRow.Dealer_Number,
dealerRow.Dealer_Id,
dealerRow.Dealer_Name
} into groupedDealers
select new Entity()
{
Number = groupedDealers.Key.Dealer_Number,
Type = EntityItem.EntityTypeName.Dealer,
Id = groupedDealers.Key.Dealer_Id,
Name = groupedDealers.Key.Dealer_Name
};
If I look at the generated SQL for the EF call, I see that Entity Framework is casting my EntityItem.EntityTypeName.Dealer constant which is defined as a String to N'DEALER' AS [C1],
SELECT
[Distinct1].[Dealer_Id] AS [Dealer_Id],
[Distinct1].[Dealer_Number] AS [Dealer_Number],
N'DEALER' AS [C1],
[Distinct1].[Dealer_Name] AS [Dealer_Name]
FROM ( SELECT DISTINCT
[Extent1].[Dealer_Id] AS [Dealer_Id],
[Extent1].[Dealer_Number] AS [Dealer_Number],
[Extent1].[Dealer_Name] AS [Dealer_Name]
FROM [dbo].[DealerMostCurrent] AS [Extent1]
INNER JOIN [dbo].[DealerContact] AS [Extent2] ON [Extent1].[Dealer_Number] = [Extent2].[Dealer_Number]
WHERE ([Extent1].[Dealer_Id] > 0) AND ([Extent2].[Contact_Id] IN (1473,1475,1477,1481))
) AS [Distinct1]
It seems that EntityFramework is ignoring my [Column(TypeName = "VARCHAR") on my output mapping class. If I explicitly tell Entity Framework that Type = System.Data.Entity.DbFunctions.AsNonUnicode(EntityItem.EntityTypeName.Dealer) then all is fine and the string is not typecast to Unicode. Am I missing something here?
Also, In my OnModelCreating I thought that doing the following would explicitly force EntityFramework to treat all string types as not Unicode.
modelBuilder.Properties<string>().Configure(p => p.IsUnicode(false));
What piece of the puzzle am I missing or misunderstanding. How do I force EntityFramework to treat all .NET String types as not Unicode? I would rather not have to go through all my code and add System.Data.Entity.DbFunctions.AsNonUnicode in all the places where I am setting a constant string value.

Use Sql View in EF 6.0

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.

Categories