How to provide SQL subquery in LINQ - c#

What is the best practice to convert Sub Query into LINQ,
for example I use this following query :
select VerID = (select top 1 x.INTERNALPACKINGSLIPID from
CUSTPACKINGSLIPVERSION x where a.RECID = x.CUSTPACKINGSLIPJOUR
order by x.VERSIONDATETIME desc),
c.LINENUM, c.RECID, *
from CUSTPACKINGSLIPJOUR a inner join CUSTPACKINGSLIPTRANS c
on a.PACKINGSLIPID = c.PACKINGSLIPID

I simulated you database with classes to get the syntax correct. Make modifications as necessary. There is no best method. Some people like using Where instead of joins. I like joins.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<CUSTPACKINGSLIPVERSIONs> CUSTPACKINGSLIPVERSION = new List<CUSTPACKINGSLIPVERSIONs>();
List<CUSTPACKINGSLIPJOURs> CUSTPACKINGSLIPJOUR = new List<CUSTPACKINGSLIPJOURs>();
List<CUSTPACKINGSLIPTRANSs> CUSTPACKINGSLIPTRANS = new List<CUSTPACKINGSLIPTRANSs>();
var VerId = (from vId in CUSTPACKINGSLIPVERSION
join slipId in CUSTPACKINGSLIPJOUR on vId.INTERNALPACKINGSLIPID equals slipId.RECID
join cId in CUSTPACKINGSLIPTRANS on vId.INTERNALPACKINGSLIPID equals cId.PACKINGSLIPID
select new { vid = vId, slipId = slipId, cId = cId })
.GroupBy(x => x.vid.VERSIONDATETIME)
.OrderBy(x => x.Key)
.FirstOrDefault()
.Select(x => new { linenum = x.cId.LINENUM, recid = x.cId.RECID })
.ToList();
}
}
public class CUSTPACKINGSLIPVERSIONs
{
public int INTERNALPACKINGSLIPID { get; set; }
public DateTime VERSIONDATETIME { get; set; }
}
public class CUSTPACKINGSLIPJOURs
{
public int RECID { get; set; }
public int PACKINGSLIPID { get; set; }
}
public class CUSTPACKINGSLIPTRANSs
{
public int PACKINGSLIPID { get; set; }
public int LINENUM { get; set; }
public int RECID { get; set; }
}
}

You have this in your query and I am assuming it is a typo: a.RECID = x.CUSTPACKINGSLIPJOUR because CUSTPACKINGSLIPJOUR is the collection name. Therefore, I used SomeId instead. But this should give you the idea:
Do a subquery within the projection. You will also need to order by descending and then take the first record-this will be like top 1. Here is the query:
var query = from a in CUSTPACKINGSLIPJOUR
join c in CUSTPACKINGSLIPTRANS on a.PACKINGSLIPID equals c.PACKINGSLIPID
select new
{
VerID = (from x in CUSTPACKINGSLIPVERSION
where a.RECID == x.SomeId select x)
.OrderByDescending(o => o.VERSIONDATETIME)
.First().INTERNALPACKINGSLIPID,
c.LINENUM,
c.RECID
};
You can test it with the following collections:
var CUSTPACKINGSLIPJOUR = new List<CUSTPACKINGSLIPJOUR> { new CUSTPACKINGSLIPJOUR { PACKINGSLIPID = 1, RECID = 1 },
new CUSTPACKINGSLIPJOUR { PACKINGSLIPID = 2, RECID = 2 }};
var CUSTPACKINGSLIPTRANS = new List<CUSTPACKINGSLIPTRANS>
{
new CUSTPACKINGSLIPTRANS { LINENUM = 1, RECID = 1, PACKINGSLIPID = 1 }
};
var CUSTPACKINGSLIPVERSION = new List<CUSTPACKINGSLIPVERSION>
{
new CUSTPACKINGSLIPVERSION { INTERNALPACKINGSLIPID = 1, SomeId = 1, VERSIONDATETIME = DateTime.Today.AddDays(-1) },
new CUSTPACKINGSLIPVERSION { INTERNALPACKINGSLIPID = 2, SomeId = 1, VERSIONDATETIME = DateTime.Today }
};
It will be the same query if you use a DbSet<T>.

