And Entry and Edit Navigation Property using Entity Framework 6 - entity-framework

This is probably a duplicated question, but I cannot find the exact answer or documentation.
I have a two tables with one to many relationship. Each item has a category, and CategoryID is the foreign key.
public partial class Item
{
public long ItemID { get; set; }
public string ItemName { get; set; }
public int CategoryID { get; set; }
public virtual Category Category { get; set; }
}
public partial class Category
{
public int CategoryID { get; set; }
public string Name { get; set; }
public virtual ICollection<Item> Items { get; set; }
}
When I try to add an item, it looks like I always need to make sure category is null. If I forgot to set it to null, EntityFrame will create a new category even the old catagory exist.
For example:
My db is:
Item
Item #1: id: 1, name TV categoryId : 1
Item #2: id: 2, name DVD categoryId : 1
Item #3: id: 3, name Cat categoryId: 2
Categories
Category #1: id: 1 name: electronics
Category #2: id: 2 name: pets.
If my code is
using (var dbContext = new DBContext())
{
Category category = dbContext.Categories.FirstOrDefault(c=>c.CategoryID = 2);
Item item = new Item()
{
Name = "dog",
CategoryId = 2,
Category = category,
};
dbContext.Items.Add(item);
dbContext.SaveChanges();
}
This code will cause another new category with duplicated name "pet" created. I guess it makes sense. But I want to know is there a guideline of how/when to set to the collection object(Category object) or when should I set it to null? What's SOP when I need to update an existing item's category? If I simply use the following code:
using (var dbContext = new DBContext())
{
Item item = dbContext.Items.FirstOrDefault(i => i.ItemID == 1);
item.CategoryId = 2;
dbContext.SaveChanges();
}
This code will not work. should I manually set the item.Category property to null? Or there is a better formation in EF6?

change Item Class to this
public partial class Item
{
public long ItemID { get; set; }
public string ItemName { get; set; }
public int CategoryID { get; set; }
[ForeignKey="CategoryID"]
public virtual Category Category { get; set; }
}
then you are using [ForeignKey] annotation in your class that connect id to data, and when you are creating new data just put category Id not data.
Item item = new Item()
{
Name = "dog",
CategoryID = 2,
};

Related

How to Allow NULL Foreign Keys with SQLite-net-extensions

I'm trying to add a nullable foreign key mapping but it doesn't work. I know the database allows nulls, since I can insert a new record with a null foreign key when using Datagrip. I only get the error when trying to insert from a Xamarin.Forms project building for Android(SQLite.SQLiteException: 'Constraint')
My classes look like:
public class Item
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
...
[ForeignKey(typeof(Location))]
public int LocationId { get; set; }
[ManyToOne]
public Location Location { get; set; }
}
public class Location
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
...
[OneToMany]
public List<Item> Items { get; set; }
}
And my inserts like
//This will no work
var todoItem = new Item()
{
Name = "Test item " + DateTime.Now.TimeOfDay.ToString(),
Description = "Desc",
Location = null // I tried with and without this line
};
await App.Database.SaveItemAsync(todoItem);
//This will work
var todoItem = new Item()
{
Name = "Test item " + DateTime.Now.TimeOfDay.ToString(),
Description = "Desc",
LocationId = 1
};
await App.Database.SaveItemAsync(todoItem);
Any idea what I'm doing wrong? Thanks
Apparently the library needs that the id field to be nullable, so instead of
[ForeignKey(typeof(Location))]
public int LocationId { get; set; }
I should use
[ForeignKey(typeof(Location))]
public int? LocationId { get; set; }
PS: In my case just building the project didn't took the changes on to effect, I only could see the result after Rebuild the project..(I'm new with Xamarin, probably I have something misconfigured...I hope)

EF Core - Cannot add object with composite key

