Click here to Skip to main content
15,885,155 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have a Database first EF model with simple POCO entities.

I receive a new Product or collection of Products and want to do the following
1: Add the new Products to the products table ( seems simple enough to do this in EF from what I read).
2: Add the newly received Products to the Intermediary Table BatchProduct where Batch.ID = BatchProduct.BatchID
2A: If the BatchProduct.BatchID does not exist I want to create it and add my Products to the table.

Is the way my code is written in Example 1 the right way to do this ?

Or should I be setting the product ID's and Batch ID's by themselves ..? and leaving BatchProduct.Batch and BatchProduct.Product alone. As in the Example 2 at the bottom


Example 1:
C#
class Batch
{
  ID {get; set;} // auto-increment in database
  NUMBER {get; set;}
  NAME {get; set;}
}


class PRODUCT
{
  ID {get; set;} // auto-increment in database
  timestamp {get; set;}
  unit {get; set;}

}

class BatchProduct
{
  ID {get; set;}
  BATCHID {get; set;} //[FK in DB]
  PRODUCTID {get; set;} //[FK in DB]

}

using (var db = myDBContext)
{
	BATCH batch = db.BATCHes.SingleOrDefault(b => b.BatchNumber == handshake.Batch);
				
    foreach (PRODUCT product in products) 
    {
	BATCH_PRODUCT batchproduct = new BATCH_PRODUCT();
        db.PRODUCTs.Add(product);
	batchproduct.BATCH = batch;
	batchproduct.PRODUCT = product;
	db.BATCH_PRODUCT.Add(batchproduct);				 
    }
	db.SaveChanges();

}

Example 2:
C#
foreach (PRODUCT product in products) 
{
    BATCH_PRODUCT batchproduct = new BATCH_PRODUCT();
    batchproduct.PRODUCTID = db.PRODUCTs.Add(product).ID;
    batchproduct.BATCHID = batch.ID;
    db.BATCH_PRODUCT.Add(batchproduct);
}
				
db.SaveChanges(); 
Posted
Updated 29-Jul-15 9:10am
v3

1 solution

When possible, try to link objects in EF to each other by setting Navigation properties. After all, EF is an Object Relationship Mapper :)

In order to check if a 'related' entity exists already in the database context (to maintain relationship integrity), you are going to have to do some sort of lookup. Use the objects!

This approach works fine for a few hundred objects at a time - but remember EF isn't designed for high volume updates/inserts. If you need maximum throughput, drop back to using underlying ADO.Net classes such as SqlDataReaders or SQLBulkCopy etc.

Below demonstrates how I would approach the situation.

C#
using (var db = myDbContext)
            {
                var batch = db.Batches.SingleOrDefault(b => b.BatchNumber == handShake.Batch);

                if (batch == null)
                {
                    batch = new Batch()
                    {
                        // set new Batch properties
                    };
                }

                foreach (Product product in products)
                {
                    BatchProduct batchproduct = new BatchProduct()
                    {
                        Batch = batch
                    };

                    var existingProduct = db.Products.SingleOrDefault(p => p.ID == product.ID);
                    if (existingProduct != null)
                    {
                        batchproduct.Product = existingProduct;
                    }
                    else
                    {
                        batchproduct.Product = new Product()
                        {
                            // set new Product properties
                        };
                    }
                    db.BatchProducts.Add(batchproduct);
                }
                db.SaveChanges();
            }
 
Share this answer
 
Comments
stixoffire 30-Jul-15 2:11am    
Relationship handling was actually my main driver for using EF. I guess I am at a loss regarding Navigation properties - I know I have a template that generated POCOs for me with the relations (I assumed form my reading that these were navigation properties).
In your example code [given my Product is a DTO] , does the db.Products table get magically updated / inserted (in my case they will never already exist in the db) ..because you set the batchproduct.Product = Product?
And is this a typo Batch = batch
Mr Ellipse 30-Jul-15 3:00am    
You got it!

EF tracks the entire 'object graph' of changes. Because you are adding a new BatchProduct to the Data Context, when SaveChanges() is called, it will evaluate the BatchProduct.Product and BatchProduct.Batch navigation properties, and perform an insert/update on those as well.

The EF Data Context does all the work via proxy wrappers, which tracks changes made to it in memory as soon as an object is added to, or retrieved from the Data Context.

Batch = batch is not a typo. Its just a concise way of setting the .Batch property of new BatchProduct(). ;)

Cheers,
stixoffire 30-Jul-15 9:48am    
As you can tell I am learning Entity Framework - and it is really a complex piece of work. I am also learning WCF and it too is pretty involved. The one thing I noticed about EF is it does not like the DataTable and I really love those things - bc they are so easy to work with and have a gazillion things built in. I will put your answer to use. Thank you for your time in answering I really appreciate it!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900