Merge objects within Entity Framework? - vb.net

I'm attempting to create a merge function, in my application i have a users object that has PK/FK relationship to other objects relating to that user. (for my example say Contact is the object, and Orders have a 1:Many relationship to Contacts.
The function would pass in two EF objects, with one being the "kept" record and the other being "merged". Whereby all data in the kept should win should there be duplicate field entry. This is all easy enough, but i can't understand how to point all the link objects to the new record PK/FK issue.
How can this be achieved within EF(Design first)?
Example code from MS - Can i simply load the objects related to the merge and change their FK relationship? (differentcontact in example below). Such that say a Contact was created twice, and orders exist under both Contacts, we want to keep the first Contact, and remove the duplicate one. First we must re-assign all the orders to the correct contact (differentcontact), and then would be able to remove the duplicate contact value?
Using context As New POCOAdventureWorksEntities()
Dim orderId As Integer = 43659
Dim differentContactID As Integer = 5
Dim order As Order = context.Orders.Include("Contact").Where(Function(o) o.SalesOrderID = orderId).First()
Dim differentContact As Contact = context.Contacts.First(Function(c) c.ContactID = differentContactID)
order.ContactID = differentContact.ContactID '// Something like this?
context.SaveChanges()

Related

SSIS Inserting incrementing ID with starting range into multiple tables at a time