Alright, I'm trying to make a Wishlist containing user favorite items, however when I try to add them to the user, EF doesn't even try to INSERT, no action.
Here is my FavoriteProduct model
public class FavoriteProduct : BaseDeletableModel<int>
{
public string FashionNovaUserId { get; set; }
public FashionNovaUser FashionNovaUser { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
}
builder.Entity<FavoriteProduct>().HasKey(x => new { x.ProductId, x.FashionNovaUserId });
Here's my user model
public class FashionNovaUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<FavoriteProduct> FavoriteProducts { get; set; }
Then through my service layer I'm trying to add the favoriteProduct to user's list
var favoriteProduct = new FavoriteProduct
{
ProductId = id,
FashionNovaUserId = user.Id
};
user.FavoriteProducts.Add(favoriteProduct);
this.db.SaveChanges();
When I do that, there database table is not updated, nor it has any new entries.
Since FashionNovaUser and Product are many-to-many relationships, if you would like to add records of FavoriteProduct in join table, just use
var favoriteProduct = new FavoriteProduct
{
ProductId = id,
FashionNovaUserId = user.Id
};
this.db.Add(favoriteProduct);//or this.db.FavoriteProduct.Add(favoriteProduct)
this.db.SaveChanges();

Adding Entity with complex type property

I am trying to add the student entity in my database, which looks like this:
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public Course Course { get; set; }
}
The Course class looks like this:
public class Course
{
public int ID { get; set; }
public string Name { get; set; }
}
Data in the Course table:
| ID | Course |
------------------------
| 1 | Math |
-----------------------
| 2 | Physics |
-----------------------
When I define student as shown below:
var student = new Student
{
Name = "ABC",
Course = new Course { ID = 1, Name = "Math"}
};
and try to add it so
context.Students.add(student);
await context.SaveChangesAsync()
the entity wasn't added. I added this line of code
context.Entry(student).State = EntityState.Added;
but nothing changed.
First of all you have to set Foreign Key CourseId to your Student entity.
A) Student Entity
public class Student
{
public int StudentID { get; set; }
public string Name { get; set; }
public int CourseID { get; set; } //This is foreign key
public virtual Course Course { get; set; }
}
B) Course Entity: ICollection property gives you all students with particular CourseID.
public class Course
{
public int CourseID { get; set; }
public string Name { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
1) If you add new student record with new course then
Course course = new Course
{
Name = "Math"
};
Course insertedCourse = context.Courses.Add(course);
Student student = new Student
{
CourseID = insertedCourse.CourseID,
Name = "ABC"
};
context.Students.Add(student);
await context.SaveChangesAsync();
2) If you have to reference your existing course from database then you have to get course from database and assign courseId to student entity.
Course existingCourse = GetCourseByIdFromDatabase();
Student student = new Student
{
CourseID = existingCourse.CourseID, //This ID comes from Db
Name = "ABC"
};
context.Students.Add(student);
await context.SaveChangesAsync();
Try once may it help you.
Edited:
As I understood with your last comment,
If you want to get student with its corresponding course then
Your get student method look like
public Student GetStudent(int Id)
{
Student student = context.Students.Find(Id);
return new Student
{
StudentID = student.StudentID,
Name = student.Name,
Course = student.Course
};
}
Ad you can access student's course like
Student student = GetStudent(1);
string CourseName = student.Course.Name;
you can use your async and await with above code depending your need.

Merge Key constraint with Entityframework

