entity-framework-6azure-mobile-servicesuniqueidentifieref-fluent-apief-code-first-mapping

Entity Framework: how to set the type of a column as uniqueidentifier with Fluent API


I use Entity Framework 6, code-first.

I have a column <string> Id that is created by a framework (Azure Mobile Server SDK), which I don't have access to.

public abstract class EntityData
{
    [Key]
    [TableColumn(TableColumnType.Id)]
    public string Id { get; set; }

    ...
}

If I don't perform any action, such column is mapped as a nvarchar(MAX) in SQL Server.

I have been able to turn it into a char(36) with this snippet in Fluent API:

PropertyConventionConfiguration pkConf = modelBuilder.Properties<string>().Where(p => p.Name == "Id");
pkConf.Configure(p => p.IsUnicode(false));
pkConf.Configure(p => p.HasMaxLength(36));
pkConf.Configure(p => p.IsFixedLength());

I want to set it as uniqueidentifier.

How can I do that with a similar Fluent API code snippet?

Thank you very much!


Solution

  • You can use a custom value converter or leverage the built in GuidToStringConverter : learn.microsoft.com/en-us/ef/core/modeling/value-conversions . A few side notes - you should create a class that inherits from this abstract class. This not only offers a layer of abstraction, it will also allow you to control more precisely how you store and access your data. Also, as you're probably aware, GUIDs make horrible PKs!

    EDIT:

    If you're using EF 6, this feature won't be available. You will therefore, need to create a wrapper property or use a stored procedure. Here's an example, sample code can be found here: https://github.com/ibrahm2/entityframework6-map-string-to-guid

    Method 1: Wrapper Property

    1. Create a class that inherits from EntityData. For this example, let's call it WrapperTable e.g.
    2. Add a property called Id with type Guid and mask the base Id property by using the new modifier. Have it return a cast version of Id from the base class as Guid. This will mask the base property. It isn't best practice so if you're uncomfortable with this, the alternative would be to create a new property e.g. called Key that wraps around Id.
    3. If your configuration, map the inherited class to the EntityDate table.

      modelBuilder.Entity().ToTable("EntityData");

    Method 2: Stored Procedure

    1. Create a stored procedure that takes in a varchar as a parameter for the Id field
    2. Map the stored procedure to the Insert function of the Entity e.g.:

      modelBuilder.Entity().MapToStoredProcedures(prop=>prop.Insert(sp=>sp.HasName("sp_InsertTable").Parameter(pm => pm.Id, "@id")));

    3. Have the stored procedure insert the varchar into your uniqueidentifier field.