LINQ DefaultIfEmpty(), generating inferred argument error - c#

I am trying to get the below linq query to return -1 if there isn't any current value. I was looking at this article on MSDN, here, and it seemed that DefaultIfEmpty() was what I wanted.
Unfortunately, I am getting a The type arguments cannot be inferred from the usage. Try specifying the type arguments explicitly. error.
I guess I am not sure what that means or what it is telling me to do. Can someone explain, please.
public static int CheckForDRIID(int personID)
{
using (var context = ConnectDataContext.Create())
{
var masterIndex =
(from applicationAssociation in context.tblApplicationAssociations
where applicationAssociation.ApplicationID == 1 && applicationAssociation.PersonID == personID
select applicationAssociation.PersonApplicationID).DefaultIfEmpty(-1).Single();
return Convert.ToInt32(masterIndex);
}
}

-1 is an int and applicationAssociation.PersionApplicationID isn't, so it doesn't know what to return. You could replace -1 with the same type as applicationAssociation.PersionApplicationID, "-1". Or specify the type like DefaultIfEmpty<string>. And a third options is to do the Convert.ToInt32 in the select.

That code works fine for me:
public static int CheckForDRIID(int personID)
{
var someAssociaction = new { ApplicationID = 1, PersonID = 1, PersonApplicationID = 1 };
var associactions = (new[] { someAssociaction }).ToList();
associactions.Add(new { ApplicationID = 2, PersonID = 2, PersonApplicationID = 2 });
int masterIndex =
(from applicationAssociation in associactions
where applicationAssociation.ApplicationID == 1 && applicationAssociation.PersonID == personID
select applicationAssociation.PersonApplicationID).DefaultIfEmpty(-1).Single();
return masterIndex;
}
I just created a sample set of associactions, because I dont have your datacontext. By the way: you can just declare masterIndex an int, because you know the type the expression will return, so you dont need a var.
So the cause for your problem lies somewhere else: the PersonApplicationID field is not an int, therefore the compiler does not know which type it should infer for the generic function DefaultIfEmpty.
Update:
Just tried the above example with setting the PersonApplicationID property to:
new Nullable<int>(1): Throws "Cannot implicitly convert type 'int?' to 'int'"
1f: Throws "Cannot implicitly convert type 'float' to 'int'"
"": Throws "The type arguments for method DefaultIfEmpty<TSource> cannot be inferred from the usage. Try specifying the type arguments explicitly."
So, I assume you are storing strings in your database's PersonApplicationID field. If so, either change your database, or parse the string to an int in the Linq query:
public static int CheckForDRIID(int personID)
{
using (var context = ConnectDataContext.Create())
{
int masterIndex =
(from applicationAssociation in context.tblApplicationAssociations
where applicationAssociation.ApplicationID == 1 && applicationAssociation.PersonID == personID
select int.Parse(applicationAssociation.PersonApplicationID)).DefaultIfEmpty(-1).Single();
return masterIndex;
}
}

Related

C# Dynamic Linq: Implement "Like" in The Where Clause

