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.
Related
I am trying to amend a c# project. I am a vb.vet programmer so having a few issues as I am new to linq. I am trying to run a Linq to Entity query. I want to select the MapEast where town = town. I keep get an error The specified cast from a materialized System.Decimal' type to the 'System.Int32' type is not valid.. I would like to put a max(1) in here too so it returns only the highest number.
var topEast = 0;
try
{
topEast = this._uow.Addresses
.Where(a =>
a.Town.Trim().ToUpper() == town.Trim().ToUpper())
.Select(m => m.MapEast).FirstOrDefault ();
return -1;
}
catch
{
return -1;
}
Thanks
var is used for implicitly typed local variable. When you defined var topEast = 0;, topEast was implicitly assigned type int, and not decimal as per your query. You can fix it by explicitly defining topEast as decimal.
decimal topEast = 0;
I would like to put a max(1) in here too so it returns only the
highest number.
Not really sure what you are trying to return, because you are returning -1 from try as well as catch block. If you are trying to return the Max value of MapEast field then you will need Enumerable.Max, otherwise FirstOrDefault would return the first item or null based on criteria.
I have a Linq to SQL query very similar to the following:
var result = (from shareclass in database.ShareClassInfo
where shareclass.Id == ID
select new ShareClass
{
IsOnlineListing = shareclass.IsOnlineListing
}
);
var list = result.ToList();
When I try to create a list from the results I get the following error:
The null value cannot be assigned to a member with type System.Boolean which is a non-nullable value type.
The reason for this is that IsOnlineListing is a bool, but the field in the database is null. So I'm effectively trying to assign a value type with a null value (which is impossible).
I think the solution to this is to make IsOnlineListing a nullable type, but I'm a little confused why I was let do this in the first place. I mean, the database field is defined as a [bit] NULL field. I thought the compiler would be smarter than to let me assign null value to a non-nullable type, or at least it would warn me about it.
So what I'm wondering, is if this is the correct solution? Is there another way to do this? Why wasn't the compiler able to tell me that this is or could be a problem?
you need to change your declaration of IsOnlineListing
From
bool IsOnlineListing;
To
bool? IsOnlineListing;
Or do something like this
var result = (from shareclass in database.ShareClassInfo
where shareclass.Id == ID
select new ShareClass
{
IsOnlineListing = shareclass.IsOnlineListing.HasValue ?
shareclass.IsOnlineListing.Value : false;
}
);
var list = result.ToList();
You can use a nullable type.
Suppose i have this sql statement and I have executed a sql command to get a datareader:
"select 1 union select 2"
//.....
var rdr = cmd.ExecuteReader();
and now i want to read the value in the first column of the first row:
var myInt = (int)rdr.GetValue(0); //great this works
var myLong = (long)rdr.GetValue(0); //throws cast exception, even though you can cast int to long
So it appears the type you cast to in C# needs to match exactly the SQL type. I.E. If the sql type is bigint, you can only cast to long. If the sql type is int, you can only cast to int. No mix and match...
I just want to get something that works regardless of the type of integer c# asks for and sql returns, as long as you could theoretically cast one to the other. So if SQL Server gives me a floating point type, and I'm asking for an int, I want the truncated int you get from doing that cast.
My goal is to make this work with generics, so I can have this function work when the generic parameter doesn't exactly match the datatype in sql server:
List<T> GetFirstColumn<T>(string sql) where T : struct
{
//get connection, execute reader
// loop:
// lst.Add( (T) rdr.GetValue(0));
}
I'd like this to work for both statments:
var sql1 = "Select 1"; //sql int
var sql2 = "Select cast(1 as bigint)"; //sql equivalent of a long
var lst1 = GetFirstColumn<int>(sql1);
var lst2 = GetFirstColumn<int>(sql2);
Does anyone have a relatively painless way of doing this?
Like Fredrik says, the value from SqlDataReader is boxed. You can convert a boxed value to an int with Convert.ToInt32, like:
int i = Convert.ToInt32(read[0]);
This will try to convert even if SQL Server returns a bigint or a decimal.
System.Convert will take care of the conversion.
T GetValue<T>(SqlDataReader rdr)
{
var dbVal = rdr.GetValue(0);
var csVal = (T)System.Convert.ChangeType(dbVal, typeof(T));
}
Caveat: if T == Nullable<S>, you need to do some extra work with reflection to get the underlying type and call ChangeType with typeof(S) as the type parameter. Apparently, MS didn't update the ChangeType function with .NET 2.0 and the introduction of nullables. And if it's a nullable, and dbVal is DBNull, you can just return null.
object dbValue = 5;
//this throws
Convert.ChangeType(dbValue, typeof(int?));
//this works
if(dbValue == DBNull.Value || dbValue == null)
{
if(typeof(int?).IsNullable) //or is a class, like string
{return null;}
dbValue = null;
}
var type = GetUnderlyingType<int?>(); //== typeof(int)
Convert.ChangeType(dbValue, type);
I think your problem is that GetValue returns an object. This means that in the case of an int, you will get an int boxed in an object. Then you cannot directly cast it to a long but must first unpack it as an int:
var myLong = (long)(int)rdr.GetValue(0);
This will be quite tricky using generics, I would say. Well, you could make generic methods with two type arguments; one specifying what type the field is, and one specifying the type you want. But I don't really see the need; SqlDataReader already has methods for the various data types, such as GetInt32, GetInt64 and so on, so the generic method would not really give any added value in that case.
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;
}
}
I have a field in my database table that use to store an enumeration value, e.g.:
create table MyTable (
...
Status tinyint not null,
...
)
and in my C# class I have
public enum TStatus : byte {
Pending = 1
Active = 2,
Inactive = 3,
}
public TStatus MyStatus {
get { return (TStatus)Status; }
set { Status = (byte)value; }
}
now I want to write a Linq query that uses the MyStatus property of MyTable e.g.
var q = MyDataContext.GetTable<MyTable>().Where(t => t.MyStatus == TStatus.Active);
but of course, Linq doesn't know how to interpret MyStatus as SQL.
What do I need to do to MyStatus in order for it to work in LinqToSQL?
Check out this link:
http://dotnet.org.za/hiltong/archive/2008/08/06/using-enums-with-linq-to-sql.aspx
As links die - and at least for me this one did die - here is the important part:
[When adding the column to the entity] by default, the Type will come up as an "int (System.Int32)", but you can change it to the fully-qualified type of the enum (in my case, ConsoleApplication1.CustomerType). BUT, in order to locate it fully, you have to add the global identifier, as follows: global::ConsoleApplication1.CustomerType , so type that as is (but the equivalent for your namespace) into the textbox
Don't have a compiler handy, but I think if you cast your enum to an int, it will work.
So try:
var q = MyDataContext.GetTable().Where(t => t.MyStatus == (int)TStatus.Active);