Linq Many to Many query - linq

I need help to query this three tables. RentCommunityFeature and RentPropertyFeature has a many to many relationship with RentUnitListing. My problem is i can't get these three tables to query. What i want is all those rentlistings that has certain features. for example if RentCommunityFeature has a "pool" and RentPropertyFeature has a "parking", i want all the records in RentUnitListing that has "Pool" and "Parking". If no parking than result should show only with "Pool".
I tried the below query but it gives incorrect results. It shows duplicate results when myCommunityFeatureId or myPropertyFeatureId is -1. I have initializes them to -1 if they are empty in DB.
Any help would be greatly appreciated.
var AllAds = from r in _db.RentUnitListings
from cf in r.RentCommunityFeatures
from pf in r.RentPropertyFeatures
where (myCommunityFeatureId > 0) ? (cf.RentCommunityFeatureID == myCommunityFeatureId && cf.RentUnitListings.) : (myCommunityFeatureId == -1)
where (myPropertyFeatureId > 0) ? (pf.RentPropertyFeatureID == myPropertyFeatureId) : (myPropertyFeatureId == -1)
select r;
public partial class RentCommunityFeature
{
public int RentCommunityFeatureID { get; set; }
public string RentCommunityFeatureDescription { get; set; }
public virtual ICollection<RentUnitListing> RentUnitListings { get; set; }
}
public partial class RentPropertyFeature
{
public int RentPropertyFeatureID { get; set; }
public string RentPropertyFeatureDescription { get; set; }
public virtual ICollection<RentUnitListing> RentUnitListings { get; set; }
}
public partial class RentUnitListing
{
public Guid RentUnitListingID { get; set; }
public string RentUnitListingShortDescription { get; set; }
public virtual ICollection<RentCommunityFeature> RentCommunityFeatures { get; set; }
public virtual ICollection<RentPropertyFeature> RentPropertyFeatures { get; set; }
}

var listings = _db.RentUnitListings
.Where(rul => rul.RentCommunityFeatures
.Any(rcf => rcf.RentCommunityFeatureID == myCommunityFeatureId)
|| rul.RentPropertyFeatures
.Any(rpf => rpf.RentPropertyFeatureID == myPropertyFeatureId))
.ToList();
It means: Return all listings that have at least one (Any) RentCommunityFeature with the myCommunityFeatureId OR at least one (Any) RentPropertyFeature with the myPropertyFeatureId. The "OR" is not exclusive, so a returned listing may have a "Pool" without a "Parking" feature or a "Parking" without a "Pool" feature or it might have both. In any case a returned listing might have a lot of other features in addition to "Pool" or "Parking".

Related

SQL query with Group By and Having Clause in LINQ structure

