可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a class for something simple, Status, and it contains two properties. I want to use an Enum for one of the Properties(StatusID) so that I can eliminate a bunch of Magic Strings.
My question is how I then work with it, for example: I have a Method that returns a List for binding in a dropdown box that looks like this -->
public static IList<Status> GetAdminStatuses()
{
IQueryable<Status> stat=context.tblAdminStatus
.Where(s => s.InactiveDate > DateTime.Now || s.InactiveDate == null)
.Select(s => new Status()
{
StatusID=s.StatusID,
StatusDescription=s.StatusDesc
});
return stat.ToList();
}
It obviously does not like my StatusID=s.StatusID
part as the DB stores it as a varchar. Am I missing something simple here or have I stumbled into noob territory and should not be doing it this way?
For reference here is the Class and Enum:
public class Status
{
public string StatusID {get; set;}
public string StatusDescription {get; set;}
}
public enum MyStatusID
{
draft, pending, declined, accepted, close
}
EDIT
So taking the advice here I was able to get my method to compile however at runtime I get the following --> Method 'System.Object Parse(System.Type, System.String)' has no supported translation to SQL.
Thoughts?
EDIT - Method in it's entirety by request, thanks (NOTE that NoaStatusID == MyStatusID)
public static IList<Status> GetAdminStatuses(NoaStatusID currentStatus = NoaStatusID.draft)
{
using (var context = MemberDataContext.Create())
{
IQueryable<Status> stat=context.tblAdminStatus
.Where(s => s.InactiveDate > DateTime.Now || s.InactiveDate == null)
.Select(s => new Status()
{
StatusID=NoaStatusID)Enum.Parse(typeof(NoaStatusID),s.StatusID),
StatusDescription=s.StatusDesc
});
switch (currentStatus)
{
case NoaStatusID.draft:
stat=stat.Where(s => (s.StatusID == NoaStatusID.draft || s.StatusID == NoaStatusID.pending));
break;
case NoaStatusID.pending:
stat = stat.Where(s => (s.StatusID == NoaStatusID.accepted || s.StatusID ==NoaStatusID.declined || s.StatusID ==NoaStatusID.pending));
break;
case NoaStatusID.declined:
stat = stat.Where(s => (s.StatusID == NoaStatusID.draft || s.StatusID == NoaStatusID.pending || s.StatusID == NoaStatusID.declined));
break;
case NoaStatusID.accepted:
stat = stat.Where(s => (s.StatusID == NoaStatusID.mailed || s.StatusID == NoaStatusID.monitor || s.StatusID == NoaStatusID.close || s.StatusID == NoaStatusID.accepted));
break;
case NoaStatusID.mailed:
stat = stat.Where(s => (s.StatusID == NoaStatusID.mailed || s.StatusID == NoaStatusID.monitor || s.StatusID == NoaStatusID.close || s.StatusID == NoaStatusID.appeal));
break;
case NoaStatusID.monitor:
case NoaStatusID.appeal:
case NoaStatusID.close:
stat = stat.Where(s => (s.StatusID == NoaStatusID.close || s.StatusID == NoaStatusID.appeal));
break;
}
return stat.ToList();
}
}
回答1:
i believe what you're searching for is:
StatusID = (MyStatusID)Enum.Parse(typeof(MyStatusID), s.StatusID),
in .Net 4.0 there is also a Enum.TryParse(string, out enum)
but that is not so useful inside your .Select()
Alternatively:
albeit less efficient in most cases, you can keep the Status.StatusID
as a string and add a readonly property StatusEnum
that outputs the Enum value on the fly:
public MyStatusID StatusEnum {
get {
return (MyStatusID)Enum.Parse(typeof(MyStatusID), StatusID)
}
private set;
}
in .Net 4.0:
public MyStatusID StatusEnum {
get {
MyStatusID value;
if(!Enum.TryParse(StatusID, out value)
value = MyStatusID.Default; // default value, instead of Exception throwing
return value;
}
private set;
}
this alternative re-parses the value everytime instance.StatusEnum is read, so I don't recommend it unless LINQ hates the first approach
Responding to your last EDIT:
The Enum.Parse() is translating to SQL fine in your example. The problem is in the switch statement where you're adding on a .Where()
clause that has a comparison with an Enum
. LINQ doesn't know how to turn an Enum == Enum
into SQL but it does know to do it with C# objects. So the easiest solution is to ToList() them and do the comparison locally. Unfortunately, that means it's downloading rows of -all- Status types from the database and then filters them locally. If you have millions of records this may not be reasonable:
public static IList<Status> GetAdminStatuses(NoaStatusID currentStatus = NoaStatusID.draft)
{
using (var context = MemberDataContext.Create())
{
List<Status> stat=context.tblAdminStatus
.Where(s => s.InactiveDate > DateTime.Now || s.InactiveDate == null)
.Select(s => new Status()
{
StatusID=NoaStatusID)Enum.Parse(typeof(NoaStatusID),s.StatusID),
StatusDescription=s.StatusDesc
})
.ToList();
switch (currentStatus)
{
case NoaStatusID.draft:
stat=stat.Where(s => (s.StatusID == NoaStatusID.draft || s.StatusID == NoaStatusID.pending)).ToList();
break;
case NoaStatusID.pending:
stat = stat.Where(s => (s.StatusID == NoaStatusID.accepted || s.StatusID ==NoaStatusID.declined || s.StatusID ==NoaStatusID.pending)).ToList();
break;
case NoaStatusID.declined:
stat = stat.Where(s => (s.StatusID == NoaStatusID.draft || s.StatusID == NoaStatusID.pending || s.StatusID == NoaStatusID.declined)).ToList();
break;
case NoaStatusID.accepted:
stat = stat.Where(s => (s.StatusID == NoaStatusID.mailed || s.StatusID == NoaStatusID.monitor || s.StatusID == NoaStatusID.close || s.StatusID == NoaStatusID.accepted)).ToList();
break;
case NoaStatusID.mailed:
stat = stat.Where(s => (s.StatusID == NoaStatusID.mailed || s.StatusID == NoaStatusID.monitor || s.StatusID == NoaStatusID.close || s.StatusID == NoaStatusID.appeal)).ToList();
break;
case NoaStatusID.monitor:
case NoaStatusID.appeal:
case NoaStatusID.close:
stat = stat.Where(s => (s.StatusID == NoaStatusID.close || s.StatusID == NoaStatusID.appeal)).ToList();
break;
}
return stat;
}
}
回答2:
Isn't what you are looking for?
Colors colorValue = (Colors) Enum.Parse(typeof(Colors), colorString);
回答3:
If you make the backing field* an int
, it will work just fine.
In fact you can even use byte
enums (with a smallint
backing field).
There is a problem with the designer however. IIRC, the enum
declaration needs to be in the same namespace.
Note: By backing field, I mean the database table column type.
回答4:
My guess is that you want the String
equivalent of the enum value, but it isn't very clear:
public static IList<Status> GetAdminStatuses()
{
IQueryable<Status> stat=context.tblAdminStatus
.Where(s => s.InactiveDate > DateTime.Now || s.InactiveDate == null)
.Select(s => new Status()
{
StatusID=Enum.GetName(typeof(MyStatusID),s.StatusID),
StatusDescription=s.StatusDesc
});
}
EDIT: Given the comments, sounds like you want:
public static IList<Status> GetAdminStatuses()
{
IQueryable<Status> stat=context.tblAdminStatus
.Where(s => s.InactiveDate > DateTime.Now || s.InactiveDate == null)
.Select(s => new Status()
{
StatusID=(MyStatusID)s.StatusID,
StatusDescription=s.StatusDesc
});
}
EDIT: Given the (further) comments, sounds like you want:
public static IList<Status> GetAdminStatuses()
{
IQueryable<Status> stat=context.tblAdminStatus
.Where(s => s.InactiveDate > DateTime.Now || s.InactiveDate == null)
.Select(s => new Status()
{
// If database is storing 'draft' (as a varchar)
StatusID=Enum.Parse(typeof(MyStatusID), s.StatusID),
StatusDescription=s.StatusDesc
});
}
Or maybe
public static IList<Status> GetAdminStatuses()
{
IQueryable<Status> stat=context.tblAdminStatus
.Where(s => s.InactiveDate > DateTime.Now || s.InactiveDate == null)
.Select(s => new Status()
{
// If database is storing '0' (as a varchar)
StatusID=(MyStatusID)int.Parse(s.StatusID),
StatusDescription=s.StatusDesc
});
}