Custom non-primitive type in Entity Framework code

2019-08-10 05:39发布

问题:

I have this custom type:

public struct PasswordString
{
    private string value;

    public PasswordString(string value)
    {
        this.value = MD5.CalculateMD5Hash(value);
    }

    public string Value
    {
        get { return this.value; }
        set { this.value = MD5.CalculateMD5Hash(value); }
    }

    public static implicit operator PasswordString(string value)
    {
        return new PasswordString(value);
    }

    public static implicit operator string(PasswordString value)
    {
        return value.Value;
    }

    public static bool operator ==(string x, PasswordString y)
    {
        return x.CompareTo(y) == 0;
    }

    public static bool operator !=(string x, PasswordString y)
    {
        return x.CompareTo(y) != 0;
    }

    public override string ToString()
    {
        return Value;
    }
}

public static class MD5
{
    public static string CalculateMD5Hash(string input)
    {
        System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
        byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
        byte[] hash = md5.ComputeHash(inputBytes);

        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        for (int i = 0; i < hash.Length; i++)
        {
            sb.Append(hash[i].ToString("X2"));
        }
        return sb.ToString();
    }
}

So, I want tu use this type in my Entity Framework project. How can I map a type to work just like a string.

public class User
{
    public int Id { get; set; }
    public string Username { get; set; }
    public PasswordString Password { get; set; }
}

The using sample:

User user = new User()
{
    Username = "steve",
    Password = "apple"
};

System.Console.WriteLine(user.Password == "apple");
System.Console.WriteLine(user.Password);

This code produces:

True
1F3870BE274F6C49B3E31A0C6728957F

My goal, is to query against the Entity Framework to have some like this:

var q = from u in users
        where u.Username == "steve" && u.Password == "apple"
        orderby u.Username
        select u;

So then, I never need to encrypt the password, but it will be stored encrypted on the database.

I am trying to use this class with EF, but with no success. There is a way achieve this with Entity Framework 4.1?

回答1:

Entity framework doesn't support type converters or any other way to map simple database column to your custom type and such feature is even not yet planned for the next release. So the answer to your question is: not possible.



回答2:

It's not possible to use your class (or struct) as a complex type in a LINQ to Entities query. I order to execute this comparison ...

u.Password == "apple"

... the constructor must be called which calls in turn MD5.CalculateMD5Hash. This method cannot be translated into SQL and the query will throw an exception. It's likely that LINQ to Entities even doesn't support any overloaded operator (like ==) - for the same reason: EF can't translate it into SQL.