Asp.Net Core Creating Database - entity-framework

I am using .net core technology and i am getting some error when i want to create new database.
This is my NorthwindContext class, i am writing server location here.
public class NorthwindContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=(localdb)\mssqllocaldb;Database=Northwind;Persist Security Info=True; User ID=sa; Password=xxxxxxxx");
}
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
}
And I want to create database with Console Project
public class Program
{
public static void Main(string[] args)
{
NorthwindContext context = new NorthwindContext();
Product product1 = new Product() {ProductId = 1, CategoryId = 1, ProductName = "Asus Notebook", UnitPrice = 5000, UnitsInStock = 100};
context.Products.Add(product1);
context.SaveChanges();
var products = context.Products.OrderBy(p => p.ProductName);
foreach (var product in products)
{
Console.WriteLine(product.ProductName);
}
}
}
In the result I am getting these:
"An unhandled exception of type 'System.Data.SqlClient.SqlException' occurred in Microsoft.EntityFrameworkCore.dll.
Additional information: Login failed for user 'sa'."
I am waiting your helps, thanks in advance.

Error message contains enough information indeed.
"login failed for user 'sa'"
Use connectionsting with trustedconnection instead of username&password.
It looks like:
connectionString="Server=(localdb)\mssqllocaldb;Database=Northwind;Trusted_Connection=True;"

Related

EF Core 6 : AutoInclude(false) still loads Navigation

READ THE EDIT!
I have two Entities :
public class Principal {
public Guid Id { get; private set; }
public Collection<Dependant> Dependants { get; init; } = new();
public Principal() { }
}
public class Dependant{
public Guid Id { get; private set; }
public Guid PrincpalId { get; private set; }
public Principal Principal{ get; private set; }
public Dependant() { }
}
I access Principal through a repository :
internal class PrincipalsRepository {
private readonly DbSet<Princpal> db;
public PrincipalsRepository (DbSet<Princpal> db) {
this.db = db;
}
public async Task AddAsync(Principal p) {
await this.db.AddAsync(p).ConfigureAwait(false);
}
public async Task<Principal>> GetByIdAsync(Guid id) {
//Notice how there's no Include here!
return await db
.FirstOrDefaultAsync(p => p.Id == id)
.ConfigureAwait(false);
}
}
I configure them like this :
public void Configure(EntityTypeBuilder<Principal > builder) {
builder
.ToTable("Principals")
.HasKey(p => p.Id);
builder
.Navigation(p => p.Dependants)
.AutoInclude(false); //THIS!!!!!
builder
.OwnsMany(p =>
p.Dependants,
navBuilder => {
navBuilder.ToTable("Dependants");
navBuilder.Property<Guid>("Id"); //Important: without this EF would try to use 'int'
navBuilder.HasKey("Id");
navBuilder
.WithOwner(v => v.Principal)
.HasForeignKey(v => v.PrincipalId);
}
);
}
The repo is used in a DbContext:
//PLEASE NOTE: This code might seem a bit broken to you because it's a trimmed down copy-paste from the real code.
public abstract class MyDatabase<TContext> : DbContext
where TContext : DbContext {
public PrincipalsRepository PrincipalsRepository = new PrincipalsRepository (DbPrincipals);
//This is exposed for unit tests
public DbSet<Principal> DbPrincipals { get; set; }
public MyDatabase(DbContextOptions<TContext> options)
: base(options) {
}
}
I configure an in-memory Db :
//PLEASE NOTE: Not everything is detailed here. It's a copy paste from a bigger code base)
private static Database CreateDatabase() {
var _connection = new SqliteConnection("Filename=:memory:");
_connection.Open();
_contextOptions = new DbContextOptionsBuilder<MyDatabase>()
.UseSqlite(_connection)
.Options;
var context = new MyDatabase(_contextOptions);
return context;
}
I run a unit test where I insert an Principal entity with a Dependant:
// Step 1 : Init
using var context = CreateDatabase();
var repo = new PrincipalsRepository(context.DbPrincipals);
// Step 2 : Insertion
var p = new Principal();
p.Dependants.Add(new Dependant());
await context.PrincipalsRepo.AddAsync(p).ConfigureAwait(false);
await context.SaveChangesAsync().ConfigureAwait(false);
// Step 3 : Read back
var p2 = context.PrincipalsRepo.GetByIdAsync(p.Id).ConfigureAwait(false);
And then...
Assert.Empty(p2!.Dependants); //The unit test fails because I can see that the Dependant has been loaded
What am I doing wrong? Why is it loaded despite me saying "AutoInclude(false)" ?
Note: After adding AutoInclude(false), creating a new migration changed the Db's model snapshot, but the migration itself was empty. Is that normal???
EDIT:
Like #DavidG and #Gert Arnold suggested in the comments, apparently I need to instantiate a brand new DbContext to do the test, because EF is somehow smart enough to pick up that p2 is the "same" as p, and... populates its navigation links (i.e. does the auto Include) without me asking?!?
I absolutely don't understand what's the logic here (in terms of behaviour consistency).
When I change the test and query p2 from a brand new DbContext instance, it works as I would expect it. I.e. it does find the Principal (p2) but its Dependants collection is empty.
Is this documented anywhere, in one form or another? Even as an implicit sentence that seems obvious on some Microsoft help page?