Suppose you have those setup:
public class TBL_CUSTPACKINGSLIPVERSION
{
public int CUSTPACKINGSLIPVERSION_ID { get; set; }
public int INTERNALPACKINGSLIPID { get; set; }
public DateTime VERSIONDATETIME { get; set; }
}
public class TBL_CUSTPACKINGSLIPJOUR
{
public int RECID { get; set; }
public int PACKINGSLIPID { get; set; }
}
public class TBL_CUSTPACKINGSLIPTRANS
{
public int PACKINGSLIPID { get; set; }
public int LINENUM { get; set; }
public int RECID { get; set; }
}
var CUSTPACKINGSLIPVERSION = new List<TBL_CUSTPACKINGSLIPVERSION>();
var CUSTPACKINGSLIPJOUR = new List<TBL_CUSTPACKINGSLIPJOUR>();
var CUSTPACKINGSLIPTRANS = new List<TBL_CUSTPACKINGSLIPTRANS>();
Then you can setting up the combined query as given in example below (assumed CUSTPACKINGSLIPVERSION_ID is the identity key which used in comparison between CUSTPACKINGSLIPJOUR & CUSTPACKINGSLIPTRANS):
var query = (from a in CUSTPACKINGSLIPJOUR
join c in CUSTPACKINGSLIPTRANS
on a.PACKINGSLIPID equals c.PACKINGSLIPID
select new {
VerID = (from x in CUSTPACKINGSLIPVERSION
where a.RECID == x.CUSTPACKINGSLIPVERSION_ID // should be an identity column/primary key to compare with
orderby x.VERSIONDATETIME descending
select x).FirstOrDefault().INTERNALPACKINGSLIPID,
c.LINENUM,
c.RECID
}).ToList();
Note that your query includes * at the end of SELECT statement which may indicate the query will return all records from both tables involved in join clause. If you want to return entire records of CUSTPACKINGSLIPJOUR only but not return all CUSTPACKINGSLIPTRANS, include a into the select new statement (incorporates SQL usage of a.*):
select new {
VerID = (from x in CUSTPACKINGSLIPVERSION
where a.RECID == x.CUSTPACKINGSLIPVERSION_ID // should be an identity column/primary key to compare with
orderby x.VERSIONDATETIME descending
select x).FirstOrDefault().INTERNALPACKINGSLIPID,
c.LINENUM,
c.RECID,
a // used if you want to return all records from CUSTPACKINGSLIPJOUR
}).ToList();

Related

How to add table my join tables? ASP.NET MVC

My question is, inside my join of IDs, is it possible to add another column with an ID?
This is what I am trying to do:
My Index:
var orders= db.Orders.ToList();
var colers = db.Colors.ToList();
var result = (from c in orders
join st in colers on c.ID_Orders equals st.id into table1
select new OrderWithColorsViewModel { order =c, colers = table1.ToList()
}).ToList();
return View(result);
My classes:
public partial class Orders
{
public int ID_Orders { get; set; }
public Nullable<System.DateTime> Data_Registo { get; set; }
public string Num_Encomenda { get; set; }
public string Ref_Cliente { get; set; }
}
public partial class Colors
{
public int ID_Orders { get; set; }
public int ID_Line_Color { get; set; }
public string Color{ get; set; }
}
public partial class Quantities
{
public int ID_Orders { get; set; }
public int ID_Line_Color { get; set; }
public int quantity{ get; set; }
}
Of what I am learning right now I have this from my join:
and:
But what I want (I think):
If i am wrong in thinking, correct me, thanks
I leave my solution here for those who need it
var result1 = (from o in order
join c in coler
on o.ID_Programa equals c.ID_Programa into co
group new { o, co } by o.ID_Programa into g
from i in g
select new { order = i.o, colors = i.co }).ToList();
var result2 = (from r1 in result1
from c in r1.colors
join q in quant
on new { orderId = c.ID_Programa, colorlineId = c.ID_Linha_Cor } equals new { orderId = q.ID_Programa, colorlineId = q.ID_Linha_Cor } into p1
from p in p1
join s in statu
on new { orderId = p.ID_Programa, colorlineId = p.ID_Linha_Cor } equals new { orderId = s.ID_Programa, colorlineId = s.ID_Linha_Cor } into q
group new ColorsAndQuantities { coler = c, quant = p1.ToList(), status = q.ToList() } by c.ID_Programa).ToList();
var result = (from r1 in result1
join m in fabric
on r1.order.ID_Programa equals m.ID_Programa into t
from t1 in t
join r2 in result2
on t1.ID_Programa equals r2.Key
select new OrdersColorsViewModel
{
order = r1.order,
malhas = t1,
colers = r2.ToList()
}).ToList();

