EF 4.0 LINQ one to many / many to one - entity-framework

Just starting to use LINQ as well as EF.
I have a set of tables in the following configuration:
PublicUtility (UtilityCode) * ----> 1 (UtilityCode) Utility (UtilityCode) 1 -----> * (UtilityCode) UtilityDetail
I have a query in SQL. Based on some other business rules this query will either return 1 value or NULL.
SELECT
#UtilityCode = UtilityDetail.UtilityCode
FROM
UtilityDetail
INNER JOIN PublicUtility ON
PublicUtility.SubdivisionCode = #SubdivisionCode AND
PublicUtility.Year = #PublicUtilityYear AND
PublicUtility.UtilityCode = UtilityDetail.UtilityCode
WHERE
UtilityDetail.DebtPurposeCode = #DebtPurposeCode
How could I rewrite this using LINQ to entities?

using (YourObjectContext ctx = new YourObjectContext())
{
var code = (from ud in ctx.UtilityDetails
join pu in PublicUtility on ud.UtilityCode equals pu.UtilityCode
where ud.DeptPurposeCode == [code_value] && pu.SubdivisionCode == [subdivcode_value] && pu.Year == [year_value]
select new {ud.UtilityCode}).FirstOrDefault();
}

Related

D365 CE: difference between OrganizationServiceContext and QueryExpression through Service?

