Linq new statement selection conditionally - c#

i need to select data to populate a DataGrid in MVC Asp.net with entity framework. When i select all values i need to have values from three tables connected: e, category and product. The connection is always 1 to 0 or 1. I have selected all walue with this code but when there isn't a category.name associated i naturally have an exception. What is the best way to do this?Do i need use if statment in New constructor?Or other?
var products = from e in dbResult
select new
{
e.Id,
e.Title,
e.Price,
e.Quantity,
e.category.nome,
e.Product.Sottotitolo,
e.Procuct.Provenienza
};
Thanks to all

Prior to C# 6 one way would be:
var products = from e in dbResult
select new
{
e.Id,
e.Title,
e.Price,
e.Quantity,
Noma = e.category == null ? "" : e.category.nome,
Sottotitolo = e.Product == null ? "" : e.Product.Sottotitolo,
Provenienza = e.Procuct == null ? "" : e.Procuct.Provenienza
};
With C# 6 you can use the ?. null-conditional member access operator:
var products = from e in dbResult
select new
{
e.Id,
e.Title,
e.Price,
e.Quantity,
Noma = e.category?.nome,
Sottotitolo = e.Product?.Sottotitolo,
Provenienza = e.Procuct?.Provenienza
};
Note that the field values in the latter method will be null instead of empty strings.

Related

Left Join to top 1 using LINQ to entites

I have a list of entities that each have 0 > n associated reviews. I want to join the latest review, if one exists for each entity. I then want to return the status of the latest review as below, but not able to filter lstReviews down to the top 1 by CreatedDate Descending.
var lstMainEntity = this.service.GetAllMainEntities();
var lstReviews = this.service.GetReviews();
var lst = from e in lstMainEntity
from review in lstReviews.Where(r => r.EntityID == e.EntityID).DefaultIfEmpty()
select new
{
ID = e.EntityID,
ReviewStatus = review != null ? review.IsComplete ? "Complete" : "Active"
}
How can i best achieve this?
I am assuming lstMainEntity and lstReviews are IQueryable<..>. If they are IEnumerable<..>, you will have to put a null check in the ReviewStatus assignment. (Performance should be faster if it is an IQueryable)
var lst = from e in lstMainEntity
let review = lstReviews.Where(r => r.EntityID == e.EntityID)
.OrderByDescending(r => r.CreatedDate)
.FirstOrDefault()
select new
{
ID = e.EntityID,
ReviewStatus = review.IsComplete ? "Complete" : "Active"
}

C# ?? operator and ora-12704: character set mismatch

I have asp.net mvc 4 application with EF 4, .net 4
This code
public List<ListItem> GetViolatedArticlesByLaw(int lawId, string culture)
{
culture = culture.ToLower();
var ans =
(from art in context.TITLENORMALAWs.Where(l => l.PARENTID == lawId)
select new ListItem
{
ID = art.ID,
ParentID = lawId,
Value = (art.NUM_STATSTR ?? ""),
});
Debug.WriteLine( ((System.Data.Objects.ObjectQuery)ans).ToTraceString() );
return ans.ToList();
}
throws ora-12704: character set mismatch.
It runs perfectly fine if I select from List, like this: from art in context.TITLENORMALAWs.Where(l => l.PARENTID == lawId).ToList()
This is the SQL generated:
SELECT
"Extent1"."ID" AS "ID",
:p__linq__1 AS "C1",
CASE WHEN ("Extent1"."NUM_STATSTR" IS NULL) THEN '' ELSE "Extent1"."NUM_STATSTR" END AS "C2"
FROM "AISSMK"."TITLENORMALAW" "Extent1"
WHERE ("Extent1"."PARENTID" = :p__linq__0)
It produces the same error in sqldeveloper and if I change this piece THEN '' ELSE to this THEN n'' ELSE it runs ok.
NUM_STATSTR in table definition is NVARCHAR2(30)
How can I make linq generate proper sql? Or do I have to call ToList() before selecting and there is no other way?
#Orif I think you should try to build the query manually instead of using the LINQ-to-SQL generators.
Try using the ExecuteQuerymethod on the DataContext class and try to add a cast to NVARCHAR
For more help read here, https://social.msdn.microsoft.com/Forums/en-US/20d456f0-9174-4745-bbc5-571f68879e27/net-strings-sql-paramater-type-always-nvarchar?forum=linqtosql
In my case, the issue was that empty strings are treated as null by Oracle, so your code Value = (art.NUM_STATSTR ?? "") actually ends up looking like Value = (art.NUM_STATSTR ?? null). Our workaround looks like this:
var ans =
(from art in context.TITLENORMALAWs
where art.PARENTID == lawId
select new
{
ID = art.ID,
ParentID = lawId,
Value = (art.NUM_STATSTR ?? ""),
})
.ToList()
.Select(a => new ListItem{
ID = a.ID,
ParentID = a.ParentID,
Value = a.Value ?? "",
});

Check if value is null, and when it is, execute extra (sub)query