I am a .NEt student trying to build a simple pizza webbshop. I am using Entityframework to build the database. The errormessage I get is this:
The MERGE statement conflicted with the FOREIGN KEY constraint "FK_Products_Categories_CategoryID". The conflict occurred in database "TomasosPizzeria", table "dbo.Categories", column 'CategoryID'.
The statement has been terminated.
I have googled and tried to solve this pne alone by renaming the properties back and forth. Here are my classes:
public class Product
{
public int ID { get; set; }
public string ProductName { get; set; }
public int ProductPrice { get; set; }
public string Ingridients { get; set; }
//--
public List<OrderDetail> OrderDetails { get; set; }
[ForeignKey("Categories")]
public int CategoryID { get; set; }
public virtual Category Categories { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
List<Product> Products { get; set; }
}
I am using a DbInitializer to set som test values. I have had problems giving the product object a category with the corresponding value.
var categories = new Category[]
{
new Category{CategoryName="Pizza"},
new Category{CategoryName="Pasta"},
new Category{CategoryName="Sallad"},
};
var products = new Product[]
{
new Product{ProductName="Äcklig Calzone", Ingridients="Gamla tomater, möglig ost, trötta oliver, Unken skinka", ProductPrice=150},
new Product{ProductName="Italiensk skit", Ingridients="Proscutti, halvfärdig mozzarella, trötta oliver, skämd vattnig proscutti", ProductPrice=250},
new Product{ProductName="La bussola", Ingridients="Äckliga tomater, giftiga räkor, levande musslor, rutten skinka",CategoryID = 2,<--Here-- ProductPrice = 105 }
};
foreach (Product s in products)
{
context.Products.Add(s);
}
context.SaveChanges();
I am thankful for all the help I get. Please tell me if you wish to see any more of my code.
Solved it by giving CategoryID to the two other products.

Entity Framework - Adding parent is also trying to add child when I don't want it to

I have two objects (WishListItem and Product) in a one-to-many relationship. WishListItem has to have a product. Each Product can be in 0 - n WishListItems.
public class WishListItem
{
public int Id { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
}
public class Product
{
public int Id { get; set; }
// ... other properties
}
The Product has no knowledge of WishListItems. All of the Products exist. I just want to add a new WishListItem. My WishListItem model for the relationship is this:
HasRequired(p => p.Product).WithMany().HasForeignKey(p => p.ProductId);
When I try to add a new item like this:
WishListItem item = new WishListItem();
// ... sets properties
WishListItems.Add(item); // WishListItems is of type DbSet<WishListItem>
SaveChanges();
This code seems to try to also add a Product. I don't want to add a new Product (or even update it). The Product property is set to null. How do I tell Entity Framework that I only want to add the WishListItem? Do I need to Ignore the Product property (by doing Ignore(p => p.Product); in my WishListItem model) and load the Product separately whenever I load my WishListItem objects?
I have solved my issue. The problem came from another property on the Product object.
private bool _isFreeShippingInitialValue;
public bool IsFreeShipping
{
get
{
return _isFreeShippingInitialValue ||
computedValueFromAnotherChildObject;
}
set
{
_isFreeShippingInitialValue = value;
}
}
We noticed that when you first get the Product object, the IsFreeShipping.get is called (not sure why) before any child objects are loaded. For example, if _isFreeShippingInitialValue is false and computedValueFromAnotherChildObject is true, IsFreeShipping first returns false (because computedValueFromAnotherChildObject is first false since no child objects have been loaded), then true the next time you try to get IsFreeShipping. This makes EF think the value has changed.
The first item we added to WishListItems worked fine. It was the second item that broke. We believe SaveChanges() (or something prior to it) loaded the Product for the first WishListItem. The SaveChanges() was breaking on the Product of the first WishListItem when we were adding the second item.
So, in short, be careful when computing values in a Property.get using child objects because it can bite you in the butt.
This works for me without adding any new Addresses records. In this model, Person has an optional home address, but address doesn't have any knowledge of the person.
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual Address HomeAddress { get; set; }
public int HomeAddress_id { get; set; }
}
public class Address
{
public int Id { get; set; }
public string PhoneNumber { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
}
In the DbContext override, I have the below code
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasRequired(t => t.HomeAddress).WithMany()
.HasForeignKey(t => t.HomeAddress_id);
}
I can write a unit test like this.
var addressId = 0;
using (var db = new DataContext())
{
var address = new Address { City = "test", Country = "test", PhoneNumber = "test", State = "test", Street = "test" };
db.Addresses.Add(address);
db.SaveChanges();
addressId = address.Id;
}
using (var db = new DataContext())
{
var person = new Person { Email = "test#test.com", FirstName = "Testy", LastName = "Tester", HomeAddress_id = addressId };
db.Persons.Add(person);
db.SaveChanges();
}