C# how to achieve 'group by' 'left join' and list inside a list selection in linq

var products = from P in product.GetAllAsync().Result
join PV in
_repositoryVariation.GetAllAsync().Result on P.Id equals PV.ProductId
into PVLJ
from PV in PVLJ.DefaultIfEmpty()
select new ProductwithVarientsGroupDto
{
Label = P.ProductName,
ProductId = P.Id,
Items = new List<ProdcutVariantsdto>() { new ProdcutVariantsdto { Label = P.ProductName.ToString() + (PV == null ? "" : " (" + PV?.VariantName.ToString() + ")"), ProductId = P.Id, ProdVariantId = PV?.Id > 0 ? PV?.Id : 0 } }
//here i need to add multiple variant records to Items, now it
// showing each item as a separate row data
};
var result = products.ToList();
return result;
The following query will work. After you left joined the data, just switch to client-evaluation (using AsEnumerable() or ToList()) and do the actual grouping with Linq. EF Core will not be able to do a Linq style grouping on its own and the data is being retrieved anyway, so there is no downside doing it client-side:
var products = (from p in context.Products
join v in
context.ProductVariations on p.Id equals v.ProductId
into g
from v in g.DefaultIfEmpty()
select new {product = p, variation = v})
.AsEnumerable() // <-- switch to client-evaluation
.GroupBy(g => g.product, g => g.variation)
.Select(g => new ProductwithVarientsGroupDto
{
Label = g.Key.ProductName,
ProductId = g.Key.Id,
Items = g.Select(v => new ProdcutVariantsdto()
{
Label = g.Key.ProductName + (v == null
? ""
: " (" + v.VariantName.ToString() + ")"),
ProductId = g.Key.Id,
ProdVariantId = v.Id > 0
? v.Id
: 0
}).ToList()
});
As #PanagiotisKanavos already mentioned in the comments, your original code first retrieves all entities from the database and then executes your query on them in memory. If you want to keep doing that, just replace context.Products with product.GetAllAsync().Result and context.ProductVariations with _repositoryVariation.GetAllAsync().Result. You could then also drop the AsEnumerable(), because you are already processing the query client-side.
Here is the fully working sample console project I used for testing:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public class Product
{
public int Id { get; set; }
public string ProductName { get; set; }
}
public class ProductVariation
{
public int Id { get; set; }
public int ProductId { get; set; }
public string VariantName { get; set; }
}
public class ProductwithVarientsGroupDto
{
public string Label { get; set; }
public int ProductId { get; set; }
public List<ProdcutVariantsdto> Items = new List<ProdcutVariantsdto>();
}
public class ProdcutVariantsdto
{
public string Label { get; set; }
public int ProductId { get; set; }
public int? ProdVariantId { get; set; }
}
public class Context : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<ProductVariation> ProductVariations { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(
#"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So63031344")
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>().HasData(
new Product {Id = 1, ProductName = "Car"},
new Product {Id = 2, ProductName = "Bus"});
modelBuilder.Entity<ProductVariation>().HasData(
new ProductVariation {Id = 1, ProductId = 1, VariantName = "Minivan"},
new ProductVariation {Id = 2, ProductId = 1, VariantName = "Convertible"},
new ProductVariation {Id = 3, ProductId = 2, VariantName = "Public Transportation"},
new ProductVariation {Id = 4, ProductId = 2, VariantName = "Shuttle"});
}
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var products = (from p in context.Products
join v in
context.ProductVariations on p.Id equals v.ProductId
into g
from v in g.DefaultIfEmpty()
select new {product = p, variation = v})
.AsEnumerable()
.GroupBy(g => g.product, g => g.variation)
.Select(g => new ProductwithVarientsGroupDto
{
Label = g.Key.ProductName,
ProductId = g.Key.Id,
Items = g.Select(v => new ProdcutVariantsdto()
{
Label = g.Key.ProductName + (v == null
? ""
: " (" + v.VariantName.ToString() + ")"),
ProductId = g.Key.Id,
ProdVariantId = v.Id > 0
? v.Id
: 0
}).ToList()
});
var result = products.ToList();
Debug.Assert(result.Count == 2);
Debug.Assert(result[0].ProductId == 1);
Debug.Assert(result[0].Items.Count == 2);
Debug.Assert(result[0].Items[0].ProdVariantId == 1);
}
}
}

