I am writing a Data Access Layer using EntityFramework 6. What I want is that when I invoke the SaveChanges() method on the DbContext, it will save the entity together with the set of relevant entities associated via navigation properties. Following is the simple code I am trying to do.
public class Customer
{
public long ID { get; set; }
public string Name { get; set; }
public virtual IEnumberable<PhoneNumber> { get; set; }
}
public class PhoneNumber
{
public long ID { get; set; }
public string Number { get; set; }
}
public class SampleContext : DbContext
{
public virtual DbSet<Customer> Customers { get; set; }
public virtual DbSet<PhoneNumber> PhoneNumbers { get; set; }
}
using(var context = new SampleContext())
{
var customer = new Customer { ID = 1, Name = "John" };
customer.PhoneNumbers = new PhoneNumbers[]
{
new PhoneNumber { ID = 1, Number = "1.111.1111111" },
new PhoneNumber { ID = 2, Number = "1.111.1111112" }
}
context.Customers.Add(customer);
context.SaveChanges();
}
The above code saves the customer in the customers table but saves nothing in the PhoneNumbers table.
Strange but found a solution. The above code need a little modification to make it work. Followings are the modifications:
//In Customer class, changed following line:
public virtual IEnumberable<PhoneNumber> { get; set; }
//To:
public virtual ICollection<PhoneNumber> { get; set; }
//Then in using block initialized entities as follows:
using(var context = new SampleContext())
{
var customer = new Customer { ID = 1, Name = "John", PhoneNumbers = new List<PhoneNumber>() };
customer.PhoneNumbers.Add(new PhoneNumber { ID = 1, Number = "1.111.1111111" });
context.Customers.Add(customer);
context.SaveChanges();
}
Related
I'm new to EF (table first) and I don't know why these related entities are not saving at all to my database.
These are the related entities, UserProfile has a set of Carts
public partial class UserProfile
{
public UserProfile()
{
Cart = new HashSet<Cart>();
Naquestions = new HashSet<Naquestions>();
}
public int Id { get; set; }
public string BotUserId { get; set; }
public int? PrestashopId { get; set; }
public bool Validated { get; set; }
public int Permission { get; set; }
public DateTime CreationDate { get; set; }
public ICollection<Cart> Cart { get; set; }
public ICollection<Naquestions> Naquestions { get; set; }
}
Cart has a set of OrderLines
public partial class Cart
{
public Cart()
{
OrderLine = new HashSet<OrderLine>();
OrderRequest = new HashSet<OrderRequest>();
}
public int Id { get; set; }
public int UserId { get; set; }
public bool Active { get; set; }
public UserProfile User { get; set; }
public ICollection<OrderLine> OrderLine { get; set; }
public ICollection<OrderRequest> OrderRequest { get; set; }
}
And when I try to add them:
public async Task AddOrderLineToUser(string botId, OrderLine orderLine)
{
using (var context = ServiceProvider.CreateScope())
{
var db = context.ServiceProvider.GetRequiredService<GretaDBContext>();
var user = await UserController.GetUserByBotIdAsync(botId);
var latestCart = user.Cart.OrderByDescending(c => c.Id).FirstOrDefault();
if (latestCart != null && latestCart.Active)
{
latestCart.OrderLine.Add(orderLine);
}
else
{
var newCart = new Cart()
{
Active = true,
};
newCart.OrderLine.Add(orderLine);
user.Cart.Add(newCart);
}
await db.SaveChangesAsync();
}
}
Nothing is saving to the database once db.SaveChangesAsync() is called.
As #Caius Jard said in the comments it seems that user comes from another context. Try
if (latestCart != null && latestCart.Active)
{
orderLine.CartId = latestCart.Id;
db.OrderLines // I assume it is name of your orderlines DbSet
.Add(orderLine);
}
else
{
var newCart = new Cart()
{
Active = true,
UserId = user.Id,
};
newCart.OrderLine.Add(orderLine);
db.Carts // also assuming name of DbSet
.Add(newCart);
}
Also you can take a look at Attach method.
But I would say that in general you are doing something not good. Usually creating new scope is not needed, and db context should be injected in corresponding class via ctor. If you still need to create new scope it would make sense to resolve UserController also. Also is UserController an ASP controller?
I'm setting up a mini model and I'm getting this exception when executing the code from the docs website.
Here's my code:
public class SomeEntity
{
public int Id { get; set; }
[Column(TypeName = "jsonb")]
public Customer Customer { get; set; }
}
public class Customer // Mapped to a JSON column in the table
{
public string Name { get; set; }
public int Age { get; set; }
public Order[] Orders { get; set; }
}
public class Order // Part of the JSON column
{
public decimal Price { get; set; }
public string ShippingAddress { get; set; }
}
using (var dbContext = services.GetRequiredService<AppDbContext>())
{
await dbContext.Database.MigrateAsync();
dbContext.SomeEntities.Add(
new SomeEntity
{
Customer = new Customer
{
Name = "Roji",
Age = 35,
Orders = new[]
{
new Order { Price = 3, ShippingAddress = "Somewhere" },
new Order { Price = 3, ShippingAddress = "Nowhere" }
}
}
});
await dbContext.SaveChangesAsync();
}
When I call SaveChanges, I get the following exception:
Npgsql.PostgresException:
42P01: relation \"SomeEntities\" does not exist
Here's a repro project.
Since I believe I followed all the steps in the manual, I've opened an issue here too.
You're calling the MigrateAsync method, but your project doesn't have any actual migrations (those can be created with dotnet ef migrations add <name>). If you're just playing around, you likely want to call dbContext.Database.EnsureCreated instead, see this doc page.
I am trying to save 2 entity into two different table and these have related by one to one. but there is something weird for me. look below code please
public int CreateNotification(BusinessModel.Notification notification)
{
var db = new DataAccess.ApplicationDbContext();
var dbNotification = new DataAccess.Notification()
{
Name = notification.Name,
};
db.Notifications.Add(dbNotification);
//set NotificationSchedule
var dbNotificationSchedule = new DataAccess.NotificationSchedule()
{
Schedule = JsonConvert.SerializeObject(notification.NotificationSchedule)
};
db.NotificatoinSchedule.Add(dbNotificationSchedule);
***db.SaveChanges();***
this code works and the Foreign key of Notification is set to Notification schedule right. BUT the question is how the Id of notification is set to the Id of notificatioschedule? if I Add the related entity after the savechange there is an error, "update entity error...."
var db = new DataAccess.ApplicationDbContext();
var dbNotification = new DataAccess.Notification()
{
Name = notification.Name,
};
db.Notifications.Add(dbNotification);
***db.SaveChanges();***
//set NotificationSchedule
var dbNotificationSchedule = new DataAccess.NotificationSchedule()
{
Schedule = JsonConvert.SerializeObject(notification.NotificationSchedule)
};
db.NotificatoinSchedule.Add(dbNotificationSchedule);
}
public class Notification
{
public int Id { get; set; }
public string Name { get; set; }
public virtual NotificationSchedule NotificationSchedules { get; set; }
}
public class NotificationSchedule
{
[ForeignKey("Notification")]
public int Id { get; set; }
public string Schedule { get; set; }
public virtual Notification Notification { get; set; }
}
I have a simple entity framework 6 code first from existing database project for my web application. When I save data sometimes it saves properly with only 1 record saved. However sometimes it saves 2, 3 5 records it appears random.
For simplicity sake I have the following 2 classes. One is a parent "Person", and "PersonAddress" is the child. In my application there will always be 2 child records to 1 parent. No more no less (dont ask why). Here are my classes which are bare bones.
[Table("Person")]
public partial class Person
{
[Key]
public int PersonID { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
[Required]
public virtual ICollection<PersonAddress> PersonAddresses { get; set; }
}
[Table("PersonAddress")]
public partial class PersonAddress
{
[Key]
public int PersonAddressID { get; set; }
public int PersonID { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zipcode { get; set; }
}
Here is my DBContext class
public partial class MyDBContext : DbContext
{
public MyDBContext()
: base("name=MyDBContext")
{
//skips database initialization so it wont track changes and produce error, not needed for code first
Database.SetInitializer<MyDBContext>(null);
}
public virtual DbSet<Person> Persons { get; set; }
public virtual DbSet<PersonAddress> PersonAddresses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>().Property(x => x.PersonID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<PersonAddress>().Property(x => x.PersonAddressID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
//sample code
Person person = new Person();
person.FirstName = "TestFName";
person.LastName = "TestLName";
List<PersonAddress> addresses = new List<PersonAddress>();
PersonAddress address1 = new PersonAddress();
address1.Address1 = "line1"
//etc
//etc
addresses.Add(address1);
PersonAddress address2 = new PersonAddress();
address1.Address2 = "line1"
//etc
//etc
addresses.Add(address2);
//now add addresses to Person
person.PersonAddresses = addresses;
using (var context = new MyDBContext())
{
context.Persons.Add(person);
context.SaveChanges();
obj.PersonID = obj.PersonID;
}
What am I doing wrong, the data always gets saved and the child records are automatically added when I save the parent without issue. But as previously stated sometimes numerous sets of records are saved and I dont see any reason why. Thanks
Try this:
using (var context = new MyDBContext())
{
Person.PersonAdresses.add(addres1);
Person.PersonAdresses.add(addres2);
context.Entry(Person).State=EntityState.Added;
context.SaveChanges();
};
I am using code first Approach in entity framework, but I am unable to seed the default data into the table. Please help.
Models
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
public int Salary { get; set; }
public virtual Department Departments { get; set; }
}
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
public Department()
{
this.Employees = new List<Employee>();
}
}
Initializer
public class DepartmentInitializer : DropCreateDatabaseIfModelChanges<EmployeeDBContext>
{
protected override void Seed(EmployeeDBContext context)
{
IList<Department> lst = new List<Department>
{
new Department
{
Name = "Developer",
Location = "Bangalore"
},
new Department
{
Name = "Tester",
Location = "Bangalore"
},
new Department
{
Name = "IT Services",
Location = "Chennai"
}
};
foreach (var item in lst)
{
context.Departments.Add(item);
}
context.SaveChanges();
}
}
Main App
class Program
{
static void Main(string[] args)
{
using (var db = new EmployeeDBContext())
{
Database.SetInitializer<EmployeeDBContext>(new DepartmentInitializer());
}
}
}
For version 6 of Entity Framework, using 'migrations' is the preferred way to version the database, using the "Configuration.Seed" method as shown in this tutorial:
http://www.asp.net/web-api/overview/data/using-web-api-with-entity-framework/part-3
Have you tried running "Update-Database" from the Package Manager Console to get it to work?
I know I have had issues using the older seeding method with EF6. Migrations has also changed for Entity Framework Core 1 (formerly EF7), so make sure you are applying the correct technique to the correct version.
Try actually querying your db
On my machine, the seeder runs when I query it for the first time.
using (var db = new EmployeeDBContext())
{
Database.SetInitializer<EmployeeDBContext>(new DepartmentInitializer());
var depts = db.Departments.ToList();
}