Ogólnie zrobiłem projekt od nowa tylko w momencie gdzie w książce było utworzenie tej klasy SeedData zrobiłem tak jak napisała mi @Aenyatia i wygląda to następująco (wszystkie wszystkie powiązane pliki to może łatwiej będzie znaleźć problem):
IProductRepository:
public interface IProductRepository
{
IQueryable<Product> Products { get; }
}
EFProductRepository:
public class EFProductRepository : IProductRepository
{
private readonly ApplicationDbContext context;
public EFProductRepository(ApplicationDbContext context)
{
this.context = context;
}
public IQueryable<Product> Products => context.Products;
}
ApplicationDbContext:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new ProductConfig());
}
public DbSet<Product> Products { get; set; }
}
ProductConfig (zostawiam jeden przykładowy obiekt Product wypełnionymi danymi, tam i tak jest więcej tych obiektów niż tutaj):
public class ProductConfig : IEntityTypeConfiguration<Product>
{
public void Configure(EntityTypeBuilder<Product> builder)
{
builder.HasData(
new Product
{
Name = "Kajak",
Description = "Łódka przeznaczona dla jednej osoby",
Category = "Sporty wodne",
Price = 275
}, new Product
{
...
});
}
}
appsettings.json:
{
"Data": {
"SportStoreProducts": {
"ConnectionString": "Server=(localdb)\\MSSQLLocalDB;Database=SportsStore;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
}
Startup:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration["Data:SportStoreProducts:ConnectionString"]));
services.AddTransient<IProductRepository, EFProductRepository>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStatusCodePages();
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Product}/{action=List}/{id?}");
});
}
}
Program.cs:
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseDefaultServiceProvider(options =>
options.ValidateScopes = false);
}
Teraz, utworzyłem migrację za pomocą komendy
dotnet ef migrations add Initial
Zrobiło mi migrację, plik 20181017214559_Initial:
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Products",
columns: table => new
{
ProductId = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(nullable: true),
Price = table.Column<decimal>(nullable: false),
Description = table.Column<string>(nullable: true),
Category = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Products", x => x.ProductId);
});
migrationBuilder.InsertData(
table: "Products",
columns: new[] { "ProductId", "Category", "Description", "Name", "Price" },
values: new object[,]
{
{ 1, "Sporty wodne", "Łódka przeznaczona dla jednej osoby", "Kajak", 275m },
{ 2, "Sporty wodne", "Chroni i ratuje życie", "Kamizelka ratunkowa", 48.95m },
{ 3, "Piłka nożna", "Zatwierdzona przez FIFA", "Piłka nożna", 19.50m },
{ 4, "Piłka nożna", "Nadadzą Twojemu boisku profesjonalny wygląd", "Flagi narożne", 34.95m },
{ 5, "Piłka nożna", "Składamy stadion na 3 500 osób", "Stadion", 79500m },
{ 6, "Szachy", "Zwiększa efektywność mózgu o 75%", "Czapka", 16m },
{ 7, "Szachy", "Zmniejsza szanse przeciwnika", "Niestabilne krzesło", 29.95m },
{ 8, "Szachy", "Przyjemna gra dla całej rodziny", "Ludzka szachownica", 75m },
{ 9, "Szachy", "Figura pokryta złotem i wysadzana diamentami", "Błyszczący król", 1200m }
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Products");
}
}
I plik ApplicationDbContextModelSnapshot:
[DbContext(typeof(ApplicationDbContext))]
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.1.4-rtm-31024")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("SportsStore.Models.Product", b =>
{
b.Property<int>("ProductId")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("Category");
b.Property<string>("Description");
b.Property<string>("Name");
b.Property<decimal>("Price");
b.HasKey("ProductId");
b.ToTable("Products");
b.HasData(
new { ProductId = 1, Category = "Sporty wodne", Description = "Łódka przeznaczona dla jednej osoby", Name = "Kajak", Price = 275m },
new { ProductId = 2, Category = "Sporty wodne", Description = "Chroni i ratuje życie", Name = "Kamizelka ratunkowa", Price = 48.95m },
new { ProductId = 3, Category = "Piłka nożna", Description = "Zatwierdzona przez FIFA", Name = "Piłka nożna", Price = 19.50m },
new { ProductId = 4, Category = "Piłka nożna", Description = "Nadadzą Twojemu boisku profesjonalny wygląd", Name = "Flagi narożne", Price = 34.95m },
new { ProductId = 5, Category = "Piłka nożna", Description = "Składamy stadion na 3 500 osób", Name = "Stadion", Price = 79500m },
new { ProductId = 6, Category = "Szachy", Description = "Zwiększa efektywność mózgu o 75%", Name = "Czapka", Price = 16m },
new { ProductId = 7, Category = "Szachy", Description = "Zmniejsza szanse przeciwnika", Name = "Niestabilne krzesło", Price = 29.95m },
new { ProductId = 8, Category = "Szachy", Description = "Przyjemna gra dla całej rodziny", Name = "Ludzka szachownica", Price = 75m },
new { ProductId = 9, Category = "Szachy", Description = "Figura pokryta złotem i wysadzana diamentami", Name = "Błyszczący król", Price = 1200m }
);
});
#pragma warning restore 612, 618
}
}
Te 2 pliki utworzyło mi w katalogu Mirations. I teraz po odpaleniu apki wyskakuje błąd że ProductId jest nullem, natomiast gdzieś w necie wyczytałem że wystarczy pierwszą migrację zrobić podając id na sztywno, a potem te id będą się same wypełniać, więc idąc tym tropem uzupełniłem ProductId we wszystkich obiektach, po odpaleniu mam taki problem:
SqlException: Cannot open database "SportsStore" requested by the login. The login failed.
Login failed for user 'DESKTOP-69SKPHN\Papryk'.
Tak więc coś się z loginem chyba nie zgadza. Mam wiele niejasności, np. czy w tym pliku Program.cs dalej trzeba użyć metody UseDefaultServiceProvider i ustawiać ValidateScopes na false, czy ten ConnectionString jest dobry, może inaczej jakoś to się teraz robi. Mogę to jeszcze raz od nowa napisać jeśli coś popsułem w migracjach, ogólnie ciężki temat.
#Edit
Probowałem się połączyć ręcznie z bazą, wpisałem w visualu ręcznie nazwę tego serwera i jak chciałem znaleźć jakąkolwiek nazwę bazy to po chwili wczytywania wyrzuciło mi taki błąd: