如何将MongoDB模式迁移到SQL Server模型“ EF-Core”?

时间:2019-02-24 01:11:25

标签: c# mongodb entity-framework .net-core

我有以下MongoDB模式

const userSchema = new mongoose.Schema(
    {
        email: { type: String, unique: true },

        tokens: [{ accessToken: String, kind: String }],

        permissions: [Number],
        registration: { type: String, match: /(CLIENT|CUSTOMER|UNKOWN)/ },

        profile: {
            name: String,
            gender: String,
            location: String,
            website: String,
            picture: String,
        },

        clientCategories: [String],
    },
    { timestamps: true },
);

我想为SQL Server和EF Core实现相同的模型,我尝试了以下实现

public class UserModel : IBaseUserModel
{
    [Key]
    public long Id { get; set; }

    [Required, EmailAddress]
    public string Email { get; set; }

    [Required]
    public ICollection<AccessToken> AccessTokens { get; set; }

    [Required]
    public ICollection<int> Permissions { get; set; }

    [Required, RegularExpression(@"^CLIENT|CUSTOMER|UNKOWN$")]
    public string Registration { get; set; }

    [Required]
    public Profile Profile { get; set; }
}

/// <summary> 
///     Basic user properties
/// </summary>
public interface IBaseUserModel
{
    long Id { get; set; }

    string Email { get; set; }

    ICollection<AccessToken> AccessTokens { get; set; }

    ICollection<int> Permissions { get; set; }

    string Registration { get; set; }

    Profile Profile { get; set; }
}

/// <summary>
///     The definition of the AccessToken
/// </summary>
public struct AccessToken { public string key, provider; }

/// <summary>
///     The definition of the User's Profile
/// </summary>
public struct Profile { public string name, gender, location, avatar; }

但我遇到了错误

  

无法映射属性'UserModel.AccessTokens',因为它的类型为'AccessToken []',它不是受支持的原始类型或有效实体类型。要么显式映射此属性,要么使用“ [NotMapped]”属性或“ OnModelCreating”中的“ EntityTypeBuilder.Ignore”忽略它。

我知道EF Core支持type conversions,但是我不知道如何使用该功能,这是我第一次使用此框架,谢谢。

侧面,我使用abstract类的原因是,我将从该类扩展其他类,例如public class CustomerModel : UserModel, ICustomer { }

1 个答案:

答案 0 :(得分:0)

type conversions对我来说不太清楚,但是现在很有意义,下面的代码可以解决问题

protected override void OnModelCreating (ModelBuilder modelBuilder)
{
    var StringListToStringConverter = new ValueConverter<ICollection<string>, string>(_strings => string.Join(";", _strings), _string => _string.Split(new[] { ';' }));
    var IntListToStringConverter = new ValueConverter<ICollection<int>, string>(_ints => string.Join(";", _ints), _string => Array.ConvertAll(_string.Split(new[] { ';' }), int.Parse));
    var AccessTokenToStringConverter = new ValueConverter<ICollection<AccessToken>, string>(_token => JsonConvert.SerializeObject(_token), _string => JsonConvert.DeserializeObject<ICollection<AccessToken>>(_string));
    var ProfileToStringConverter = new ValueConverter<Profile, string>(_token => JsonConvert.SerializeObject(_token), _string => JsonConvert.DeserializeObject<Profile>(_string));

    modelBuilder
        .Entity<UserModel>()
        .Property(e => e.Permissions)
        .HasConversion(IntListToStringConverter);

    modelBuilder
        .Entity<UserModel>()
        .Property(e => e.AccessTokens)
        .HasConversion(AccessTokenToStringConverter);

    modelBuilder
        .Entity<UserModel>()
        .Property(e => e.Profile)
        .HasConversion(ProfileToStringConverter);

    modelBuilder
        .Entity<ClientModel>()
        .Property(e => e.Categories)
        .HasConversion(StringListToStringConverter);
}

我认为将属性转换为字符串并将其存储在同一表中要比将每个属性保存到新表中更好。