Is it possible to check for a null value in a LINQ query and when the value is null, that it executes an extra (sub)query, all at once?
Explanation
I have default buttons declared in my database, with default descriptions. A user can customize these buttons, and these settings are stored in the ButtonLocations table. Now, every button has a standard description and the user can edit this description. When the user edits the description, it is stored in the Descriptions table in my database.
When I retrieve all buttons, I first check if a button has a specific description (in buttonlocations, with a left join). If this is not true (so null), I retrieve the default description.
Currently I get all my entities with their description and after that I loop through all of them to check if the value is null. This results in multiple queries to the database.
var temp = (from bl in context.buttonLocations
join b in context.Buttons
on bl.ButtonID equals b.ButtonID into buttons
from button in buttons.DefaultIfEmpty()
join d in context.Descriptions
on new
{
ID = bl.ButtonLocationID,
langID = languageID,
originID = descriptionOriginID
}
equals new
{
ID = d.ValueID,
langID = d.LanguageID,
originID = d.DescriptionOriginID
}
into other
where bl.ButtonGroupID == buttonGroupId
from x in other.DefaultIfEmpty()
select new
{
Button = button,
ButtonLocation = bl,
Description = x
}).ToList();
// Retrieve default descriptions if no specific one is set
foreach (var item in temp)
{
if (item.Description == null)
{
item.Description = context.Descriptions
.FirstOrDefault(x => x.ValueID == item.Button.ButtonID && x.LanguageID == languageID && x.DescriptionOriginID == (short)DescriptionOriginEnum.Button);
}
}
I think Colin's answer using the coalesce operator ought to work, but if it can't be made to you could try doing a subselect which gets both options, then ordering by preference for custom source, and taking the top record. (I'm assuming here that any given button only really has one description, and multiple descriptions shouldn't result in multiple buttons.)
var temp = (from bl in context.buttonLocations
join b in context.Buttons
on bl.ButtonID equals b.ButtonID into buttons
from button in buttons.DefaultIfEmpty()
let description = (
from d in context.Descriptions
where
d.LanguageID == languageID
&& (
(
d.ValueID == bl.ButtonLocationID
&& d.DescriptionOriginID == descriptionOriginID
)
||
(
d.ValueID == b.ButtonID
d.DescriptionOriginID == (short)DescriptionOriginEnum.Button
)
)
// this line puts custom descriptions first
orderby d.DescriptionOriginID == (short)DescriptionOriginEnum.Button
? 1
: 0
select d
)
// this will get a custom description if there was one, otherwise
// the first one will be the default description
.FirstOrDefault()
where bl.ButtonGroupID == buttonGroupId
select new
{
Button = button,
ButtonLocation = bl,
Description = description
})
.ToList();
This is obviously a bit awkward, and probably not the most efficient query. I would try moving the coalesce operator to a let description = d ?? /*subselect*/ line first.
The null coalescing operator should work for you here. Something like this:
.....
select new
{
Button = button,
ButtonLocation = bl,
Description ?? context.Descriptions
.FirstOrDefault(
x => x.ValueID == button.ButtonID
&& x.LanguageID == languageID
&& x.DescriptionOriginID == (short)DescriptionOriginEnum.Button)
})

Where is the DefaultIfEmpty with the linq query style

var query = from r in list where r.Id == "" DefaultIfEmpty(String.Empty)
does not work.
How do I have to write a linq query with query style and use the DefaultIfEmpty method?
Assuming your list contains the type Item you would want:
// define your default item
var defaultItem = new Item { ... };
var query = (from r in list where r.Id == "" select r).DefaultIfEmpty(defaultItem);
or in method syntax
var query = list.Where( r => r.Id == "" ).DefaultIfEmpty(defaultItem);
However if you're selecting a specific string property of Item then you may want something like
var query = (from r in list where r.Id == "" select r.StringProperty)
.DefaultIfEmpty(string.Empty);
DefaultIfEmpty is used usually with JOINS, (outer joins).
You may see: How to: Perform Left Outer Joins (C# Programming Guide)
For your case it apears you want to select empty string if the r.Id is null, you can you can do:
var query = from r in list
select new
{
ID = r.Id == null ? string.Empty : r.Id
};

using linq to sql to specify where clause

I am using this method to get results to fill my grid but this method is also used to fill another grid which requires a where clause with two params and this one
only needs one. Even though i passed in null of the param that isn't used but still it is returning no results because of the where clause. Any advice of how i could
change this maybe use linq to sql where i call the method to specify the where clause instead of in the method getting data?
DocsForReview.DataSource = docLib.GetGrid(Guid.Empty, lib);
using (var dc = new DocMgmtDataContext())
{
var subs = (from doc in dc.Documents
join u in dc.Users on doc.OwnedByUserID equals u.ID
where doc.OwnedByUserID == usr && doc.LibraryID == lib
select new StudentDocuments
{
DocID = doc.ID,
Assignment = doc.Library.Name,
Submitted = doc.UploadDT,
Student = u.FullName
}).OrderByDescending(c => c.Submitted).AsEnumerable().ToList();
return subs;
}
For nullable types try this:
doc.LibraryID == (lib ?? doc.LibraryID)
In your case (a System.Guid) you can try this:
doc.LibraryID == (lib == Guid.Empty ? doc.LibraryID : lib)

Categories