So I want to make a general sorter for my data. I have this code to get data from the database which will extract the data only which contains value.
using System.Linq.Dynamic;
public static IQueryable<object> SortList(string searchString, Type modelType,
IQueryable<object> model)
{
....
string toStringPredicate = type == typeof(string) ? propertyName +
".Contains(#0)" : propertyName + ".ToString().Contains(#0)";
model = model.Where(propertyName + " != NULL AND " + toStringPredicate, value);
}
The model is this:
public class ManageSubscriberItems
{
public int? UserId { get; set; }
public string Email { get; set; }
public Guid SubscriberId { get; set; }
}
When I call:
models = (IQueryable<ManageSubscriberItems>)EcommerceCMS.Helpers.FilterHelper
.SortList(searchString, typeof(ManageSubscriberItems), models);
if(models.Any())
It throws this error:
"LINQ to Entities does not recognize the method 'System.String
ToString()' method, and this method cannot be translated into a store
expression."
EDIT
I found the problem, but I still cannot fix it. So if the property is not string, it will throw an error when calling .ToString().Contains().
model = model.Where(propertyName + " != NULL AND " + propertyName +
".ToString().Contains(#0)", value);
What I want is to implement LIKE in the query. Can anyone help me?
If you use System.Linq.Dynamic.Core with EF Core, you have an option to use
var q = context.Cars.Where(config, "DynamicFunctions.Like(Brand, \"%a%\")");
See this link for an example:
https://github.com/StefH/System.Linq.Dynamic.Core/blob/6fc7fcc43b248940560a0728c4d181e191f9eec1/src-console/ConsoleAppEF2.1.1/Program.cs#L117
And I just tested in linqpad connecting to a real database, and code like this just works?
var result1 = Entity1s.Where("Url != NULL AND it.Url.Contains(#0)", "e");
[UPDATE 2019-04-17]]
In case you don't know the type, you can cast it to object and then cast that to a string.
Code:
var r = Entity1s.Select("string(object(Rating))").Where("Contains(#0)", "6");
so the problem here is that IQueryable thing happens on the SQL server not in C#... so SQL server doesn't know anything about .toString() method.
so => and Like operator it self works on strings.. so it's nvarchar and varchar data types in SQL server.
I could give You an example of how to achieve it if you could tell me more about your problem and what You want to achieve.
could do a sample.
You already have a "Like" in Linq that can run in the database and works with strings, it's called "IndexOf":
((IQueryable)model).Where(m => m.Property.IndexOf(searchString) == 1);
According to MSDN:
IndexOf(string)
'The zero-based index position of value if that string is found, or -1 if it is not. If value is Empty, the return value is 0.'
So I want to make a general sorter for my data.
instead of fixing 'invoke issue', general way should use generics, like
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source,
string property,
bool asc = true) where T : class
{
//STEP 1: Validate MORE!
var searchProperty = typeof(T).GetProperty(property);
if (searchProperty == null) throw new ArgumentException("property");
....
//STEP 2: Create the OrderBy property selector
var parameter = Expression.Parameter(typeof(T), "o");
var selectorExpr = Expression.Lambda(Expression.Property(parameter, property), parameter)
//STEP 3: Update the IQueryable expression to include OrderBy
Expression queryExpr = source.Expression;
queryExpr = Expression.Call(typeof(Queryable), asc ? "OrderBy" : "OrderByDescending",
new Type[] { source.ElementType, searchProperty.PropertyType },
queryExpr,
selectorExpr);
return source.Provider.CreateQuery<T>(queryExpr);
}
having property name string and direction usually used for making 'column sorting' on data.
Next are relation predicates are coming, and 'Linq.Dynamic' seems reasonable when doing from scratch, but there is generic and canonical form exists.

The cast to value type 'Boolean' failed because the materialized value is null

