-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot configure different Identity column facets for different tables in TPC mapping #28195
Labels
area-model-building
closed-fixed
The issue has been fixed and is/will be included in the release indicated by the issue milestone.
type-enhancement
Milestone
Comments
Split off from #27970 |
AndriySvyryd
added
the
closed-fixed
The issue has been fixed and is/will be included in the release indicated by the issue milestone.
label
Jul 1, 2022
This still doesn't work. Exception:
Schema: CREATE TABLE [Cats] (
[Id] int NOT NULL,
[Name] nvarchar(max) NOT NULL,
[FoodId] uniqueidentifier NULL,
[Vet] nvarchar(max) NULL,
[EducationLevel] nvarchar(max) NOT NULL,
CONSTRAINT [PK_Cats] PRIMARY KEY ([Id])
);
CREATE TABLE [Dogs] (
[Id] int NOT NULL,
[Name] nvarchar(max) NOT NULL,
[FoodId] uniqueidentifier NULL,
[Vet] nvarchar(max) NULL,
[FavoriteToy] nvarchar(max) NOT NULL,
CONSTRAINT [PK_Dogs] PRIMARY KEY ([Id])
);
CREATE TABLE [FarmAnimals] (
[Id] int NOT NULL,
[Name] nvarchar(max) NOT NULL,
[FoodId] uniqueidentifier NULL,
[Value] decimal(18,2) NOT NULL,
[Species] nvarchar(max) NOT NULL,
CONSTRAINT [PK_FarmAnimals] PRIMARY KEY ([Id])
);
CREATE TABLE [Humans] (
[Id] int NOT NULL,
[Name] nvarchar(max) NOT NULL,
[FoodId] uniqueidentifier NULL,
[FavoriteAnimalId] int NULL,
CONSTRAINT [PK_Humans] PRIMARY KEY ([Id])
); Code: // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using (var context = new AnimalsContext())
{
await context.Database.EnsureDeletedAsync();
Console.WriteLine(context.Model.ToDebugString());
Console.WriteLine();
await context.Database.EnsureCreatedAsync();
var catFood = new PetFood("Lily's Kitchen", LifeStage.Adult);
var dogFood = new PetFood("Canagan", LifeStage.Adult);
var hay = new FarmFood("Hay");
var sushi = new HumanFood("Sushi", 670);
var arthur = new Human("Arthur") { Food = sushi };
var wendy = new Human("Wendy");
var christi = new Human("Christi");
var alice = new Cat("Alice", "MBA") { Vet = "Pengelly", Food = catFood, Humans = { arthur, wendy } };
var mac = new Cat("Mac", "Preschool") { Vet = "Pengelly", Food = catFood, Humans = { arthur, wendy } };
var toast = new Dog("Toast", "Mr. Squirrel") { Vet = "Pengelly", Food = dogFood, Humans = { arthur, wendy } };
var clyde = new FarmAnimal("Clyde", "Equus africanus asinus") { Value = 100.0m, Food = hay };
wendy.FavoriteAnimal = toast;
arthur.FavoriteAnimal = alice;
christi.FavoriteAnimal = clyde;
await context.AddRangeAsync(wendy, arthur, christi, alice, mac, toast, clyde);
await context.SaveChangesAsync();
}
Console.WriteLine();
using (var context = new AnimalsContext())
{
foreach (var human in context.Humans)
{
Console.WriteLine($"Human.FavoriteAnimalId = {context.Entry(human).Property("FavoriteAnimalId").CurrentValue}");
}
}
public abstract class Animal
{
protected Animal(string name)
{
Name = name;
}
public int Id { get; set; }
public string Name { get; set; }
public abstract string Species { get; }
public Food? Food { get; set; }
}
public abstract class Pet : Animal
{
protected Pet(string name)
: base(name)
{
}
public string? Vet { get; set; }
public ICollection<Human> Humans { get; } = new List<Human>();
}
public class FarmAnimal : Animal
{
public FarmAnimal(string name, string species)
: base(name)
{
Species = species;
}
public override string Species { get; }
[Precision(18, 2)]
public decimal Value { get; set; }
public override string ToString()
=> $"Farm animal '{Name}' ({Species}/{Id}) worth {Value:C} eats {Food?.ToString() ?? "<Unknown>"}";
}
public class Cat : Pet
{
public Cat(string name, string educationLevel)
: base(name)
{
EducationLevel = educationLevel;
}
public string EducationLevel { get; set; }
public override string Species
=> "Felis catus";
public override string ToString()
=> $"Cat '{Name}' ({Species}/{Id}) with education '{EducationLevel}' eats {Food?.ToString() ?? "<Unknown>"}";
}
public class Dog : Pet
{
public Dog(string name, string favoriteToy)
: base(name)
{
FavoriteToy = favoriteToy;
}
public string FavoriteToy { get; set; }
public override string Species
=> "Canis familiaris";
public override string ToString()
=> $"Dog '{Name}' ({Species}/{Id}) with favorite toy '{FavoriteToy}' eats {Food?.ToString() ?? "<Unknown>"}";
}
public class Human : Animal
{
public Human(string name)
: base(name)
{
}
public override string Species
=> "Homo sapiens";
public Animal? FavoriteAnimal { get; set; }
public ICollection<Pet> Pets { get; } = new List<Pet>();
public override string ToString()
=> $"Human '{Name}' ({Species}/{Id}) with favorite animal '{FavoriteAnimal?.Name ?? "<Unknown>"}'"
+ $" eats {Food?.ToString() ?? "<Unknown>"}";
}
public abstract class Food
{
public Guid Id { get; set; }
}
public class PetFood : Food
{
public PetFood(string brand, LifeStage lifeStage)
{
Brand = brand;
LifeStage = lifeStage;
}
public string Brand { get; set; }
public LifeStage LifeStage { get; set; }
public override string ToString()
=> $"Pet food by '{Brand}' ({Id}) for life stage {LifeStage}";
}
public enum LifeStage
{
Juvenile,
Adult,
Senior
}
public class HumanFood : Food
{
public HumanFood(string name, int calories)
{
Name = name;
Calories = calories;
}
[Column("Name")]
public string Name { get; set; }
public int Calories { get; set; }
public override string ToString()
=> $"{Name} ({Id}) with calories {Calories}";
}
public class FarmFood : Food
{
public FarmFood(string name)
{
Name = name;
}
[Column("Name")]
public string Name { get; set; }
public override string ToString()
=> $"{Name} ({Id})";
}
public class AnimalsContext : DbContext
{
public DbSet<Animal> Animals
=> Set<Animal>();
public DbSet<Pet> Pets
=> Set<Pet>();
public DbSet<FarmAnimal> FarmAnimals
=> Set<FarmAnimal>();
public DbSet<Cat> Cats
=> Set<Cat>();
public DbSet<Dog> Dogs
=> Set<Dog>();
public DbSet<Human> Humans
=> Set<Human>();
public DbSet<Food> Foods
=> Set<Food>();
public DbSet<PetFood> PetFoods
=> Set<PetFood>();
public DbSet<FarmFood> FarmFoods
=> Set<FarmFood>();
public DbSet<HumanFood> HumanFoods
=> Set<HumanFood>();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.EnableSensitiveDataLogging()
.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}");
optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Animal>().UseTpcMappingStrategy();
modelBuilder.Entity<Cat>().Property(e => e.Id).ValueGeneratedOnAdd().UseIdentityColumn(1, 4);
modelBuilder.Entity<Dog>().Property(e => e.Id).ValueGeneratedOnAdd().UseIdentityColumn(2, 4);
modelBuilder.Entity<FarmAnimal>().Property(e => e.Id).ValueGeneratedOnAdd().UseIdentityColumn(3, 4);
modelBuilder.Entity<Human>().Property(e => e.Id).ValueGeneratedOnAdd().UseIdentityColumn(4, 4);
modelBuilder.Entity<Food>().UseTpcMappingStrategy();
modelBuilder.Entity<FarmAnimal>().Property(e => e.Species);
modelBuilder.Entity<Human>()
.HasMany(e => e.Pets)
.WithMany(e => e.Humans)
.UsingEntity<Dictionary<object, string>>(
"PetsHumans",
r => r.HasOne<Pet>().WithMany().OnDelete(DeleteBehavior.Cascade),
l => l.HasOne<Human>().WithMany().OnDelete(DeleteBehavior.ClientCascade));
}
} |
modelBuilder.Entity<Cat>().ToTable(tb => tb.Property(e => e.Id).UseIdentityColumn(1, 4));
modelBuilder.Entity<Dog>().ToTable(tb => tb.Property(e => e.Id).UseIdentityColumn(2, 4));
modelBuilder.Entity<FarmAnimal>().ToTable(tb => tb.Property(e => e.Id).UseIdentityColumn(3, 4));
modelBuilder.Entity<Human>().ToTable(tb => tb.Property(e => e.Id).UseIdentityColumn(4, 4)); |
|
Adding table names to the configuration gets us back to the original exception: modelBuilder.Entity<Cat>().ToTable("Cats", tb => tb.Property(e => e.Id).UseIdentityColumn(1, 4));
modelBuilder.Entity<Dog>().ToTable("Dogs", tb => tb.Property(e => e.Id).UseIdentityColumn(2, 4));
modelBuilder.Entity<FarmAnimal>().ToTable("FarmAnimals", tb => tb.Property(e => e.Id).UseIdentityColumn(3, 4));
modelBuilder.Entity<Human>().ToTable("Humans", tb => tb.Property(e => e.Id).UseIdentityColumn(4, 4)); |
Hey, @ajcvickers any news on this? I run into the same problem. |
@GermanOller2001 This has been fixed in EF 7.0.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
area-model-building
closed-fixed
The issue has been fixed and is/will be included in the release indicated by the issue milestone.
type-enhancement
Tried to do this for value generation using Identity columns with gaps. Possibly just part of #19811, but we should check that this scenario works.
Tables:
Full code:
The text was updated successfully, but these errors were encountered: