I have a DBContext where PriceListTest object is loaded as follows
DBContext.cs:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//other code removed
//pricelist
modelBuilder.Entity<PriceListTest>().ToTable(null);
modelBuilder.Entity<PriceListTest>().ToSqlQuery(
#"SELECT T.ID, T.SHORTNAME, T.DESCRIPTION, CTL.CoCTestCode AS CODE, CTL.CoCTestName AS NAME, CTL.CLIENTID, T.ISSET, 0 AS PRICELISTID, CONT.MATRIXTYPEID AS MatrixTypeId, -1 AS MATRIXID
FROM [TESTLIST] T
INNER JOIN [COCTESTLIST] CTL ON ELVISTESTLISTID = T.ID
INNER JOIN CUSTOMERCONTAINERS_TESTLIST custTest on custTest.TESTLISTID = T.ID
INNER JOIN CUSTOMERCONTAINERS cont on cont.id = custTest.CustomerContainerID
WHERE T.RECORDSTATUS = 0");
}
In this code, MatrixTypeId field is the problem!
When I run this query in SQL it will return the following result:
ID
ClientID
MatrixTypeId
7893
NULL
1
7893
NULL
2
7893
NULL
2
7891
NULL
1
7891
735
1
7891
NULL
2
and so on.. (total of 28 records)
In my repository, I filter it based on some parameters.
TestListRepository:
public async Task<List<PriceListTest>> Search(string text,int clientId, int batchId)
{
// some code removed for brevity
var productQuery = await context.PriceListTests.Where(p => !existingTestIds.Contains(p.Id) && (p.Name.Contains(text) || p.Code.Contains(text))
&& (p.ClientId == newClientId)
&& sampleMatrixTypes.Contains(p.MatrixTypeId)).Distinct().ToListAsync();
// productQuery.ToQueryString();
return productQuery;
}
The query that I grab from productQuery.ToQueryString(); is:
DECLARE #__text_1 nvarchar(4000) = N'BTEX';
SELECT DISTINCT [p].[Id], [p].[ClientId], [p].[Code], [p].[Description], [p].[Isset], [p].[MatrixId], [p].[MatrixTypeId], [p].[Name], [p].[PRICELISTID], [p].[ShortName]
FROM
(SELECT T.ID, T.SHORTNAME, T.DESCRIPTION, CTL.CoCTestCode AS CODE, CTL.CoCTestName AS NAME, CTL.CLIENTID, T.ISSET, 0 AS PRICELISTID, CONT.MATRIXTYPEID AS MatrixTypeId, -1 AS MATRIXID
FROM [TESTLIST] T
INNER JOIN [COCTESTLIST] CTL ON ELVISTESTLISTID = T.ID
INNER JOIN CUSTOMERCONTAINERS_TESTLIST custTest ON custTest.TESTLISTID = T.ID
INNER JOIN CUSTOMERCONTAINERS cont on cont.id = custTest.CustomerContainerID
WHERE T.RECORDSTATUS = 0) AS [p]
WHERE (([p].[Id] NOT IN (CAST(5233 AS smallint), CAST(5234 AS smallint), CAST(5766 AS smallint)) AND (((#__text_1 LIKE N'') OR (CHARINDEX(#__text_1, [p].[Name]) > 0)) OR ((#__text_1 LIKE N'') OR (CHARINDEX(#__text_1, [p].[Code]) > 0)))) AND [p].[ClientId] IS NULL) AND [p].[MatrixTypeId] IN (1, 2)
When I run this query, again I get the expected/correct resultset in SQL
ID
ClientID
MatrixTypeId
7893
NULL
1
7893
NULL
2
7891
NULL
1
7891
NULL
2
But when I get the json response, it has all 4 matrixtypeid values fixed as 1
Also, watching the object in debugger has all 4 matrixtypeId are set as 1
ID
ClientID
MatrixTypeId
7893
NULL
1
7893
NULL
1
7891
NULL
1
7891
NULL
1
PriceListTest.cs
public class PriceListTest
{
public short Id { get; set; }
public string Code { get; set; }
public string ShortName { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int? ClientId { get; set; }
public bool Isset { get; set; }
public int PRICELISTID { get; set; }
public int MatrixTypeId { get; set; }
public int MatrixId { get; set; }
}
P.S: Other fields like ShortName,Description, Code, Name are all based off on ID so they are repeated as often as ID is being in the above sample.
Also, PriceListID and MatrixId are fixed for backward compatibility but are irrelevant for my code.
UPDATE: I have created a new join table to avoid nesting of so many objects. The new query is:
SELECT distinct T.ID, T.SHORTNAME, T.DESCRIPTION, CTL.CoCTestCode, CTL.CoCTestName, CTL.CLIENTID, T.ISSET, CTLM.MATRIXTYPEID
FROM [TESTLIST] T
INNER JOIN [COCTESTLIST] CTL ON ELVISTESTLISTID = T.ID
INNER JOIN [CoCTestList_MATRIXTYPE] CTLM ON ctl.ID = CTLM.COCTESTLISTID
WHERE T.RECORDSTATUS = 0
Instead of PriceListTest I am now using CoCTestList class/table which is more relevant and straight forward. Also, I have removed the hard coded fields: MatrixID and PriceListID.
The resulting json though still is giving MatrixTypeId as 1 :)
CoCTestList.cs
public class CoCTestList
{
public int Id { get; set; }
[NotMapped]
public string PriceBookSection { get; set; }
[NotMapped]
public string PriceBookGroup { get; set; }
public string CoCTestCode { get; set; }
public string CoCTestName { get; set; }
//[NotMapped]
public int ElvisTestListId { get; set; }
public int? ClientId { get; set; }
[NotMapped]
public bool IsEnabled { get; set; }
[NotMapped]
public string ShortName { get; set; }
[NotMapped]
public string Description { get; set; }
[NotMapped]
public bool Isset { get; set; }
[NotMapped]
public int MatrixTypeId { get; set; }
}
Related
How to join multiple tables using group by. I have consulted some posts on stackoverflow, but it doesn't seem to work for me.
I have Model
public class Customer
{
public int ID { get; set; }
public string RadomID { get; set; }
public bool Active { get; set; }
}
public class RatingStore
{
public string RadomID { get; set; }
public string Content { get; set; }
}
public class Product
{
public int IDProduct { get; set; }
public string RadomID { get; set; }
}
This is how I count in CustomersController
public CustomersController(ApplicationDBContext context)
{
_context = context;
}
var qr = (from Customer c in _context.Customers
join o in _context.RatingStore on c.RadomID equals o.RadomID
join p in _context.Products on c.RadomID equals p.RadomID
where c.Active == true
group c by c.RadomID into g
select new
{
StoreId = g.Key,
CountRatingStore = g.Count(),
CountProdStore = g.Count(),
}).ToList();
However when I debug the results
CountRatingStore = g.Count() --> result: 2
CountProdStore = g.Count() --> result: 2
It has to be like this:
CountRatingStore = g.Count() --> result: 1
CountProdStore = g.Count() --> result: 2
Because of the data in my database:
Table Product:
Table RatingStore:
Table Customer:
Maybe my command is incorrect. How to get the correct result as I described above. Thank you
Update
public class ApplicationDBContext : DbContext
{
public ApplicationDBContext(DbContextOptions<ApplicationDBContext> options) : base(options)
{
}
public virtual DbSet<Product> Products { get; set; }
public virtual DbSet<RatingStore> RatingStore { get; set; }
public virtual DbSet<Customer> Customers { get; set; }
}
I am trying to count the number of columns of Table Product and RatingStore with the same RandomID condition.
---> The problem I have not been able to solve. I ask for help from everyone.
public class Employee
{
public string FullName { get; set; }
public string Code { get; set; }
public string Gender { get; set; }
public string MaritalStatus { get; set; }
public DateTime DateOfBirth { get; set; }
public string Status { get; set; }
// # Address
public Address Address { get; set; }
}
public class Address
{
public string Address1 { get; set; }
public string? Address2 { get; set; }
public string City { get; set; }
public string? Region { get; set; }
public string PostCode { get; set; }
public Country Country { get; set; }
private Address() {}
}
EntityConfiguration
public class EmployeeConfiguration : IEntityTypeConfiguration<Employee>
{
public void Configure(EntityTypeBuilder<Employee> builder)
{
builder.OwnsOne(e => e.Address);
}
}
Generated SQL
SELECT t."Id", t."BsonId", t."Code", t."CompanyId", t."Created", t."DateOfBirth", t."FullName", t."Gender", t."LastModified", t."MaritalStatus", t."Status", t1."Id", t1."Address_Address1", t1."Address_Address2", t1."Address_City", t1."Address_PostCode", t1."Address_Region"
FROM (
SELECT e."Id", e."BsonId", e."Code", e."CompanyId", e."Created", e."DateOfBirth", e."FullName", e."Gender", e."LastModified", e."MaritalStatus", e."Status"
FROM "I180814-04-edm"."Employees" AS e
ORDER BY (SELECT 1)
LIMIT #__p_1 OFFSET #__p_0
) AS t
LEFT JOIN (
SELECT e0."Id", e0."Address_Address1", e0."Address_Address2", e0."Address_City", e0."Address_PostCode", e0."Address_Region", e1."Id" AS "Id0"
FROM "I180814-04-edm"."Employees" AS e0
INNER JOIN "I180814-04-edm"."Employees" AS e1 ON e0."Id" = e1."Id"
WHERE (e0."Address_Region" IS NOT NULL) OR ((e0."Address_PostCode" IS NOT NULL) OR ((e0."Address_City" IS NOT NULL) OR ((e0."Address_Address2" IS NOT NULL) OR (e0."Address_Address1" IS NOT NULL))))
) AS t0 ON t."Id" = t0."Id"
LEFT JOIN (
SELECT e2."Id", e2."Address_Address1", e2."Address_Address2", e2."Address_City", e2."Address_PostCode", e2."Address_Region", e3."Id" AS "Id0"
FROM "I180814-04-edm"."Employees" AS e2
INNER JOIN "I180814-04-edm"."Employees" AS e3 ON e2."Id" = e3."Id"
WHERE (e2."Address_Region" IS NOT NULL) OR ((e2."Address_PostCode" IS NOT NULL) OR ((e2."Address_City" IS NOT NULL) OR ((e2."Address_Address2" IS NOT NULL) OR (e2."Address_Address1" IS NOT NULL))))
) AS t1 ON t."Id" = t1."Id"
Did I miss something? I searched all over but I could not find anyway to modify the generated SQL for OwnedProperties in Ef core. Is there a way to setup the relationships so that ef core projects the properties as if it was a single model rather than detecting it as a relationship and generating a left join.
In fact, there are nothings wrongs with generated SQL statement (left join).
You can use right predicate to be sure address is not null like inner join without any performance impact:
var result = await dbcontext.Employee.Include(x => x.Include(y => y.Address)).Where(p => p.Address != null).FirstOrDefaultAsync();
This is a very common approach.
This was a known issue in Entity Framework Core 3.1. It has been fixed in Entity Framework 5.0. The bug ticket has some useful discussions about performance and workarounds, if you aren't able to upgrade. https://github.com/dotnet/efcore/issues/18299
I want to display the results of this SQL query in a WPF datagrid. My question how to run this query using EF6?
select c.*, count(o.id) from clients c
left join optics o
on o.client_id = c.id
where o.r_sph = 12 // 12 is a variable value
group by c.id
My Clients model:
public clients()
{
this.optics = new ObservableCollection<optics>();
}
public long id { get; set; }
public string name { get; set; }
public string phone { get; set; }
public Nullable<System.DateTime> date_of_birth { get; set; }
public System.DateTime inserted_at { get; set; }
public System.DateTime updated_at { get; set; }
public virtual ObservableCollection<optics> optics { get; set; }
And Optics model:
public long id { get; set; }
public Nullable<System.DateTime> at { get; set; }
public Nullable<decimal> r_sph { get; set; }
public Nullable<int> r_axs { get; set; }
public string notes { get; set; }
public Nullable<long> client_id { get; set; }
public System.DateTime inserted_at { get; set; }
public System.DateTime updated_at { get; set; }
public virtual clients clients { get; set; }
Update:
I use this code to filter the results:
public IQueryable < Multi.Model.clients > FilterClients(optisysEntities db, System.Linq.IQueryable < Multi.Model.clients > clients, ClientsFilter clientsFilter) {
if (!String.IsNullOrWhiteSpace(clientsFilter.Name))
clients = db.clients.Where(c => c.name.Contains(clientsFilter.Name));
if (!String.IsNullOrWhiteSpace(clientsFilter.Phone))
clients = clients.Where(u => u.phone.Contains(clientsFilter.Phone));
}
You will need to return a new object (unless you already have a model set up which includes the "Count" property). Something like this:
var query = (from c in context.Clients
join o in context.Optics
on c.id equals o.client_id
where o.r_sph == 12
group new { c, o } by new { c.Id }
into g
select new {Id = g.Key.id,
// other properties from "Client",
Count = g.Count()}
).ToList();
I can't figure out why entityframework is returning me all columns on the below two queries. I'm trying to get it to return me just the date column but back all the columns of db.EmailDetails come when I look at the sql generated (posted below)
var y = (from data1 in db.EmailDetails
join data2 in db.AddressBookEntries on data1.FromAddressBookEntryId equals data2.Id
orderby data1.EmailSendFinishTime descending
select data1.EmailSendFinishTime).FirstOrDefault();
var x =
db.EmailDetails.Where(a => a.User.Username == username && a.FromAddressBookEntry.WhiteList).
Select(a => new
{
a.EmailSendFinishTime
}).
OrderByDescending(
a => a.EmailSendFinishTime)
.FirstOrDefault();
sql generated:
exec sp_executesql N'SELECT TOP (1)
[Project1].[Id] AS [Id],
[Project1].[UserId] AS [UserId],
[Project1].[InValidMailMessage] AS [InValidMailMessage],
[Project1].[MailInternalDate] AS [MailInternalDate],
[Project1].[MessageUniqueId] AS [MessageUniqueId],
[Project1].[FromAddressBookEntryId] AS [FromAddressBookEntryId],
[Project1].[ToEmailAddress] AS [ToEmailAddress],
[Project1].[EmailFolderId] AS [EmailFolderId],
[Project1].[EmailHeaderInfo] AS [EmailHeaderInfo],
[Project1].[EmailSendSmtpServer] AS [EmailSendSmtpServer],
[Project1].[EmailSendStatus] AS [EmailSendStatus],
[Project1].[EmailSendStartTime] AS [EmailSendStartTime],
[Project1].[EmailSendFinishTime] AS [EmailSendFinishTime],
[Project1].[EmailSendLogMessage] AS [EmailSendLogMessage],
[Project1].[Subject] AS [Subject],
[Project1].[MimeMessageFull] AS [MimeMessageFull],
[Project1].[HighPriority] AS [HighPriority],
[Project1].[SentDateTime] AS [SentDateTime],
[Project1].[EmailDeleted] AS [EmailDeleted],
[Project1].[EmailDeletedDateTime] AS [EmailDeletedDateTime],
[Project1].[EmailViewed] AS [EmailViewed],
[Project1].[EmailViewedDateTime] AS [EmailViewedDateTime],
[Project1].[BodyTextForSend] AS [BodyTextForSend],
[Project1].[ReceivedDate] AS [ReceivedDate]
FROM ( SELECT [Extent1].[Id] AS [Id],
[Extent1].[UserId] AS [UserId],
[Extent1].[InValidMailMessage] AS [InValidMailMessage],
[Extent1].[MailInternalDate] AS [MailInternalDate],
[Extent1].[MessageUniqueId] AS [MessageUniqueId],
[Extent1].[FromAddressBookEntryId] AS [FromAddressBookEntryId],
[Extent1].[ToEmailAddress] AS [ToEmailAddress],
[Extent1].[EmailFolderId] AS [EmailFolderId],
[Extent1].[EmailHeaderInfo] AS [EmailHeaderInfo],
[Extent1].[EmailSendSmtpServer] AS [EmailSendSmtpServer],
[Extent1].[EmailSendStatus] AS [EmailSendStatus],
[Extent1].[EmailSendStartTime] AS [EmailSendStartTime],
[Extent1].[EmailSendFinishTime] AS [EmailSendFinishTime],
[Extent1].[EmailSendLogMessage] AS [EmailSendLogMessage],
[Extent1].[Subject] AS [Subject],
[Extent1].[MimeMessageFull] AS [MimeMessageFull],
[Extent1].[HighPriority] AS [HighPriority],
[Extent1].[SentDateTime] AS [SentDateTime],
[Extent1].[EmailDeleted] AS [EmailDeleted],
[Extent1].[EmailDeletedDateTime] AS [EmailDeletedDateTime],
[Extent1].[EmailViewed] AS [EmailViewed],
[Extent1].[EmailViewedDateTime] AS [EmailViewedDateTime],
[Extent1].[BodyTextForSend] AS [BodyTextForSend],
[Extent1].[ReceivedDate] AS [ReceivedDate]
FROM [dbo].[EmailDetails] AS [Extent1]
INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserId] =
[Extent2].[Id]
INNER JOIN [dbo].[AddressBookEntries] AS [Extent3] ON
[Extent1].[FromAddressBookEntryId] = [Extent3].[Id]
WHERE ([Extent2].[Username] = #p__linq__0) AND
([Extent3].[WhiteList] = 1)) AS [Project1]
ORDER BY [Project1].[EmailSendFinishTime] DESC',N'#p__linq__0 nvarchar(4000)
',#p__linq__0=N'ekellner9
EmailDetail Definition and AddressBookEntry Definition
public class EmailDetail
{
public EmailDetail()
{
// keep sqlserver from blowing up with no datetime set
EmailSendStartTime = new DateTime(1900, 1, 1);
EmailSendFinishTime = new DateTime(1900, 1, 1);
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[ForeignKey("User")]
public long UserId { get; set; }
[Required(ErrorMessage = "Must have user associted with EmailDetail")]
public User User { get; set; }
public long? FromAddressBookEntryId { get; set; }
public AddressBookEntry FromAddressBookEntry { get; set; }
public DateTime EmailSendStartTime { get; set; }
public DateTime EmailSendFinishTime { get; set; }
}
public class AddressBookEntry
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[ForeignKey("User")]
public long UserId { get; set; }
[Required]
public User User { get; set; }
[MaxLength(512)]
[Required(ErrorMessage = "Email is required")]
public string Email { get; set; }
}
I'm not getting the same results as you. Using the following console app:
public class EmailDetail
{
public EmailDetail()
{
// keep sqlserver from blowing up with no datetime set
EmailSendStartTime = new DateTime(1900, 1, 1);
EmailSendFinishTime = new DateTime(1900, 1, 1);
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[ForeignKey("User")]
public long UserId { get; set; }
[Required(ErrorMessage = "Must have user associted with EmailDetail")]
public User User { get; set; }
public long? FromAddressBookEntryId { get; set; }
public AddressBookEntry FromAddressBookEntry { get; set; }
public DateTime EmailSendStartTime { get; set; }
public DateTime EmailSendFinishTime { get; set; }
}
public class AddressBookEntry
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[ForeignKey("User")]
public long UserId { get; set; }
[Required]
public User User { get; set; }
[MaxLength(512)]
[Required(ErrorMessage = "Email is required")]
public string Email { get; set; }
public bool WhiteList { get; set; }
}
public class User
{
public long UserId { get; set; }
public string Username { get; set; }
}
public class CFContext : DbContext
{
public DbSet<AddressBookEntry> AddressBookEntries { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<EmailDetail> EmailDetails { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
class Program
{
static void Main(string[] args)
{
var db = new CFContext();
var y = (from data1 in db.EmailDetails
join data2 in db.AddressBookEntries on data1.FromAddressBookEntryId equals data2.Id
orderby data1.EmailSendFinishTime descending
select data1.EmailSendFinishTime).FirstOrDefault();
string username = "1";
var x = db.EmailDetails.Where(a => a.User.Username == username && a.FromAddressBookEntry.WhiteList).
Select(a => new
{
a.EmailSendFinishTime
}).
OrderByDescending(
a => a.EmailSendFinishTime)
.FirstOrDefault();
Console.WriteLine(y);
Console.WriteLine(x);
}
}
I got these SQL queries
SELECT TOP (1)
[Extent1].[EmailSendFinishTime] AS [EmailSendFinishTime]
FROM [dbo].[EmailDetails] AS [Extent1]
WHERE [Extent1].[FromAddressBookEntryId] IS NOT NULL
ORDER BY [Extent1].[EmailSendFinishTime] DESC
SELECT TOP (1)
[Project1].[C1] AS [C1],
[Project1].[EmailSendFinishTime] AS [EmailSendFinishTime]
FROM ( SELECT
[Extent1].[EmailSendFinishTime] AS [EmailSendFinishTime],
1 AS [C1]
FROM [dbo].[EmailDetails] AS [Extent1]
INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[UserId]
INNER JOIN [dbo].[AddressBookEntries] AS [Extent3] ON [Extent1].[FromAddressBookEntryId] = [Extent3].[Id]
WHERE ([Extent2].[Username] = #p__linq__0) AND ([Extent3].[WhiteList] = 1)
) AS [Project1]
ORDER BY [Project1].[EmailSendFinishTime] DESC
Is there anything else in your model, or maybe there's something else making the SQL query above?
I have the following classes. I have a object var of Description class. I want to select Balance related to the Client provided in the var object using Linq to Sql or Lambda expression. How to join these tables to get the Balance from Account table?
public class Description
{
public int DescriptionID { get; set; }
// Attributes
public int ClientID { get; set; }
[ForeignKey("ClientID")]
public virtual Client Client { get; set; }
}
public class Client
{
public int ClientID { get; set; }
// Attributes
public int UserID { get; set; }
[ForeignKey("UserID")]
public virtual User User { get; set; }
}
public class User
{
public int UserID { get; set; }
// Attributes
}
public class Account
{
public int AccountID { get; set; }
[Required, Column("Balance"), Display(Name = "Account Balance")]
public double Balance { get; set; }
public int UserID { get; set; }
[ForeignKey("UserID")]
public virtual User User { get; set; }
}
You could try this:
var balance = (from a in context.Accounts
join c in context.Clients on a.UserID equals c.UserID
where c.ClientID == yourDescriptionObject.ClientID
select a.Balance)
.SingleOrDefault();
Or - if you only have the DescriptionID:
var balance = (from a in context.Accounts
join c in context.Clients on a.UserID equals c.UserID
join d in context.Descriptions on c.ClientID equals d.ClientID
where d.DescriptionID == yourDescriptionID
select a.Balance)
.SingleOrDefault();
(Or FirstOrDefault() or ToList() or Sum()? Because your model would allow that clients/descriptions are related to multiple accounts ...)