Model First: how to add property of type Color?
Asked Answered
D

3

8

I'm creating a new database with the model-first approach and I want to add a column to a table of the type System.Drawing.Color but I don't have this option in the properties list.

Is there a way to use more data types than the ones available?

Dispassion answered 15/7, 2014 at 10:22 Comment(0)
R
17

Another option here, is to use adapt the answer from Entity Framework 6 Code First - Custom Type Mapping

public class MyLittlePony {
    public string Name { get; set; }
    public Int32 Argb {
        get {
            return Color.ToArgb();
        }
        set {
            Color = Color.FromArgb(value);
        }
    }

    [NotMapped]
    public Color Color { get; set; }
}

The NotMapped attribute makes the entity framework not try to map the Color property to a column in the database.

Raviv answered 28/8, 2014 at 15:4 Comment(0)
R
3

One option here is to have an int version of the ARGB colours:

public class ColorData
{
   public int Id { get; set; }

   public int Argb { get; set; }

   public System.Drawing.Color Color
   {
      get { return new System.Drawing.Color.FromArgb(this.Argb); }
      set 
      { 
         if(value!=null)
             this.Argb = value.ToArgb(); 
         else
             this.Argb = 0;
      }
   }
}

In your mapping, ignore the Color property specifically by using the fluent bindings:

protected void override OnModelCreating(ModelBuilder builder)
{
   var colorTable = builder.Entity<ColorData>();
   colorTable.HasKey(x => x.Id).HasColumnName("COLOR_ID");
   colorTable.Property(x => x.Argb).HasColumnName("COLOR_ARGB");
   colorTable.Ignore(x=>x.Color);

   colorTable.ToTable("COLOR_DATA");
}

From here you now can store the data from any Color's static methods:

ColorData data = new ColorData();
data.Color = Color.Black;
data.Color = Color.FromName("Black");
data.Color = Color.FromArgb( 0xFF000000 );
data.Color = Color.FromArgb( 255, 0, 0, 0 );

One alternative chosen in the comments is to serialize as XML.

The code above uses an integer, as this uses native, efficient data types to SQL Server and is easily maintainable.

The XML version would take up much more space, is less maintainable and will now add complexity to searching for a specific colour. An expanded System.Drawing.Color type would look like this:

<Color>
    <A>123</A>
    <R>45</R>
    <G>67</G>
    <B>89</B>
    <ScA>0.482352942</ScA>
    <ScR>0.026241‌​2224</ScR>
    <ScG>0.0561284944</ScG>
    <ScB>0.09989873</ScB>
</Color>

Which is easier to search for the color blue?

For the int type, this would be:

SELECT COUNT(1) FROM Customer cust
INNER JOIN Color col
ON cust.FavouriteColorId = color.Id
WHERE col.Argb = 0xFF0000FF

For the XML type:

SELECT COUNT(1) FROM Customer cust
INNER JOIN Color col
ON cust.FavouriteColorId = color.Id
WHERE col.ArgbXml.value('/Color/A') = N'255'
AND col.ArgbXml.value('/Color/R') = N'0'
AND col.ArgbXml.value('/Color/G') = N'0'
AND col.ArgbXml.value('/Color/B') = N'255'
Rael answered 15/7, 2014 at 10:34 Comment(5)
Thanks for the idea but I would prefer to use Color.FromName("name"). I take it there is no way to set the type to Color? Because I want even more types like excel chart serie propertiesDispassion
@MihaiBratulescu how do you suggest you convert Color back to name?Blowzy
@Blowzy Colort.FromsString(myString) and Color.ToString() someting like thisDispassion
@Mihai Bratulescu: What if your color doesn't have a name? This way it is completely flexible, and its just a data access concern. You can set the color to whatever you want.Rael
You can also save the date as a number but this is not the topic of my question. What I wanted to know is if you can user different types for the columns so I tried with code first and it didn't add them to the table (not being supported). I decided to serialize my objects to xmlDispassion
P
1

It's ef core 8 now, and I was just searching for the way to convert color to something storable. So if someone else would look for it too:

in place:

builder.Property(x => x.Color)
    .HasConversion(c => c.ToArgb(), i => Color.FromArgb(i))
    .IsRequired();

global:

public class ColorToIntConverter : ValueConverter<Color, int>
{
    public ColorToIntConverter() : base(v => v.ToArgb(), v => Color.FromArgb(v))
    {
    }
}

and then in the context:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder.Properties<Color>().HaveConversion<ColorToIntConverter>();
}
Practical answered 18/7 at 13:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.