使用EF Core隐式转换实体

时间:2019-12-02 15:40:51

标签: c# .net entity-framework implicit-conversion ef-core-2.2

假设我有以下实体

public abstract class BaseEntity {
 public Guid Id { get;set; }
 public string Prop1 { get;set; }
 public long Prop2 { get;set; }
 public byte Type_Id { get;set; }
}

public class Type1 : BaseEntity { }

public class Type2 : BaseEntity { }

public class Type3 : BaseEntity {
  public long? Prop3 { get;set; }
}

以及以下上下文映射:

builder.ToTable("Entities").HasDiscriminator(a => a.Type_Id)
                .HasValue<Type1>((byte)Types.Type1)
                .HasValue<Type2>((byte)Types.Type2)
                .HasValue<Type3>((byte)Types.Type3);
// in DbContext
public DbSet<BaseEntity> Entities { get; set; }

我想从数据库创建get IQueryable(所有记录)Type1和Type2在Prop3中将为null, 我执行以下操作:

public DbSet<BaseEntity> DBSet { get;set; }
private static readonly MethodInfo FromSqlMethodInfo = typeof(RelationalQueryableExtensions).GetTypeInfo().GetDeclaredMethods("FromSql").Single(mi => mi.GetParameters().Length == 3);
public IQueryable<Type3> GetEntities(IEnumerable<Guid> ids) {
                RawSqlString sql = @"select [Id]
          ,[Prop1]
          ,[Prop2]
          ,[Prop3]
          ,[Type_Id]
            from [dbo].[Entities] where Id in (select item from @Ids)";
                var ids = new SqlParameter("@Ids", SqlDbType.Structured);
                ids.TypeName = typeof(Guid).Name.ToLowerInvariant() + "_item_list";
                ids.Direction = ParameterDirection.Input;
                ids.Value = CreateItemList(tpIds);
                var param = new object[] { ids };
                var conversion = from s in DBSet select (Type3)s;
                var result = conversion.Provider.CreateQuery<Type3>(Expression.Call(null, FromSqlMethodInfo.MakeGenericMethod(typeof(Type3)), conversion.Expression,
                   Expression.Constant(sql), Expression.Constant(param)));
                return result;
            }


var query = GetEntities(someIds);
var result = query.OrderBy(m => m.Type_Id).Skip(skip).Take(take).ToList();

查询成功执行,但是在调用ToLIst时,将引发异常: 无法将类型'Type1'的对象强制转换为类型'Type3',这是我们所期望的,因为我们没有告知应如何转换...所以问题是:EF Core可以完成这种技巧吗?

2 个答案:

答案 0 :(得分:1)

您可以使用隐式重载强制转换运算符。 Here是帮助您的链接。

答案 1 :(得分:0)

好,所以目前唯一可行的解​​决方案是再创建一个具有所有必需属性的实体,

public class NewEntity {
 public Guid Id { get;set; }
 public string Prop1 { get;set; }
 public long Prop2 { get;set; }
 public byte Type_Id { get;set; }
 public long? Prop3 { get;set; }
}

将新的DbSet添加到上下文中

public DbSet<NewEntity> NewEntities { get; set; }

将其映射到旧表并正确更新上下文配置, 避免生成多余的列(在这种情况下,EF可能会 尝试添加名称为NewEntity_Prop1,NewEntity_Prop2等的新列。 以及外键和索引

public override void Configure(EntityTypeBuilder<NewEntity> builder) {
    builder.ToTable("Entities");
    builder.Property(m => m.Prop1).HasColumnName("Prop1");
    builder.Property(m => m.Prop2).HasColumnName("Prop2");
    builder.Property(m => m.Type_Id).HasColumnName("Type_Id");
    builder.HasOne<BaseEntity>().WithOne().HasForeignKey<NewEntity>(e => e.Id);
}

或创建视图

 public DbQuery<NewEntity> NewEntities { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder) {
 modelBuilder.Query<NewEntity>().ToView("NewEntities");
            base.OnModelCreating(modelBuilder);
}