how do I write this query in LINQ (c# EF6)?
Can someone please help me here - I am new to Entity Framework Structure - So bit hard for me to use different clauses
SELECT
sum(remainingamount) TotalSiteCreditAmount,
max(expirationutcdatetime) MaxExpiryDate
FROM
WholesaleCredits
WHERE
ExpirationUTCDateTime > Getdate()
GROUP BY
registeredcustomerid,
siteid
HAVING
registeredcustomerid = :registeredCustomerId
AND siteid = :siteId
Tried below thing as of now :
var data = context.WholesaleCredit
.Where(x => x.ExpirationUTCDateTime > DateTime.Now)
.GroupBy (x => x.RegisteredCustomerId)
Entity Used in code:
public partial class WholesaleCredits
{
public virtual int Id { get; set; }
public virtual decimal CreditAmount { get; set; }
public virtual decimal RemainingAmount { get; set; }
public virtual Site Site { get; set; }
public virtual DateTime GeneratedUTCDateTime { get; set; }
public virtual DateTime ExpirationUTCDateTime { get; set; }
public virtual int RegisteredCustomerId { get; set; }
}
You do not need HAVING here and Grouping should be provided by constant, because you have filter on grouping keys:
var data = context.WholesaleCredit
.Where(x => x.ExpirationUTCDateTime > DateTime.Now && x.RegisteredCustomerId == registeredCustomerId && x.Site.Id == siteid)
.GroupBy(x => 1)
.Select(g => new
{
TotalSiteCreditAmount = g.Sum(x => x.RemainingAmount),
MaxExpiryDate = g.Max(x => x.ExpirationUTCDateTime)
})
.First();

Selecting single element from each group that cointains maximum DateTime value

model :
public class ReferenceParameterHistory
{
[Key]
public int IDReferenceParameterHistory { get; set; }
public double Value { get; set; }
public string Value_S { get; set; }
public DateTimeOffset CreatedAt { get; set; }
[Required]
public bool IsStable { get; set; }
public int? IDReference { get; set; }
public Reference Reference { get; set; }
[Required]
public int IDParameterTemplate { get; set; }
public ParameterTemplate ParameterTemplate { get; set; }
}
My code in ASP.NET core controller :
[HttpGet]
public async Task<IActionResult> GetReferenceParameterHistory(int? IDparameterTemplate,
int? IDreference,
DateTimeOffset? startDate,
DateTimeOffset? endDate,
bool latestOnly)
{
try
{
IQueryable<ReferenceParameterHistory> query = _context.ReferenceParameterHistory.OrderByDescending(rph => rph.IDReferenceParameterHistory);
if (IDparameterTemplate != null && IDparameterTemplate > 0)
query = query.Where(rph => rph.IDParameterTemplate == IDparameterTemplate);
if (IDreference != null && IDreference > 0)
query = query.Where(rph => rph.IDReference == IDreference);
if (startDate != null)
query = query.Where(rph=> rph.CreatedAt >= startDate);
if (endDate != null)
query = query.Where(rph => rph.CreatedAt <= endDate);
if (latestOnly)
{
// I tried this but it doesnt compile and I don't have idea how to solve this ....
//query = (from rph in query
// group rph by rph.IDParameterTemplate
// into groups
// where groups.Max(rph => rph.CreatedAt)
// select groups.Key);
}
var referenceParameterHistory = await query.AsNoTracking().ToListAsync();
if (referenceParameterHistory.Any())
return new ObjectResult(referenceParameterHistory);
return new NotFoundResult();
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new StatusCodeResult(500);
}
}
I have a database table based on that ReferenceParameterHistory model class. I want to group records exctracted from that table by IDParameterTemplate and from each group I need to extract records that have the highest value in CreatedAt column (latest records). So each group contains many recods but I need to get only these with max value in CreatedAt column. The result should be IEnumerable of ReferenceParameterHistory since I store that query in an IQueryable variable and then send it to SQL Server to process the query. Commented code in my example is just what I tried but I don't know how to do that.
How can I solve that problem ?
You reused the variable rph inside the lambda.
How to select only the records with the highest date in LINQ
query = (from rph in query
group rph by rph.IDParameterTemplate into g
select g.OrderByDescending(t=>t.CreatedAt).FirstOrDefault());

KendoUI Scheduler

I am trying to implement the scheduler control to show live calculation of material usage on daily bases (in a week by week view).
I am unable to have the Usage data displayed in the cells although I managed to have to Materials displayed on the left hand side. I wonder if any one could help or give me some hints on what I am doing wrong. Here is my code so far:
I can be sure that data is being return to the view but the view is not showing the usage data, which is simply numeric values corresponding to a material on a specific day of the week. I have also attached a screenshot of how it looks like:
the Controller method to read the data:
public JsonResult Read([DataSourceRequest] DataSourceRequest request)
{
try
{
var usageList = new List<ReportUsageViewModel>();
var imports = _importRespository.GetImports();
foreach (var usageReportStoredProcedure in imports)
{
var usageViewModel = new ReportUsageViewModel();
usageViewModel.MaterialID = usageReportStoredProcedure.MaterialID;
usageViewModel.Start = usageReportStoredProcedure.ScanDate;
usageViewModel.End = usageReportStoredProcedure.ScanDate;
usageViewModel.DailyUsage = usageReportStoredProcedure.UsageQuantity;
usageViewModel.Title = usageReportStoredProcedure.UsageQuantity.ToString();
usageList.Add(usageViewModel);
}
return Json(usageList.ToDataSourceResult(request));
}
catch (Exception exc)
{
ErrorHelper.WriteToEventLog(exc);
return null;
}
}
The actual control
<div id="StockViewer">
#(Html.Kendo().Scheduler<WorcesterMarble.ViewModels.ReportUsageViewModel>()
.Name("StockViewer")
.Timezone("Europe/London")
.Resources(resource => resource.Add(m => m.MaterialID)
.Title("Materials")
.Name("Materials")
.DataTextField("Name")
.DataValueField("MaterialID")
.BindTo(Model.MaertiaList))
.MajorTick(270)
.MinorTickCount(1)
.StartTime(DateTime.Now.Date.AddHours(8))
.EndTime(DateTime.Now.Date.AddHours(17))
.AllDaySlot(false)
.Date(DateTime.Now.Date)
.Editable(false)
.Views(x => x.WeekView(v =>
{
v.Footer(false);
v.Selected(true);
v.DateHeaderTemplate("<span class='k-link k-nav-day'>#=kendo.toString(date, 'ddd dd/M')#</span>");
}))
.Group(group => group.Resources("Materials").Orientation(SchedulerGroupOrientation.Vertical))
.DataSource(d => d
.Model(m => {
m.Id(f => f.MaterialID);
m.Field(f => f.Title).DefaultValue("No title");
})
.Read("Read", "ReportUsage")
)
)
Update: This is the ViewModel implementing the ISchedulerEvent
public class ReportUsageViewModel : ISchedulerEvent
{
public int MaterialID { get; set; }
public string MaterialName { get; set; }
public int? DailyUsage { get; set; }
public List<MaterialViewModel> MaertiaList { get; set; }
public string Description { get; set; }
public System.DateTime End { get; set; }
public bool IsAllDay { get; set; }
public string RecurrenceException { get; set; }
public string RecurrenceRule { get; set; }
public System.DateTime Start { get; set; }
public string Title { get; set; }
}
The issue was in these two lines:
.StartTime(DateTime.Now.Date.AddHours(8))
.EndTime(DateTime.Now.Date.AddHours(17))
The data was there but these two lines were hiding it. The data was being logged at times outside the time range of 8 to 17 so I removed these two lines and then set the Major ticks to 1440, which is the total number of ticks in 24 hrs, which helped me hiding the time column as I didn't need it..

