Entity Framework Creates New / Duplicate Entries for Associated Objects - c#

I am trying to use Code First to create an SQL CE 4 database. When running the sample code below, Entity Framework is inserting new records for product each time, even though the data is exactly the same. What do I need to do to make Entity Framework not create duplicate associated products? The values in the ForeignID1 and the Product object are values that already exist in the database, but Entity Framework is wiping the ID I give it and adding a new ID.
namespace MyApp.Model
{
public class MyThing
{
public int ID { get; set; }
[ForeignKey("Product")]
public int ForeignID1{ get; set; }
public virtual Product Product { get; set; }
}
}
// Data.DataManager.cs
public class DataManager : DbContext
{
public DbSet<Model.MyThing> Things{ get; set; }
public DbSet<Model.Product> Products { get; set; }
}
These are the values it has entered. There should only be one value in the table that is referenced by multiple MyThings's

In order to avoid the duplication you must attach the related entity to the context:
context.Products.Attach(myThing.Product);
context.Things.Add(myThing);
Or...
myThing.Product = null;
context.Things.Add(myThing);
...will work as well if you have set myThing.ForeignID1 to an existing Product ID.

Related

Entity Framework doesn't generate all tables from database

This is my diagram in my database:
but when I use Entity Framework it was like that:
It hasn't table name ListSuiteQuestion but It has 2 new property in class Question and Suite:
enter image description here
Table ListSuiteQuestion is automatically created by sql because in sql we don't have something called many to many relationship (m:n) and sql creates another table to implement m:n relationship with keys containing the primary key of two relationship tables is also the name of the combination of the names of the two relation tables.
Within your entity framework by accessing each table through another table you have access to that table so there is no need to define it by entity framework. However, if you intend to customize or add a field to a third table you can manually build it into the code and then display it entity framework, though you don't need to.
if you want create it manually in code do like this :
public class Suite
{
//another property
public int IdSuite { get; set; }
public virtual ICollection<SuitQuestions> Questions { get; set; }
}
public class Question
{
//another property
public int IdQuestion { get; set; }
public virtual ICollection<SuitQuestions> Suites { get; set; }
}
public class SuiteQuestions
{
public Suite Suite { get; set; }
public int IdSuite { get; set; }
public Question Question { get; set; }
public int IdQuestion { get; set; }
//add custome property if you need
}
and config it.
It's correct. A question has a list of suites and a suite has a list of questions.
If you do:
var suite = context.Suites.Find(5);
var question = context.Questions.Find(30);
suite.Questions.Add(question);
// And update this suite object here;
You will see a new record in ListSuiteQuestion Tables with IdSuite = 5 and IdQuestion = 30. The class ListSuiteQuestion doesn't need to be created.
However, if you really want to create the class you have to add Id to the Table ListSuiteQuestion as primary key.

Duplicate entities when setting state within a collection in Entity Framework

I have a solution which uses Entity Framework to insert invoices to a database table. These invoices reference an order, which in turn also references an order item collection.
In this instance I am trying to add an order to the database, however the code is inside a new DbContext and so I need to attach the order and order items to the context, as these already exist in the database and shouldn't be re-added.
I've cut down the model properties for the sake of demonstration:
public class Invoice {
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int InvoiceId { get; set; }
public string OrderNumber { get; set; }
...
public virtual List<InvoiceLineItem> LineItems { get; set; }
}
public class InvoiceLineItem {
[Key]
public int Id { get; set; }
...
public ShopifyOrderItem { get; set; }
}
public class ShopifyOrder {
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public long Id { get; set; }
public int OrderNumber { get; set; }
...
public OrderInvoiceStatus InvoiceStatus { get; set; }
public virtual List<ShopifyOrderItem> OrderItems { get; set; }
}
public class ShopifyOrderItem {
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public long Id { get; set; }
...
[Required]
public virtual ShopifyOrder ShopifyOrder { get; set; }
}
In the invoice engine, I'm running the following code for each invoice to add it to the database:
ShopifyOrder order = await db.ShopifyOrders.SingleOrDefaultAsync(x => x.OrderNumber.ToString() == inv.OrderNumber);
if (order != null) {
// Attach marketplace entity to the invoice to avoid duplicate primary key exceptions
db.Marketplaces.Attach(inv.Marketplace);
db.Invoices.Add(inv);
order.InvoiceStatus = OrderInvoiceStatus.InProgress;
}
I've tried a number of methods to try and attach the states, however they all throw errors.
inv.LineItems.ForEach(li => {
db.Entry(li).State = EntityState.Unchanged;
db.Entry(li.ShopifyOrderItem).State = EntityState.Unchanged;
db.Entry(li.ShopifyOrderItem.ShopifyOrder).State = EntityState.Modified;
});
The above code returns the following error on save:
EntityFramework: Saving or accepting changes failed because more than one entity of type 'TorroModels.ShopifyOrder' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model.
What is the best way to attach the LineItems/ShopifyOrderItems without trying to attach the ShopifyOrder connected property multiple times?
Sorry to say but it seems that you need to follow the best practice first when constructing a relationship. You may follow this link :
http://www.entityframeworktutorial.net/entity-relationships.aspx
In short :
Avoid using only "Id" in every entity, or you can use attributes to map between the physical name and the property name
It seems that you have circular references here, so maybe you could simplify it first
Next, you can read this link :
http://www.entityframeworktutorial.net/EntityFramework5/attach-disconnected-entity-graph.aspx
if you need to know more about what's the best practice of attaching entities, but in my opinion, just don't abuse this feature, because using normal CRUD should be sufficient most of the time.
I'm sorry I cannot help you more than this, because of lack of information I may need, and with my reputation I still cannot comment directly in your post to ask for it.