I'm trying to execute a LINQ query within a plugin, using the OrganizationServiceContext, to retrieve some quotes. On these quotes, I'm using .Select() to only select the value for the field cgk_totalnetprice, as shown below:
quotes = OrganizationServiceContext.QuoteSet
.Where(_ =>
_.OpportunityId != null &&
_.OpportunityId.Id == opportunityId &&
_.QuoteId != currentQuote.Id &&
(_.StatusCode.Value == (int)Quote_StatusCode.Won || _.StatusCode.Value == (int)Quote_StatusCode.WonOrder) &&
_.cgk_quotetypecode != null &&
(_.cgk_quotetypecode.Value == (int)QuoteTypeCode.Regular || _.cgk_quotetypecode.Value == (int)QuoteTypeCode.ServiceUnderWarranty))
.Select(x => new Quote() { Id = x.Id, cgk_totalnetprice = x.cgk_totalnetprice})
.ToList();
However, when retrieving those quotes, the context does not return a value for all except one quote (and it is not the quote that triggered the update in the first place, but just a random one that was not updated at all)
Weird part: when I rewrite the query to a QueryExpression, everything works perfectly:
QueryExpression qe = new QueryExpression("quote");
//Exclude current quote
qe.Criteria.AddCondition("quoteid", ConditionOperator.NotEqual, currentQuote.Id);
//Opportunity
qe.Criteria.AddCondition("opportunityid", ConditionOperator.NotNull);
qe.Criteria.AddCondition("opportunityid", ConditionOperator.Equal, opportunityId);
//State-Status
FilterExpression statusFilter = new FilterExpression(LogicalOperator.Or);
statusFilter.AddCondition("statuscode", ConditionOperator.Equal, (int)Quote_StatusCode.Won);
statusFilter.AddCondition("statuscode", ConditionOperator.Equal, (int)Quote_StatusCode.WonOrder);
qe.Criteria.AddFilter(statusFilter);
//QuoteType
qe.Criteria.AddCondition("cgk_quotetypecode", ConditionOperator.NotNull);
FilterExpression typeFilter = new FilterExpression(LogicalOperator.Or);
typeFilter.AddCondition("cgk_quotetypecode", ConditionOperator.Equal, (int)QuoteTypeCode.Regular);
typeFilter.AddCondition("cgk_quotetypecode", ConditionOperator.Equal, (int)QuoteTypeCode.ServiceUnderWarranty);
qe.Criteria.AddFilter(typeFilter);
qe.ColumnSet = new ColumnSet("quoteid", "cgk_totalnetprice");
quotes = this.OrganizationService.RetrieveMultiple(qe).Entities.Cast<Quote>().ToList();
What could cause this difference between OrganizationServiceContext and OrganizationService + QueryExpression??
Queries on OrganizationServiceContext rely on LINQ for CRM, which in turn translates LINQ expressions into QueryExpression objects. LINQ for CRM comes with a few weaknesses:
it does not implement all capabilities of the underlying QueryExpression,
it only supports a limited set of LINQ constructs (see MS Docs),
in some cases it creates incorrect queries,
query processing is approx. 10% slower.
Your query looks pretty straightforward, yet it fails. Maybe you can leave the line _.cgk_quotetypecode != null && out. I guess it is not needed and combined with the subsequent filtering on the same attribute it may trick the LINQ parser into constructing the wrong filter and/or conditions.
Another option is to materialize the LINQ query first and then select the columns needed. Of course this will lead to a select *, but it's often worth trying while troubleshooting.
E.g. you could write:
.ToArray()
.Select(x => new Quote() { Id = x.Id, cgk_totalnetprice = x.cgk_totalnetprice});
Working with Dynamics CRM/365 CE I learned to avoid LINQ for CRM. Instead I use a bunch of extension methods allowing me to create QueryExpression queries in a much less verbose way.
Final suggestion: in some cases a filter's LogicalOperator.Or can be replaced by ConditionOperator.In or ConditionOperator.Between. Doing so the construct
//State-Status
FilterExpression statusFilter = new FilterExpression(LogicalOperator.Or);
statusFilter.AddCondition("statuscode", ConditionOperator.Equal, (int)Quote_StatusCode.Won);
statusFilter.AddCondition("statuscode", ConditionOperator.Equal, (int)Quote_StatusCode.WonOrder);
qe.Criteria.AddFilter(statusFilter);
can simply be replaced by this oneliner:
qe.Criteria.AddCondition("statuscode", ConditionOperator.In, (int)Quote_StatusCode.Won, (int)Quote_StatusCode.WonOrder);
I generally use the query syntax for Dynamics LINQ queries. I'd suggest standard query troubleshooting - start with no conditions and add them one-by-one.
Below is an idea of how my query would look. I'd keep adding / modifying the where clauses until the query returned what I expected.
We could use && operators instead of multiple where clauses, but I find that having the multiple where clauses often makes commenting and uncommenting easier.
using(var ctx = new OrganizationServiceContext(ctx))
{
var x = from q in ctx.CreateQuery<Quote>()
where q.QuoteId ! = currentQuote.Id
where q.OpportunityId != null
where q.cgk_quotetypecode != null
where q.cgk_quotetypecode == QuoteTypeCode.Regular || QuoteTypeCode.ServiceUnderWarranty
select new Quote
{
Id = q.Id,
cgk_totalnetprice = x.cgk_totalnetprice
};
var quotes = x.ToList();
}

Is it possible to combine multiple IQueryable into a single one without using Union?

Good evening. Is it possible to combine multiple IQueryable into a single one without using Union in EF Core 2? The main problem is that it doesn't allow to use methods like .Union(), .Except() etc.
It's important that IQueryable should be executed as a single query.
This is what I want to get: toCreateSubquery.Union(toDeleteSubquery)
The queries I want to combine are listed below.
var toCreateSubquery =
validLinks
.Where(
rl => !existingLinks.Any(
el => el.Contract == rl.Contract && el.Estate == rl.Estate)) // Except() doesn't work'
.Select(x => new {x.Contract, x.Estate, Type = ActionType.Create});
var toDeleteSubquery =
existingLinks
.Where(el => !validLinks.Any(rl => el.Contract == rl.Contract && el.Estate == rl.Estate))
.Select(x => new {x.Contract, x.Estate, Type = ActionType.Delete});
This is the visualization of the problem I'm solving.
I want to get the union of these sets without intersection and be able to distinguish belonging to one of these sets.
Just in case, I attach the code of getting these sets:
var validLinks = from ac in _context.AreaContracts
from e in _context.Estate
where (from al in e.AreaLinks select al.Area.Id).Contains(ac.Area.Id) ||
e.Geometry.Intersects(
ac.Area.Geometry)
select new { Contract = ac.Contract.Id, Estate = e.Id };
var existingLinks = from sd in _context.SquareDistributions
select new { Contract = sd.Contract.Id, Estate = sd.Estate.Id };
Thank you for your attention.