ASP.Net MVC converting Sql to Linq

I'm updating an old app, to use EF and Linq. I'm having trouble with one of the queries - in SQL it is:
SELECT id, type_id, rule_name, rule_start, rule_end, rule_min
FROM Rules
WHERE (rule_min > 0)
AND (rule_active = 1)
AND (rule_fri = 1)
AND ('2012-01-01' BETWEEN rule_start AND rule_end)
AND (id IN
(SELECT rule_id
FROM RulesApply
WHERE (type_id = 3059)))
ORDER BY pri
So far I have:
var rules = db.Rules.Include("RulesApply")
.Where(t => (t.rule_active == 1)
&& (t.rule_min > 0)
&& (dteFrom >= t.rule_start && dteFrom <= t.rule_end)
&& (this is where I'm stuck)
)
.OrderBy(r => r.pri);
It's the last subquery I'm stuck with adding into the LINQ above:
AND (id IN
(SELECT rule_id
FROM RulesApply
WHERE (type_id = 3059)))
Models are:
public class Rule
{
[Key]
public Int64 id { get; set; }
public Int64 hotel_id { get; set; }
public byte rule_active { get; set; }
public DateTime rule_start { get; set; }
public DateTime rule_end { get; set; }
public int rule_min { get; set; }
public int pri { get; set; }
public virtual ICollection<RuleApply> RulesApply { get; set; }
}
public class RuleApply
{
[Key, Column(Order = 0)]
public Int64 type_id { get; set; }
[Key, Column(Order = 1)]
public Int64 rule_id { get; set; }
[ForeignKey("rule_id")]
public virtual Rule Rule { get; set; }
}
Can anyone please help me complete this query?
Thank you,
Mark
Try doing this:
var rules = db.Rules.Include("RulesApply")
.Where(t => (t.rule_active == 1)
&& (t.rule_min > 0)
&& (dteFrom >= t.rule_start && dteFrom <= t.rule_end)
&& t.RulesApply.Any(a => a.type_id == 3059)
.OrderBy(r => r.pri);
If t.RulesApply is illegal (i.e. doesn't compile), then replace it with the correct reference to the navigation property found on your Rules object that points to the RulesApply object.
If you have set up navigational properties between the entities, you can navigate from one to the other:
//This gets the RulesApply object
var rulesapply = db.RulesApply.Single(x=> x.type_id == 3059);
//This gets all Rules connected to the rulesapply object through its navigational property
var rules = rulesapply.Rules;
//You can use LINQ to further refine what you want
rules = rules.Where( x=> /* and so on...*/ );
You can stack these statements together on a single line, I only split them up for readability purposes :)

Append OR subquery in Linq

I am trying to build a simple search against some entities (EF4, if that makes any difference). Passed into my search query is a list of criteria objects. The crieteria object looks like this:
public class ClaimSearchCirtieria
{
public Guid? FinancialYear { get; set; }
public bool AllClaimants { get; set; }
public IList<Guid> ClaimantIds { get; set; }
public bool AllExpenseCategories { get; set; }
public IList<ExpenseCategoryAndTypeCriteria> EpenseCategoryAndTypes { get; set; }
}
And the ExpenseCategoryAndTypeCriteria
public class ExpenseCategoryAndTypeCriteria
{
public Guid ExpenseCategory { get; set; }
public bool AllTypesInCatgeory { get; set; }
public IList<Guid> ExpenseTypes { get; set; }
}
Searching on financial years and claimants needs to be an AND query, then I need the expense categories and expense types to be appended as an OR sub query.
In essence I'm trying to do:
select *
from claims
where <financial year> AND <Claimants> AND (expense type 1 OR expense type 2 or expense category X)
So far I've got this:
public PagedSearchResult<Claim> Search(ClaimSearchCirtieria searchCriteria, int page, int pageSize)
{
var query = All();
if (searchCriteria.FinancialYear.HasValue)
{
query = from claim in query
where claim.FinancialYearId == searchCriteria.FinancialYear
select claim;
}
if (!searchCriteria.AllClaimants)
{
query = from claim in query
where searchCriteria.ClaimantIds.Contains(claim.ClaimantId)
select claim;
}
if (!searchCriteria.AllExpenseCategories)
{
foreach (var item in searchCriteria.EpenseCategoryAndTypes)
{
if (item.AllTypesInCatgeory)
{
//Just search on the category
query = query.Where(claim =>
(from transaction in claim.ClaimTransactions
where item.ExpenseCategory == transaction.ExpenseType.ExpenseCategoryId
select transaction).Count() > 0
);
}
else
{
//Search for the specified types
query = query.Where(claim =>
(from transaction in claim.ClaimTransactions
where item.ExpenseTypes.Contains(transaction.ExpenseTypeId)
select transaction).Count() > 0
);
}
}
}
return PagedSearchResult<Claim>.Build(query, pageSize, page);
}
What I'm currently seeing is that the last expense category requested is the only expense category I get results for. Also, looking at the code, it looks like I would expect this to be building a series of AND queries, rather that the required OR.
Any pointers?
You can do this with LINQKit's PredicateBuilder. You need to use AsExpandable() when composing Entity Framework queries.

Resources