3

Bit (sorry) confused about how to use bitwise operators with Entity Framework.

A recent requirement has necessetated that we alter an enum from a series of sequential integers into a bitwise enum. So:

[Flags]
public enum AdminLevel
{
    None = 0,
    Basic = 1,
    Partial = 2,
    Full = 4
} 

We originally stored this as an int column in the database. It's still an int, of course, but I'm having trouble seeing how I can perform selections based on more than one possible enum value. For example this code:

public string GetAdminEmails(AdminLevel adminlevel)
{
    using (IRepository r = Rep.Renew())
    {
        string[] to = r.GetUsers().Where(u => u.AdminLevel >= (int)adminlevel).Select(u => u.Email).ToArray();
        return string.Join(",", to);
    }
}

Would return all the admin levels including and above the one supplied. If I want more than one admin level, I now have to call it like this:

GetAdminEmails(AdminLevel.Partial | AdminLevel.Full);

But obviously I can't convert that to an int and use greater than any more. Is there a neater way of handling this change than a series of flow control statements?

Bob Tway
  • 9,301
  • 17
  • 80
  • 162
  • 1
    It sounds like you want `GetAdminEmails(AdminLevel.Partial | AdminLevel.Full)` to mean "get admin emails above `AdminLevel.Partial` OR `AdminLevel.Full`". Is that right? If that's what you want, you're going to need to do something clever to decompose the flagged enum into a sequence of OR predicates... or you could figure out what the lowest set flag is and use that in your query. – Steve Ruble Jan 06 '16 at 16:49
  • @SteveRuble That's right, thanks. What's confused me is some isolated suggestions that EF has a certain level of inbuilt ability to recognize and work with bitwise values. I wondered if there was a neater way to handle this. – Bob Tway Jan 06 '16 at 16:55
  • People already discussed related to this topic. It might helpful .. http://stackoverflow.com/questions/1426577/how-to-use-flags-enums-in-linq-to-entities-queries – Shanthini Jan 06 '16 at 16:59

1 Answers1

1

You can use the HasFlag method:

AdminLevel myFlags = AdminLevel.Partial | AdminLevel.Full;
string s = GetAdminEmails(myFlags);

public string GetAdminEmails(AdminLevel myFlags)
{
  using (IRepository r = Rep.Renew())
  {
      string[] to = r.GetUsers().Where(u => u.AdminLevel.HasFlag(myFlags))
                                .Select(u => u.Email).ToArray();
      return string.Join(",", to);
  }
}

You can define an int column in your database as an enumeration in your model:

public enum MyEnum : int { First = 0, Second = 1}

public partial class MyModel
{
   public MyEnum Type {get; set;}
}

Throughout your application you can just use MyEnum and EF will work with int on the background.

Alexander Derck
  • 13,818
  • 5
  • 54
  • 76
  • OK, it looks like I'm asking the wrong question. I came across HasFlag while searching for a solution, but I don't seem to have access to it. We're using EF database first and my field is an int, not an enum? – Bob Tway Jan 06 '16 at 17:08
  • @MattThrower Just define your Model as `AdminLevel` instead of `int`, EF does the conversion automatically – Alexander Derck Jan 06 '16 at 17:59
  • You can as well use '.HasColumnType("INT")' in mapping of your Context and in your entity model should have AdminLevel type as already recommended – Maxim Fleitling Jan 06 '16 at 18:05
  • @MattThrower yes, I'm using Database first too mainly and for a lot of `int` `byte` `short` I have defined enumerations. It's just a lot easier to work with. Edited my answer with an example. – Alexander Derck Jan 07 '16 at 09:23