How to create a single repository for all queries using ADO.net and MVC

since im using npgsql and postgressql creating model from my database is a big pain,there are man views and adding views to model using npgsql is a big pain which is not solved yet,any way for some reasons I need to use ado,is there any possibility to have a single gate for all my transactions?i have the following code in my controller:
Here I have my connection:
NpgsqlConnection npgc = new NpgsqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Central"].ConnectionString);
npgc.Open();
NpgsqlCommand cmd = new NpgsqlCommand(#"SELECT xc.m_error_group_name, xc.m_error_group_id, count(*),error_duration
FROM (
SELECT extract(year from m_date) m_year, v1.m_error_group_name, v1.m_error_group_id,
zd.t_users g on(g.user_id=f.pv_person_resp_id) and g.user_name in(#rgnal)
LEFT OUTER JOIN ssw_mdt.t_master_pc_alarm_pattern t3 ON (t1.m_inv_error_details = t3.pc_group_pattern)
WHERE (m_date between #fr and #to)
AND t1.crew_present is FALSE
AND t1.m_grid_loss is FALSE
) GROUP BY 1, 2
order by error_duration desc", npgc);
here is how I query:
NpgsqlParameter[] param = {new NpgsqlParameter("#rgnal",reginalManagers),
new NpgsqlParameter("#fr",dtFrom),
new NpgsqlParameter("#to",dtTo);
cmd.Parameters.AddRange(param);
FaultStatViewModel flt = new FaultStatViewModel();
using (NpgsqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
flt.m_error_group_name.Add(rdr["m_error_group_name"].ToString());
}
}
npgc.Close();
so imagine I have 10 other queries I don't want to do these all again and again,please help me out,im new

How to remove duplicate data from child object called in entity framework?

var eventDetails = (from e in db.tb_Event
select new
{
e.EventID,
e.tb_Customer.CustomerName,
e.StartDate,
e.EndDate,
loc = (from l in db.tb_EventLocation where l.EventID == e.EventID select new { l.tb_Location.LocationName }).Distinct(),
e.Objective
});
This is the correct way do do it. Try this out, this is working fine for me. Since you cannot use Include() for filtering you have to use projection technique.

EF 4 Code First - Problem while using inner query

I'm having problem using queries like this with Entity Framework 4 Code First:
var entities = context.TestEntities.Where( e => context.TestEntities2.Count() > 0)
The above query will generate the following exception:
Unable to create a constant value of
type 'TestModel.TestEntities2'. Only
primitive types ('such as Int32,
String, and Guid') are supported in
this context.
The same code works if I use the model designer and generate the POCO-classes and thus using a ObjectContext instead.
EDIT: It works in a console-application but not while using my repository in an MVC 3 project.
EDIT 2: How about this:
var userProfile = ctx.UserProfiles.Where(p => p.User.Id == user.Id).SingleOrDefault();
return ctx.Feeds.Where( f => ctx.ProfileFollowers.Count() > 0 ).ToList();
The above two lines throws the exception. Commenting out the first line solves the problem. Bug in DbContext?
//var userProfile = ctx.UserProfiles.Where(p => p.User.Id == user.Id).SingleOrDefault();
return ctx.Feeds.Where( f => ctx.ProfileFollowers.Count() > 0 ).ToList();
Posted to http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/2fb5ceea-9f30-4665-af98-945c6485f60b
Try the Any method:
var q = context.TestEntities.Where(a=>context.TestEntities2.Any());
This code results in the EXISTS clause:
SELECT
[Extent1].[ProductID] AS [ProductID],
...
FROM [dbo].[Products] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Regions] AS [Extent2]
UPD: In case of repositories the correct way is to execute the first query and then the second one:
if(context.TestEntities2.Count() > 0)
var q = context.TestEntities.Select(t=>t);