【问题标题】:Cast entities implicitly with EF Core使用 EF Core 隐式转换实体
【发布时间】:2019-12-02 15:40:51
【问题描述】:

假设我有以下实体

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; }

我想从 DB(所有记录)中创建 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 可以做到这样的技巧吗?

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

    • 嗨@nAviD,我如何告诉 EF 使用重载运算符?
    • 当你的类有隐式操作符时,它应该可以自动转换为目标类。虽然我没有在 EF 上测试过。另一种方法是使用 AutoMapper
    • @da_sann 我只是忘了在我之前的评论中提到你。
    • 好的,这不起作用,因为 EF 仅通过 Value Conversions 提供转换,这在这种情况下是不可能的,并且 AutoMapper 不能解决问题..由于某些原因,由于某些 EF 内部逻辑,仍然得到相同的异常(虽然堆栈跟踪有点不同......)
    【解决方案2】:

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

    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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-30
      • 2021-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多