Nested Select in Join and Partition By

i am very new in C# and i want write this TSql Code in Linq.plz help. thank you
select a.Id,
a.Date,
b.Title CategoryTitle,
a.Title,
a.Description,
a.Image
from (select *,
ROW_NUMBER() over(partition by CategoryID order by Date) rankno
from News) a
join Categories b on a.CategoryID = b.Id
where rankno <= 5
Assuming you have enumerables for News and Categories:
var results = News.Join(Categories, // Join News and Categories
a => a.CatergoryId,
b => b.Id,
(a,b) => new { News = a, Category = b}
)
.GroupBy(c => c.Category) // "partition by categoryId"
.SelectMany(g => g.OrderBy(gd => gd.News.CreationDate) // "order by Date"
.Take(5) // RankNo <= 5
.Select(gdd => new { // results
Id = gdd.News.Id,
Date = gdd.News.Date,
CategoryTitle = gdd.Category.Title,
Title = gdd.News.Title,
Description = gdd.News.Description,
Image = gdd.News.Image
})
);
I modeled your database using classes to get syntax correct. See code below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication93
{
class Program
{
static void Main(string[] args)
{
Context dbContext = new Context();
var results = (from n in dbContext.news
join c in dbContext.category.OrderBy(x => x.Date) on n.Id equals c.Id
select new { news = n, category = c})
.Select((x,i) => new { Date = x.news.Date, CategoryTitle = x.category.Title, Title = x.news.Title, Description = x.news.Description, Image = x.news.Image, RankNo = i})
.ToList();
}
}
public class Context
{
public List<News> news { get; set; }
public List<Category> category { get; set; }
}
public class News
{
public int Id { get; set; }
public DateTime Date { get; set; }
public string Title { get;set;}
public string Description { get;set;}
public byte[] Image { get;set;}
}
public class Category
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime Date { get; set; }
}
}

Unable to convert AnonymousType#1 ti IEnumerable

I have declared a model in my .cs page
public class InstrumentDetails
{
public long PullNo { get; set; }
public string Description { get; set; }
public int New { get; set; }
public int LN { get; set; }
public int PR { get; set; }
public int Any { get; set; }
}
After that i am retrieving data like this way :
IEnumerable<InstrumentDetails> instrumentdetails = (from p in NemcDb.tblPulls
join
pi in NemcDb.tblPullInstruments
on
p.PullId equals pi.PullId
join
i in NemcDb.tblInstruments
on
pi.InstrumentCode equals i.InstrumentCode
select new
{
PullNo = p.PullNo.Value,
InstrumentType = i.Description,
New = pi.NewQuantity,
LN = pi.LNQuantity,
PR = pi.UsedQuantity,
Any = pi.AnyQuantity
}).Where(i => i.PullNo.ToString() == item);
But it gives me the error
Cannot convert 'System.Linq.IQueryable<AnonymousType#1>' to 'System.Collections.Generic.IEnumerable<>'. An explicit conversion exists (are you missing a cast?)
Where am I wrong?...I couldn't get it through....Please help.
You don't tell that you want an object of type InstrumentDetails, you create an anonymous type. Change select new { ... into select new InstrumentDetails { ... and then also call ToList(), ToEnumerable() or ToArray() in the end so the query is actually run.
The answer would be :
IEnumerable<InstrumentDetails> instrumentdetails = (from p in NemcDb.tblPulls
join
pi in NemcDb.tblPullInstruments
on
p.PullId equals pi.PullId
join
i in NemcDb.tblInstruments
on
pi.InstrumentCode equals i.InstrumentCode
select new InstrumentDetails
{
PullNo = p.PullNo.Value,
InstrumentType = i.Description,
New = pi.NewQuantity,
LN = pi.LNQuantity,
PR = pi.UsedQuantity,
Any = pi.AnyQuantity
}).Where(i => i.PullNo.ToString() == item).ToList();
}
How Silly of me............

ASP.NET MVC 5 Entity Join