public ActionResult Votation(int id=0)
{
var events = db.Events_Info_tbl.Where(x => x.is_active == true).FirstOrDefault();
//query the first category
List<CampaignManager_tbl> candidates = new List<CampaignManager_tbl>();
candidates = (from cat in db.Events_Category_tbl
join can in db.Candidates_Info_tbl
on cat.events_category_id equals can.events_category_id
where cat.events_info_id == events.events_info_id
select new CampaignManager_tbl {
events_category_name = cat.events_category_name,
candidates_fullname = can.candidates_fullname,
candidates_info_id = can.candidates_info_id,
vote_no = cat.vote_no.Value,
isSelected = can.isSelected.Value,
events_category_id = cat.events_category_id
}).ToList();
return View(candidates);
}
This code was working before but now I've got this error: The cast to value type 'Boolean' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.
What's wrong with this? I didn't change any of my codes before. It just this time I've got an error.
I ran into this error because of a different problem. In my query I am selecting specific columns from an account member and its associated account:
DBContext.Set<AccountMember>()
.Include(am => am.Account)
.Select(am => new
{
am.ID,
am.IsPrimary,
Account = new { am.Account.ID, am.Account.DoNotEmail }
});
Both of my boolean properties, IsPrimary and DoNotEmail are non-nullable so the resulting property type of their properties in the anonymous type is bool. The exception occurs when an AccountMember does not have an Account. Since am.Account is null, the expression am.Account.DoNotEmail returns null. But the anonymous type's DoNotEmail property inferred it was of type bool which cannot be set to null. The solution is to give it a hint that this should be a nullable bool by casting the property to a bool?:
DBContext.Set<AccountMember>()
.Include(am => am.Account)
.Select(am => new
{
am.ID,
am.IsPrimary,
Account = new { am.Account.ID, DoNotEmail = (bool?)am.Account.DoNotEmail }
});
Hapily EF is smart enough to ignore this cast and not blow up trying to convert it to SQL.
I'm going out on a limb here, but I'd guess it has to do with this line:
isSelected = can.isSelected.Value,
If when the two tables are joined, one of them does not return a value for that particular field, it will be null. It appears the type here is a nullable of some type - probably bool?, based on the naming - and that would match your error.
Try to replace it with the following:
isSelected = can.isSelected.HasValue ? can.isSelected.Value : false,
Of course, you can replace the default false here with true, if that makes more sense in your case.
Edit: Note that you should probably do the same for the other column you use in a similar way (I'm assuming this is returning an int?):
vote_no = cat.vote_no.HasValue ? cat.vote_no.Value : 0
Is db.Candidates_Info_tbl.IsSelected a bit field?
If so, the query could likely result in
isSelected = can.isSelected.Value,
with isSelected being null, whereas you probably declared isSelected as bool in CampaignManager_tbl class.
Change the isSelected to bool in the CampaignManager_tbl class and try again.
if your field type is int while some value is null, then you can use case-when and convert to bit like below
SELECT CASE WHEN FieldName IS NOT NULL THEN CONVERT(BIT,FieldName) ELSE CONVERT(BIT,0) END AS NewFieldName

linq select field type unknown

I have the following code:
var query =
from product in products.AsEnumerable()
where product.Field<string>("Product") == "Phone"
select new
{
Name = product.Field<string>("Name"),
ProductNumber = product.Field<string>("ProductNumber"),
ListPrice = product.Field<Decimal>("Price")
};
But I am getting the following error:
Unable to cast object of type 'System.Int32' to type 'System.String'.
I assume that's because in the ProductNumber column I don't always have doesn't always have strings, and in the first row the ProductNumber is actually an int. I've tried converting and casting them to string, but didn't work.
How can I fix this?
From the documentation of Field<T>:
InvalidCastException [is thrown when] the value type of the underlying column could not be cast to the type specified by the generic parameter, T.
It looks like in your case the column type is a nullable integer, so you need to do something like this:
var query =
from product in products.AsEnumerable()
where product.Field<string>("Product") == "Phone"
select new
{
Name = product.Field<string>("Name"),
// Below, I am using ""+... idiom for a null-safe ToString
ProductNumber = ""+product.Field<int?>("ProductNumber"),
ListPrice = product.Field<Decimal>("Price")
};
The idea is to retrieve the value as an int, but accept data rows where the data is missing.
If you do not mind ProductNumber of your anonymous class being nullable ints instead of strings, remove the ""+ part of the expression.
First you fetch the records as enumerable with ProductNumber as string and then later on Enumerable have a conversion from string to int.

How to Assign a Query Result to an Integer Array

public List<Workflow> GetMyWorkflows(int[] MyRoles)
{
int[] myWorkflowIDs = new int[] { };
RapidWorkflowDataContext context = new RapidWorkflowDataContext();
var query = from w in context.WorkflowRoles
where MyRoles.Contains((int)w.RoleID)
select w.WorkflowID;
var distinctWorkflows = query.Distinct();
myWorkflowIDs = distinctWorkflows.toArray();
return myWorkflowIDs;
}
In this method I want to retrieve an array of workflows that a user can
access.
I get the following error : Cannot implicitly convert type 'int?[]' to 'int[]'
I want to retrieve an array of workflows
But your method must return a List<Workflow> or a List<int>.
So you should skip the array idea. The other issue is between int and int?. You can solve that in the select clause with select w.WorkflowID.Value or select w.WorkflowID ?? 0. Or simply select w for a List<Workflow>.
Also it is a good idea to dispose a context when it becomes unreachable.
public List<int> GetMyWorkflows(int[] MyRoles)
{
using (RapidWorkflowDataContext context = new RapidWorkflowDataContext())
{
var query = from w in context.WorkflowRoles
where MyRoles.Contains((int)w.RoleID)
select w.WorkflowID ?? 0;
// select w; to return a List<WorkFlow>
var distinctWorkflows = query.Distinct();
return distinctWorkflows.ToList(); // ToList because we are closing the Context
}
}
I'm going to guess that WorkflowID is of type int?. If you are certain that it cannot be null, change your central query to:
var query = from w in context.WorkflowRoles
where MyRoles.Contains((int)w.RoleID)
select w.WorkflowID.Value;
This will ensure that query is now of type IEnumerable<int> instead of IEnumerable<int?>, with the int following on throuhh the Distinct() and ToArray() functions.
This seems like a pretty good error to me
Cannot convert type 'int?[]' to 'int[]'
You must have an array of type int? and be trying to implicitly convert it to int.
Therefore you have two options - stop trying to implicitly convert, and allow the result to be int?[], like this:
int?[] myWorkflowIDs = new int?[] { };
or force the convert to take place, like this:
RapidWorkflowDataContext context = new RapidWorkflowDataContext();
var query = from w in context.WorkflowRoles
where MyRoles.Contains((int)w.RoleID)
select (int)w.WorkflowID;
// or w.WorkflowID ?? 0; as necessary
So int? can also be written Nullable<int> which is basically an int that can take null values. For example:
int? nullableNumber = 5; // Set to a value
nullableNumber = null? // Set to null (which is possible because int? is nullable).
As you can imagine, Nullable<int> is useful for databases because sometimes you might have a column that has null values, and so this type gives a useful means of mapping to this sort of value. The problem, though is that in your code you have to deal with two different types, int vs. int?. You can cast between the two values by using:
// If the nullable-integer is not-null then use it's value, else default to `0`.
int nonNullable = nullableNumber ?? 0;
which will replace nulls with 0 if the value is null. Or you can just store your myWorkflowIDs in a nullable value (Nullable<int>[] or int?[]), which semantically better reflects what the column value in the database actually is.

How to handle ObjectResult in Entity Framework 4

In Entity Framework 4, I'm facing a problem when I use function import to a stored procedure and then using as a scalar value. It generates the code below:
public virtual ObjectResult<Nullable<int>> GetTopEmployee()
{
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Nullable<int>("GetTopEmployee");
}
How do I use the return value of this method?
For example, this code works fine:
NorthwindEntities db = new NorthwindEntities();
var i = db.GetTopEmployee();
But I want to use return values only as int. If I use return value as non while in function import it give -1 as output.
When I try the code below:
NorthwindEntities db2 = new NorthwindEntities();
int j = db.GetTopEmployee();
It throws an error saying:
Cannot implicitly convert type 'System.Data.Objects.ObjectResult' to 'int'
How do I parse the above?
Notice that the return type of GetTopEmployee is an ObjectResult<Nullable<int>>. ObjectResult<T> implements IEnumerable<T> so your method is capable of returning more than one Nullable<int>.
I assume you are trying to get some form of Id for the employee. If you are absolutely sure you are only going to get one result you could use the following code to get that Id.
var topId = db.GetTopEmployee().FirstOrDefault();
topId could be null. You will have to use topId.Value or var result = topId ?? -1; to get an int result.
NorthwindEntities db = new NorthwindEntities();
int j = db.GetTopEmployee().FirstOrDefault() ?? -1;

Categories