Duplicating entities from EF Core into MongoDB on Creation or Edit

I'm working on an asp.net core project that has both sql server and mongodb. the task is to add or update any entity that is being added or updated to sql server(using ef core), to mongo.
I figured I can override OnSaveChangesAsync but I have no idea how to access the entities that are being changed there in order to call the mongo service's update and insert methods on them.
This can be done by using interceptors:
The Model:
public class Student
{
public Guid Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
DbContext:
public class StudentsContext : DbContext
{
public DbSet<Student> Students { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.AddInterceptors(new UpdateMongoInterceptor())
.UseSqlite(#"DataSource=C:\Databases\Students.db");
}
}
SaveChangesInterceptor:
public class UpdateMongoInterceptor : SaveChangesInterceptor
{
public override InterceptionResult<int> SavingChanges(DbContextEventData eventData, InterceptionResult<int> result)
{
UpdateMongoDb(eventData.Context);
return result;
}
private static void UpdateMongoDb(DbContext context)
{
context.ChangeTracker.DetectChanges();
foreach (var entry in context.ChangeTracker.Entries())
{
switch (entry.State)
{
case EntityState.Modified:
case EntityState.Added:
if (entry.Entity is Student student)
{
//Update MongoDB...
Console.WriteLine($"Push student entity to mongoDB Id: {student.Id}, Name:{student.Name}, Age:{student.Age}");
}
break;
}
}
}
Usege:
using (var context = new StudentsContext())
{
var student = new Student {Id = Guid.NewGuid(), Name = "Jon Snow", Age = 25};
context.Add(student);
context.SaveChanges();
}
Interceptors documentations can be found here: Example: SaveChanges interception for auditing
** If you are using DB generated keys you should override SavedChanges and figure out of the entity was updated or added.

Why table not exists while I create a in-memory sqlite database with entityframework core?

I want to create an in-memory SQLite database.
Here is startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<TestDBContext>().AddEntityFrameworkSqlite();
}
Here is the Model of database:
public class TestModel
{
public string UserName { get; set; }
[Key]
public string id { get; set; }
}
Here is the DBContext of database:
public class TestDBContext : DbContext
{
public virtual DbSet<TestModel> Test { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=:memory:");
}
}
And here is the controller:
private readonly TestDBContext TestDBContext;
public HomeController(ILogger<HomeController> logger,TestDBContext _TestDBContext)
{
_logger = logger;
this.TestDBContext = _TestDBContext;
}
public IActionResult Index()
{
TestDBContext.Database.EnsureCreated();
TestDBContext.SaveChanges();
TestDBContext.Test.Add(new TestModel() { User = DateTime.Now.ToString(),id=Guid.NewGuid().ToString() });
TestDBContext.SaveChanges();
return View(TestDBContext.Test.ToList());
}
Every time it runs, it will report an error:
Inner Exception 1:
SqliteException: SQLite Error 1: 'no such table: Test'.
I have used the EnsureCreated and the EnsureCreated runs without any error. Why it still be like this?
EF Core's DbContext always opens and closes connections to the database automatically, unless you pass an already open connection. And when the connection gets closed, the Sqlite In-memory database will be removed. So I modified your code a little bit like this.
public void ConfigureServices(IServiceCollection services)
{
var connection = new SqliteConnection("datasource=:memory:");
connection.Open();
services.AddControllersWithViews();
services.AddDbContext<TestDBContext>(options =>
{
options.UseSqlite(connection);
});
}
And the Database Context class - I added the constructors so that I can provide the parameters.
public class TestDBContext : DbContext
{
public TestDBContext(DbContextOptions options) : base(options)
{
}
protected TestDBContext()
{
}
public virtual DbSet<TestModel> Test { get; set; }
}
And instead of creating the database in the Index action method, create it in the startup.
Also, opt to use the DbContext.Database.Migrate() method instead of EnsureCreated else you won't be able to use migrations later down the line.

EfCore 3 and Owned Type in same table, How do you set owned instance

How do you set owned type instance with efcore3?
In following example an exception is raised
'The entity of type 'Owned' is sharing the table 'Principals' with
entities of type 'Principal', but there is no entity of this type with
the same key value that has been marked as 'Added'.
If I set Child property inline savechanges doesn't update child properties
I can't find any example about this. I tried with several efcore3 builds and daily builds. What didn't I understand?
using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
namespace TestEF
{
class Program
{
static void Main(string[] args)
{
var id = Guid.NewGuid();
using (var db = new Ctx())
{
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
var p = new Principal {Id = id};
db.Principals.Add(p);
db.SaveChanges();
}
using (var db = new Ctx())
{
var p = db.Principals.Single(o => o.Id == id);
p.Child = new Owned();
p.Child.Prop1 = "Test2";
p.Child.Prop2 = "Test2";
db.SaveChanges();
}
}
public class Principal
{
public Guid Id { get; set; }
public Owned Child { get; set; }
}
public class Owned
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
public class Ctx : DbContext
{
public DbSet<Principal> Principals { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=TestEF;Trusted_Connection=True;Persist Security Info=true");
}
protected override void OnModelCreating(ModelBuilder mb)
{
var emb = mb.Entity<Principal>();
emb
.OwnsOne(o => o.Child, cfg =>
{
cfg.Property(o => o.Prop1).HasMaxLength(30);
//cfg.WithOwner();
});
}
}
}
}
This is a bug, filed at https://github.com/aspnet/EntityFrameworkCore/issues/17422
As a workaround you could make the child appear as modified:
db.ChangeTracker.DetectChanges();
var childEntry = db.Entry(p.Child);
childEntry.State = EntityState.Modified;
db.SaveChanges();
Try this instead:
_context.Update(entity);
This will update all the owned properties so SaveChanges() updates them, too.

Seeding not working in Entity Framework Code First Approach

I am developing a .Net project. I am using entity framework code first approach to interact with database. I am seeding some mock data to my database during development. But seeding is not working. I followed this link - http://www.entityframeworktutorial.net/code-first/seed-database-in-code-first.aspx.
This is my ContextInitializer class
public class ContextInitializer : System.Data.Entity.CreateDatabaseIfNotExists<StoreContext>
{
protected override void Seed(StoreContext context)
{
IList<Brand> brands = new List<Brand>();
brands.Add(new Brand { Name = "Giordano" ,TotalSale = 1 });
brands.Add(new Brand { Name = "Nike" , TotalSale = 3 });
foreach(Brand brand in brands)
{
context.Brands.Add(brand);
}
base.Seed(context);
context.SaveChanges();
}
}
This is my context class
public class StoreContext : DbContext,IDisposable
{
public StoreContext():base("DefaultConnection")
{
Database.SetInitializer(new ContextInitializer());
}
public virtual DbSet<Category> Categories { get; set; }
public virtual DbSet<Brand> Brands { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
This is my brand class
public class Brand
{
public int Id { get; set; }
[Required]
[MaxLength(40)]
public string Name { get; set; }
public int TotalSale { get; set; }
}
I searched solutions online and I followed instructions. I run context.SaveChanges as well. But it is not seeding data to database. Why it is not working?
You are taking the wrong initializer, CreateDatabaseIfNotExists is called only if the database not exists!
You can use for example DropCreateDatabaseIfModelChanges:
Solution 1)
public class ContextInitializer : System.Data.Entity.DropCreateDatabaseIfModelChanges<StoreContext>
{
You have to take care with this approach, it !!!removes!!! all existing data.
Solution 2)
Create a custom DbMigrationsConfiguration:
public class Configuration : DbMigrationsConfiguration<StoreContext>
{
public Configuration()
{
// Take here! read about this property!
this.AutomaticMigrationDataLossAllowed = true;
this.AutomaticMigrationsEnabled = false;
}
protected override void Seed(StoreContext context)
{
IList<Brand> brands = new List<Brand>();
brands.Add(new Brand { Name = "Giordano", TotalSale = 1 });
brands.Add(new Brand { Name = "Nike", TotalSale = 3 });
foreach (Brand brand in brands)
{
context.Brands.AddOrUpdate(m => m.Name, brand);
}
base.Seed(context);
context.SaveChanges();
}
}
In this way you can called( !!Before you create the DbContext or in the DbContext constructor!!):
// You can put me also in DbContext constuctor
Database.SetInitializer(new MigrateDatabaseToLatestVersion<StoreContext , Yournamespace.Migrations.Configuration>("DefaultConnection"));
Notes:
DbMigrationsConfiguration need to know about the connection string you can provide this info in the constructor or from outside.
In Your DbMigrationsConfiguration you can configure also:
MigrationsNamespace
MigrationsAssembly
MigrationsDirectory
TargetDatabase
If you leave everything default as in my example then you do not have to change anything!
Setting the Initializer for a Database has to happen BEFORE the context is ever created so...
public StoreContext():base("DefaultConnection")
{
Database.SetInitializer(new ContextInitializer());
}
is much to late. If you made it static, then it could work:
static StoreContext()
{
Database.SetInitializer(new ContextInitializer());
}
Your code is working if you delete your existing database and the EF will create and seeding the data
Or
You can use DbMigrationsConfiguration insted of CreateDatabaseIfNotExists and change your code as follow:
First you have to delete the existing database
ContextInitializer class
public class ContextInitializer : System.Data.Entity.Migrations.DbMigrationsConfiguration<StoreContext>
{
public ContextInitializer()
{
this.AutomaticMigrationDataLossAllowed = true;
this.AutomaticMigrationsEnabled = true;
}
protected override void Seed(StoreContext context)
{
IList<Brand> brands = new List<Brand>();
brands.Add(new Brand { Name = "Giordano", TotalSale = 1 });
brands.Add(new Brand { Name = "Nike", TotalSale = 3 });
foreach (Brand brand in brands)
{
context.Brands.AddOrUpdate(m => m.Name, brand);
}
base.Seed(context);
context.SaveChanges();
}
}
StoreContext
public class StoreContext : DbContext, IDisposable
{
public StoreContext() : base("DefaultConnection")
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<StoreContext, ContextInitializer>());
// Database.SetInitializer(new ContextInitializer());
}
public virtual DbSet<Category> Categories { get; set; }
public virtual DbSet<Brand> Brands { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
Then any change in your seed will automatically reflected to your database