How do I insert records using Entity Framework with nested list of objects?

I am making a call to an endpoint and receiving back a list of objects, let's call them Receipts. Each Receipt can contain a list of a variable amount of Vehicles. I want to be saving records with a composite key comprised of the Receipt ID and Vehicle ID.
I set up the model as:
public class Receipt
{
[Key]
[Column(Order=1)]
public string id { get; set; }
public int count { get; set; }
public List<Vehicles> vehicles { get; set; }
public class Vehicles
{
[Key]
[Column(Order=2)]
public string id { get; set; }
}
}
Next, I added Receipt to the DbContext
public class DbContext : System.Data.Entity.DbContext
{
public DbSet<Receipt> Receipt { get; set; }
}
Finally, I insert/update and save changes
try
{
using (var dbContext = new DbContext())
{
dbContext.Receipt.AddOrUpdate(receipt);
dbContext.Receipt.SaveChanges();
}
}
My program is not catching any exceptions but the table/database is completely empty. Am I structuring the object right to inform Entity Framework of how I want these rows saved? One option would be to loop through each Vehicle in a Receipt and create a new Entity that stores the Receipt ID and Vehicle ID along with other fields needed
As your database is completely empty and your code does not show any sign of it either, I'm afraid the solution to your question is to actually call
dbContext.SaveChanges();
To make it really work as expected, as mentioned in a comment, your property should be a
public virtual ICollection<Vehicles> Vehicles { get; set; }
and although I don't know if it's a problem, I would recommend putting your Vehicle class as a normal non-nested class.

Use linq to load Navigation Property without Declaring Foreign Key

The project I'm in is using Entity Framework 6 with code first and has central database and a local database. The central DB is the same as the Local DB with the exception that all relationships (Foreign keys, primary keys etc) have been removed.
So lets imagine that I have the following classes:
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public int ProductTypeId { get; set; }
public ProductType ProductType { get; set; }
}
public class ProductType
{
public int ProductTypeId { get; set; }
public string Name { get; set; }
public List<Product> Products { get; set; }
}
if the database has a foreign key in the Product table I can do
IEnumerable<Product> products = ctx.Produts.Include(x => x.ProductType);
If the datbase doesnt have the foreign key, will EF still load the ProductType object using the code above?
Without foreign key, EF will not load the ProductType object.
You will need to do a new query. Something like this:
IEnumerable<Product> products = ctx.Produts;
foreach (var product in products )
{
ProductType type = (from t in ctx.ProductType where t.ProductTypeId == product.ProductTypeId select t).Single();
product.ProductType = type;
}
I was curious about this so I mocked up a quick test, which I ran both with and then without the foreign key in the database. The answer seems to be yes, it will work, provided you have configured your keys still in Entity Framework. Note however, of course, that the database will obviously not enforce reference constraints without the keys, although it looks like EF will.

SQLite-Net Extensions not inserting in cascade in some cases

I am using SQLite-Net PCL together with SQLite-Net extensions for the development of an application using Xamarin.
In my model I have an entity (let's call it A) which is connected to other four entities through one-to-many relationships (that are represented as lists in the model). In order to populate the tables recursively when inserting an object of A in the database I have defined the relations to use Cascade on both read, insert and delete.
In order to test if I did everything correctly I created an object of type A and populated the including lists, and finally I have inserted it into the database. The strange thing is that, for 2 of the 4 including lists the insertion went well, and all the connected objects are inserted. For other 2, instead, only the first object of the list is inserted in the database. To be clear, I am checking the database content directly with a db browser.
The following is an example of one of the objects for which only the first element of the list is inserted.
public class Username : Entity
{
public string Name
{
get;
set;
}
[ForeignKey(typeof(A))]
public int AId
{
get;
set;
}
public Username(string username)
{
Name = username;
}
}
This is instead one of the objects for which the insertion is correct.
public class AnAddress: Entity
{
public string Address
{
get;
set;
}
public AddressType Type
{
get;
set;
}
[ForeignKey(typeof(A))]
public int AId
{
get;
set;
}
}
To be clear, the base object Entity contains the definition of the primary key:
public abstract class Entity
{
[PrimaryKey, AutoIncrement]
public int Id
{
get;
set;
}
public Entity()
{
Id = -1;
}
}
And this is the way the relationships are defined:
public class A : Entity
{
public string Name
{
get;
set;
}
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<AnAddress> Addresses
{
get;
set;
}
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<Username> Usernames
{
get;
set;
}
}
I then create an A object by initialising it with two lists (List and List) in the same identical way.
I finally insert the object in the database with
c.InsertWithChildren(entity, recursive: true));
Where entity is of type A and c is the connection object.
Do you have any clue about the motivation of this strange behaviour?

Categories

Resources