Is there are one or some reliable variants to solve easy task?
I've got a number of XML files which will be converting into 6 SQL tables (via SSIS).
Before the end of this process i need to add a new (in fact - common for all tables) column (or field) into each of them.
This column represents ID with assigning range and +1 incrementing step. Like (350000, 1)
Yes, i know how to solve it on SSMS SQL stage. But i need a solution at SSIS's pre-SQL converting lvl.
I'm sure there should be well-known pattern-solutions to deal with it.
I am going to take a stab at this. Just to be clear, I don't have a lot of information in your question to go on.
Most XML files that I have dealt with have a common element (let's call it a customer) with one to many attributes (this can be invoices, addresses, email, contacts, etc).
So your table structure will be somewhat star shaped around the customer.
So your XML will have a core customer information on a 1 to 1 basis that can be loaded into a single main table, and will have array information of invoices and an array of addresses etc. Those arrays would be their own tables referencing the customer as a key.
I think you are asking how to create that key.
Load the customer data first and return the identity column to be used as a foreign key when loading the other tables.
I find it easiest to do so in script component. I'm only going to explain how to get the key back. I personally would handle the whole process in C# (deserializing and all).
Add this to Using Block:
Using System.Data.OleDB;
Add this into your main or row processing depending on where the script task / component is:
string SQL = #"INSERT INTO Customer(CustName,field1, field2,...)
values(?,?,?,...); Select cast(scope_identity() as int);";
OleDBCommanad cmd = new OleDBCommand();
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = SQL;
cmd.Parameters.AddWithValue("#p1",[CustName]);
...
cmd.Connection.Open();
int CustomerKey = (int)cmd.ExecuteScalar(); //ExecuteScalar returns the value in first row / first column which in our case is scope_identity
cmd.Connection.Close();
Now you can use CustomerKey for all of the other tables.

Querying many to many relationship

Every article I need to solve my problem seems to be in C# and I need a solution in VB.NET.
I'm using EF 6.0 with Database First model. Let me use the classic Customer product scenario to demonstrate my situation. In my database I have three tables Customer, Product and CustomerProduct. See this example in this link as mine is exactly the same.
After I generate my model from the database, my entity model diagram shows that the CustomerProduct has disappeared as expected and the the model shows a many to many relationship between Customer and Product also as expected with navigational properties of Products in Customer and Customers in Product.
All I want to do is find the product related to a customer pull out some data from both tables namely CustName and ProductName.
The SQL I would use is:
SELECT c.CustName, p.ProductName FROM Customer c
INNER JOIN CustomerProduct cp on c.CustomerId = cp.CustomerId
INNER JOIN Product p on cp.ProductId = p.ProductId
WHERE c.CustomerId=101
I don't know how to use the Addresses navigational property to access the Address data in one query.
You include them and then access them via the property in the Entity class.
Dim query = model.User.Include("Address").Include("UserAddressLink").Where(Function(o) o.UserId = 101).FirstOrDefault
If Not query Is Nothing Then
Dim houseNumber = query.Address.HouseNo 'uses the navigation property
End If
Thanks to InteXX I managed to work it out. This is my whole solution
Using db as new CustProdEntities
Dim query = db.Customers.Include(Function(U) U.Products).ToList
txtCustomer.Text = query.First.CustName
txtProduct.Text query.First.Products.First.ProdName
End Using
The bit I was stuck on was having to filter twice to the Product data. I'm not sure if there's an easier way to do this but it works for now.

Duplicate a record and its references in web2py

In my web2py application I have a requirement to duplicate a record and all its references.
For example
one user has a product (sponserid is the user). and this product has so many features stored in other tables (reference to product id).
And my requirement is if an another user is copying this product, the a new record will generate in the product table with new productid and new sponserid. And all the reference table records will also duplicate with the new product id. Effectively a duplicate entry is creating in all the tables only change is product id and sponserid.
The product table fields will change. So I have to write a dynamic query.
If I can write a code like below
product = db(db.tbl_product.id==productid).select(db.tbl_product.ALL).first()
newproduct = db.tbl_product.insert(sponserid=newsponserid)
for field,value in product.iteritems():
if field!='sponserid':
db(db.tbl_product.id==newproduct).update(field=value)
But I cannot refer a field name like this in the update function.
Also I would like to know if there is any other better logic to achieve this requirement.
I would greatly appreciate any suggestions.
For the specific problem of using the .update() method when the field name is stored in a variable, you can do:
db(db.tbl_product.id==newproduct).update(**{field: value})
But an easier approach altogether would be something like this:
product = db(db.tbl_product.id==productid).select(db.tbl_product.ALL).first()
product.update(sponserid=newsponserid)
db.tbl_product.insert(**db.tbl_product._filter_fields(product))
The .update() method applied to the Row object updates only the Row object, not the original record in the db. The ._filter_fields() method of the table takes a record (Row, Storage, or plain dict) and returns a dict including only the fields that belong to the table (it also filters out the id field, which the db will auto-generate).

Table not getting updated while using LinQ

I am trying to update a table using LinQ. Though records are getting inserted, for some reason they are not getting updated.
what can be possible problem
Dim db as new empDataContext
Dim emptable as new employee
if update then
emptable=GetEmp(txtempID.Text)
emptable.Name="Test"
emptable.Age=11
emptable.City="NYC"
else
emptable.Name="Test"
emptable.Age=11
emptable.City="NYC"
emtable.deptID=10
db.employee.InsertOnSubmit(emptable)
end if
db.SubmitChanges()
Judging just from what I can see here, I'm guessing your GetEmp method is using a different data context to retreive the data than the one you're using to save it back to the DB.
When using LINQ to SQL, the context is what tracks the changes to the tables. If you're not careful and mix Contexts by accident, you can get strange behaviors like this.
You can test by chaging:
emptable=GetEmp(txtempID.Text)
to
// Returns the first matching employee with the id
emptable = (from e in db.Employees
where e.id == txtempid.Text).FirstOrDefault()
If you find that the context is the issue, just modify your GetEmp method to accept the context as a parameter rather than creating a new one itself.
What does GetEmp do? In particular, as presented it appears that it does not have a reference to the empDataContext named db. DataContexts are examples of identity maps and as such they track items that have been loaded from a persistence mechanism. If you are using a different DataContext in GetEmp then the DataContext db does not know about the instance of employee with SomeID equal to the value represented by txtempID.Text.
So either pass a reference to db into GetEmp or change your code to the following:
emptable = db.Single(Function(e as employee) e.SomeID=Int32.Parse(txtempID.Text))
then your update should work.
If I had to guess, I would say that the GetEmp() call is not using the same database context object. Therefore, Linq-To-SQL doesn't think any changes are occuring in the "db" database context.
Randy

In a datacontext are inserted values not available within the datacontext until after submitchanges?

I'm going through an XML file of articles and the journalist(s) that wrote them. As we are adding the articles into _Data our datacontext we may come across a journalist that needs adding so we do this:
newJourno = New journalist With {.name = strJournalist}
_Data.journalists.InsertOnSubmit(newJourno)
.articles_journalists.Add(New articles_journalist With {.id_journalist = newJourno.id, .id_article = .id})
However subsequently we may come across this same journalist again and nothing is returned when we do this:
Dim journo = _Data.journalists.Where(Function(s) s.name = strJournalist).SingleOrDefault
So it uses the code above again to insert the same journalist again.
Once all of our inserts are done we do a submitchanges. At this point it has a head fit:
INSERT statement conflicted with COLUMN FOREIGN KEY constraint 'FK_articles_journalists_journalists'. The conflict occurred in database 'blah', table 'journalists', column 'id'. The statement has been terminated.
From looking through the sql generated in sql profiler you can see that it is trying to add some journalists more than once, this will fail as the name must be distinct. The subsequent records that are trying to be inserted with these journalists are failing as the journalist wasn't updated.
Surely if I have a collection of journalists, add some to it and then look in my collection I should see all of them and not just the original ones. I can fudge it I guess by doing a submitchanges but that seems a bit silly.
Thanks in advance,
Dave.
If you want to add two child-parent rows to the database, you must assign the entity, instead of the Id column, the Id will be autogenerated and will be available only after the submit changes.
You have to do a articles_journalist object, and then assign the newJourno entity to this:
articles_journalist.journalist = newJourno;
CMS is right about needing to assign the object, not the id.
However this doesn't seem to get around the problem of the datacontext not realising that it has had new stuff added to it until you submitchanges. I can only presume this is by design and therefore I am now calling submitchanges as and when the code inserts objects that we later search for.
"the name must be distinct."
This is a serious design flaw. Person names are never unique.