I'm new in ASP, Entity and lambda expressions. How can I join two tables?
Route Model:
public partial class Route
{
public Route()
{
Flights = new HashSet<Flight>();
}
public int RouteID { get; set; }
public int DepartureAirportID { get; set; }
public int ArrivalAirportID { get; set; }
public int FlightDuration { get; set; }
public virtual Airport Airport { get; set; }
public virtual Airport Airport1 { get; set; }
public virtual ICollection<Flight> Flights { get; set; }
}
Airport Model:
public partial class Airport
{
public Airport()
{
Routes = new HashSet<Route>();
Routes1 = new HashSet<Route>();
}
public int AirportID { get; set; }
public string City { get; set; }
public string Code { get; set; }
public virtual ICollection<Route> Routes { get; set; }
public virtual ICollection<Route> Routes1 { get; set; }
}
SQL query looks like this:
SELECT a.AirportID, a.City
FROM Route r INNER JOIN Airport a ON r.ArrivalAirportID = a.AirportID
WHERE r.DepartureAirportID = #departureAirportID
ORDER BY a.City
Sorry for this easy question but I don't know how to do this with Entity Framework...
Something like this should do (untested and just going on from your query) with a variable hard-coded):
using (var db = new YourDbContext())
{
var query = from r in db.Route
join a in db.Airport a on r.ArrivalAirportID equals a.AirportID
where r.DepartureAirportID = 1 // replace with your varialble.
orderby a.City
select a;
}
Include with join entity framework. here doctorSendAnswerModel also a inner table.
var data = _patientaskquestionRepository.Table.Include(x=>x.DoctorSendAnswer).Join(_patientRepository.Table, a => a.PatientId, d => d.Id, (a, d) => new { d = d, a = a }).Where(x => x.a.DoctorId == doctorid);
if(!string.IsNullOrEmpty(status))
data=data.Where(x=>x.a.Status==status);
var result = data.Select(x => new {x= x.a,y=x.d }).ToList();
var dt = result.Select(x => new PatientAskQuestionModel()
{
PatientId = x.x.PatientId.Value,
AskQuestion = x.x.AskQuestion,
Id = x.x.Id,
DoctorId = x.x.DoctorId,
FileAttachment1Url = x.x.FileAttachment1,
DocName = x.y.FirstName + " " + x.y.LastName,
CreatedDate = x.x.CreatedDate.Value,
doctorSendAnswerModel = x.x.DoctorSendAnswer.Select(t => new DoctorSendAnswerModel { Answer = t.Answer }).ToList()
}).ToList();
return dt;
LinQ query:
from r in context.Route
join a in context.Airport
on r.ArrivalAirportID equals a.AirportID
WHERE r.DepartureAirportID = "value"
ORDER BY a.City
select a.AirportID, a.City
var balance = (from a in context.Airport
join c in context.Route on a.ArrivalAirportID equals c.AirportID
where c.DepartureAirportID == #departureAirportID
select a.AirportID)
.SingleOrDefault();
You can do the following:
var matches = from a in context.Airports
join r in context.Routes
on a.AirportID equals r.ArrivalAirportID
where r.DepartureAirportID = departureAirportID
order by a.City
select new
{
a.AirportID,
a.City
};
Entity query with conditional join with pagination.
if (pageIndex <= 0)
pageIndex = 1;
pageIndex = ((pageIndex - 1) * pageSize) ;
var patient = _patientRepository.Table.Join(_DoctorPatient.Table.Where(x => x.DoctorId == Id && x.IsBlocked==false), x => x.Id, d => d.PatientId, (x, d) => new { x = x });
if (state != "")
patient = patient.Where(x => x.x.State.Contains(state));
if (name != "")
patient = patient.Where(x => (x.x.FirstName + x.x.LastName).Contains(name));
if (sdate != null)
patient = patient.Where(x => x.x.CreatedDate >= sdate);
if (eDate != null)
patient = patient.Where(x => x.x.CreatedDate <= eDate);
var result = patient.Select(x => x.x).Select(x => new PatientDoctorVM() { PatientId = x.Id, Id = x.Id, FirstName = x.FirstName, LastName = x.LastName, SSN = x.NewSSNNo, UserProfileId = x.UserProfileId, Email = x.Email, TumbImagePath = x.TumbImagePath }).OrderBy(x => x.Id).Skip(pageIndex).Take(pageSize).ToList();
Your entity and lembda query will be lool like this:
return (from d in _doctorRepository.Table
join p in _patientDoctor.Table on d.Id equals p.DoctorId
where p.PatientId == patientid.Value select d
).ToList();
Take a look at this site, it will explain you how the join works in Linq.
So if you ever need it again you will be able to solve it yourself.

Categories