引用与EF核心接口的设计模型

时间:2019-08-26 10:09:04

标签: c# entity-framework-core

我坚持如何设计我的配方模型,以便可以与EF Core一起使用。我发现它很复杂,因为这些成分可以只是原料,也可以是其他配方。 我有以下型号:

public interface IIngredient
{
    int Id { get; }
    string Name { get; }
    decimal KiloPrice { get; }
}

public class RawMaterial : IIngredient
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal KiloPrice { get; set; }
}

public class Recipe : IIngredient
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal KiloPrice => 
        RecipeLines.Sum(x => x.Ingredient.KiloPrice * x.Quantity) / 
        RecipeLines.Sum(x => x.Quantity);
    public List<RecipeLine> RecipeLines { get; set; }
}

public class RecipeLine
{
    public int Id { get; set; }
    public IIngredient Ingredient { get; set; }
    public decimal Quantity { get; set; }
}

是否甚至可以让EF Core映射IIngredient?因为这意味着当原料是RawMaterial时,可以轻松获取KiloPrice,但是当原料是Recipe时,则需要加载RecipeLines来计算KiloPrice。

2 个答案:

答案 0 :(得分:0)

很遗憾,EfCore无法映射接口。解决方法是使用Abstract类。我知道这与设计背道而驰,但这是您所能做到的。

public interface IIngredient
{
    int Id { get; }
    string Name { get; }
    decimal KiloPrice { get; }
}


public abstract class BaseIngredient:IIngredient
{
    int Id { get; }
    string Name { get; }
    decimal KiloPrice { get; }
}


public class RawMaterial : BaseIngredient
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal KiloPrice { get; set; }
}

public class Recipe : BaseIngredient
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal KiloPrice => 
        RecipeLines.Sum(x => x.Ingredient.KiloPrice * x.Quantity) / 
        RecipeLines.Sum(x => x.Quantity);
    public List<RecipeLine> RecipeLines { get; set; }
}

然后,如果您确实要使用接口,则可以使用基类类型的后备字段和接口类型的公共属性。

public class RecipeLine
{
    public int Id { get; set; }
    private readonly BaseIngredient _ingredient;
    public IIngredient Ingredient=>_ingredient;
    public decimal Quantity { get; set; }
}

在您的ModelBuilder中,您需要将PropertyAccessMode指定为字段。

答案 1 :(得分:0)

我不一定需要使用接口。我正在尝试使用您建议的基类。

public abstract class BaseIngredient
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal KiloPrice { get; }
}


public class RawMaterial : BaseIngredient
{
    public decimal KiloPrice { get; set; }
}

public class Recipe : BaseIngredient
{
    public new decimal KiloPrice =>
        RecipeLines.Sum(x => x.Ingredient.KiloPrice * x.Quantity) /
        RecipeLines.Sum(x => x.Quantity);
    public virtual ICollection<RecipeLine> RecipeLines { get; set; }
}

public class RecipeLine
{
    public int Id { get; set; }
    public int RecipeId { get; set; }
    public Recipe Recipe { get; set; }
    public int BaseIngredientId { get; set; }
    public BaseIngredient Ingredient { get; set; }
    public decimal Quantity { get; set; }
}

public class SqliteDbContext :DbContext
{
    public DbSet<RawMaterial> RawMaterials { get; set; }
    public DbSet<Recipe> Recipes { get; set; }
    public DbSet<RecipeLine> RecipeLines { get; set; }
    public DbSet<BaseIngredient> BaseIngredients { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<RawMaterial>().ToTable("RawMaterial");
        modelBuilder.Entity<Recipe>().ToTable("Recipe");
        modelBuilder.Entity<BaseIngredient>().ToTable("BaseIngredient");

        modelBuilder.Entity<RawMaterial>()
            .HasBaseType<BaseIngredient>();
        modelBuilder.Entity<Recipe>()
            .HasBaseType<BaseIngredient>();
        modelBuilder.Entity<BaseIngredient>()
            .HasDiscriminator<string>("Discriminator")
            .HasValue<BaseIngredient>("BaseIngredient")
            .HasValue<RawMaterial>("RawMaterial")
            .HasValue<Recipe>("Recipe");
        modelBuilder.Entity<RecipeLine>()
            .HasOne(x => x.Ingredient);
        modelBuilder.Entity<RecipeLine>()
            .HasOne(x => x.Recipe)
            .WithMany(x => x.RecipeLines)
            .HasForeignKey(x => x.RecipeId);
    }
}

当我使用RecipeLines保存配方时,由于复制了Ingrediënt而收到了ID约束错误。当我第一次保存配方,然后向其添加RecipeLines时,这种关系确实起作用。

但是我现在真正的问题是,KiloPrice始终为0。

Ingrediënt using KiloPrice from the BaseIngredient