Situation: I have 3 tables:
movies (pk:movietitle, movielength....etc)
rentals (pk:personid, fk:movietitle,...etc)
rentingpeople (pk+fk:personid, name, phone...etc)
On my form there is a listbox bindingsourced with the movie titles, next to the listbox there are textboxes bindingsourced from db.movies
When someone click on the rentthismovie button I would like to delete the current rental data about that movie from table rentals and rentingpeople.
I wrote the first part and get an error because of foreign keys problem (I mentioned primary key as pk and foreign key as fk in the tables above)
var search = (from g in db.Rentals
where g.Movietitle == (string)listBox1.SelectedValue select g).First();
db.Rentals.DeleteObject(search);
db.SaveChanges();
I get an error:
The DELETE statement conflicted with the REFERENCE constraint \"FK_Rentingpeople_Rentals\". The conflict occurred in database \"C:\USERS\PC\DOCUMENTS\VISUAL STUDIO 2010\PROJECTS\FILMEK\FILMEK\BIN\DEBUG\DATABASE1.MDF\", table \"dbo.Rentingpeople\", column 'personid'.\r\nThe statement has been terminated.
Because of the primary-foreign key connection I must delete the data from rentingpeople table too as I read from this error but I can't really find a working solution.
The problem is in the db design
movies(pk:movietitle,movielength....etc)
rentals(pk:personid,fk:movietitle,...etc)
rentingpeople(pk+fk:personid,name,phone...etc)
If I got this right, movies contains the list of movies, rentingpeople is the list of people who are renting or have rented, and rentals tracks rentals. If so, rentingpeople.personid should be a pk, and rentals.personid should be an fk to the other, like this:
movies(pk:movietitle,movielength....etc)
rentals(fk:personid,fk:movietitle,...etc)
rentingpeople(pk:personid,name,phone...etc)
if you want to improve search on rentals (assuming any one person can exercise multiple rentals at the same time) you can introduce a non-unique index on personid, or a composite unique index to personid and movietitle on table rentals
You need to delete all the PK and not null references to the object you are deleting before you delete object itself.
You can change non nullable columns to nullable ones if logic allows.
var rentalsToBeDeleted = db.Rentals.Where(o =>o.movieid == movieid).ToList();
for (int i = rentalsToBeDeleted.count; i < 0; i--)
{
db.Rentals.DeleteObject(rentalsToBeDeleted.elementAt(i));
}
after all the referenced deleted.
db.SaveChanges();
writing without VS so mistakes are likely but you should get the idea.
Related
I have a database like lets say a class Student and a class Course. These two have many to many relationship through a join table, holding ids of these two tables which is hidden in EF the way it supposed to.
First if I add two courses to a student. Like
John.classes.Add(math); John.classes.Add(physics) where 'John', math and physics are objects of their respective classes. When i save changes, everything happens the ways it should happen. An entry in students table, two entries in courses table and two entries in StudentCourses join table. All good.
But then, when i add another student say 'Bob' with same two classes. Bob.classes.Add(math); Bob.classes.Add(physics);It should add a row in students table adding Bob and two rows in StudentCourses join table. This doesn't happen. A row is added to students table but no rows are being added to StudentCourses table giving error of duplicate entry in courses table. Entity Framework is not adding courses because math and physics already exist in courses table but it should add two entries in StudentCourses join table.
A work around this is by adding an id column in join table and use this table as normal table and manually add entries in StudentCourses table. But i dont want to do this, I want to know the actual solution.
Thanks
i solved it by
team ct = context.teams.Find(club.id);
if (ct == null)
{ comp.teams.Add(club); }
else
{ ct.competitions.Add(comp); }
context.SaveChanges();
where comp is competition object.
I am sure this is not the actual solution but just a way around. This can't be...
I have an audit trailing system in my project from http://doddleaudit.codeplex.com/.
As you can see on this image it records the EntityTable - which is the table name, and the EntityTableKey - which is the primary key
I would like to associate the audit records with the tables it had recorder, then query the result in linq to sql. But the problem is if the audit table has record for orders and record for products it will never know just by the primary key, where does the record belong, thus i need to use the table name as part of the key.
So the question is: Is it possible to create a relation that will have a composite primary key that contains the table name in it?
AuditRecord to Orders
AuditRecord to Products
You could do it, but I would recommend a bit different approach.
Don't use char/varchars/nvarchar in your PK/FK, it bloats the index. I would rather create another table that will hold TableId/TableName pairs of all your tables (you can use sys.tables.object_id for your id if you wish) and have a FK in AuditRecords to it. Then establish composite key between AuditRecords and AuditRecordFields (Id, TableId).
Another thing:
EntityTable and AssociationTable should be of sysname type
AuditDate can be of type Date (available from SQL Server 2008)
EDIT:
If you like to access audit records from each object, you can create a base class for your audited objects and implement following method (beware, it's untested):
public IQueryable<AuditRecord> AuditRecords
{
get
{
MyContext ctx = new MyContext();
var ars = from ar in ctx.AuditRecords
where ar.EntityTable.Equals(this.GetType().Name)
select ar;
return ars;
}
}
let's say I have to tables: "Customer" (parent) & "Address" (child). They are associated, so there is a 1:1 relationship between them.
Table<Customer> table = db.GetTable<Customer>();
var query = from c in table
select p;
Is there a possibility to query against tables that are associated with "Customer" using the selected Customer-tables or do I have to get all Address-tables in a separate query?
Besides if I use a DELETE-command on a Customer-table, does this DELETE all the associated tables too?
Thanks in advance,
Prot
If they are related with a foreign key, then it should be very straight forward. The Address should just be a property of Customer.
var query = from c in table
select c.Address;
Or you could do it with a join if a foreign key doesn't exist.
var query = from c in table
join address in [AddressTable] on c.AddressId equals address.Id
select address;
The type of DELETE you're referring to is called a cascade delete. You'll need to enable it on your foreign key (you'll need an FK for this to work). See this thread.
you don't have to get the address out separately, you should be able to just lazy load the address if you have set up an association in the dbml (i.e the arrow linking the tables).
Instellisense should show the property;
var query = from c in table
select p.Address;
for the delete set up an on delete cascade on your foreign key on the tables themselves and this will delete the associated address every time you delete a customer record.
I have a table that hold records of part numbers for a specific project like so:
create table ProjectParts
(
PartNumber varchar(20) not null,
ProjectID int not null,
Description varchar(max) not null,
primary key nonclustered (PartNumber, ProjectID)
);
I have a view that will collect inventory information from multiple places, but for now I basically have a skeleton:
create view ProjectQuantities as
select distinct
pp.PartNumber,
pp.ProjectID,
0 as QtyOnHand,
0 as QtyOnOrder,
0 as QtyCommitted
from
ProjectParts pp;
So far, so good. I go into EF designer in Visual Studio (I already had an object model using the ProjectParts table) and update the model from the database. I select the ProjectQuantities view, click ok.
EF tries to divine the key on the table as a combination of all columns, but I fix that so the key for the object is the PartNumber and ProjectID columns. I check to make sure this validates, and it does.
Next, I add an 1:1 association between the ProjectPart object and the ProjectQuantity object in the EF UI and click OK. Now, when I try validating, I get the message Error 11008: Association 'ProjectQuantityProjectPart' is not mapped. Seriously? It can't figure this out? Alright, I select the link, go to the Mapping Details, and add the ProjectParts table. It adds both tables and meshes up the key relationships. My job is done. I run the validation.
No luck for me. Now I get the error Error 3021: Problem in mapping fragments starting at line (line number): Each of the following columnes in table ProjectParts is mapped to multiple conceptual side properties. The the message lists the ProjectID and the PartNumber columns and their references to the association I just created.
Well duh! Of course there are multiple references! it's a 1:1 compound key, it has to have multiple references!
This is stopping me from getting stuff done. Does anyone know a simple way to fix this so I can collect Quantity information when I'm collecting data about a project and its parts?
Thanks!
You may find this article useful http://blogs.u2u.be/diederik/post/2011/01/31/Building-an-Entity-Framework-40-model-on-views-practical-tips.aspx
I have a typed DataSet with two TableAdapters (1 to many relationship) that was created using visual studio 2010's Configuration Wizard. The child table's FK uses cascading. It is a small part of an application that keeps track of groups (parent table) and group members (child table).
I can insert new tuples into the Groups table fine but the problem occurs when I am trying to insert new tuples into the Members table when the FK is based on a group that I just inserted into the group table. You can see the problem in the following code snippet
GroupsDataSet.GroupsRow addedGroup = this.groupsDataSet.Groups.AddGroupsRow(groupName, this.type);
this.groupsDataSet.Members.AddMembersRow(memberName, addedGroup);
this.groupsTableAdapter.Update(this.GroupsDataSet.Groups);
this.membersTableAdapter.Update(this.GroupsDataSet.Members);
When I insert a new row into the Group table (parent) the PK id returned by addedGroup.id is -1 so it seems that Members table (child) insertion is trying to insert a new row with groupId = -1 which does not exist and is throwing the error. What is the correct way to add a new Group (parent) and then immediately add a new Member (child) that is associated with the newly added Group?
I think the problem that you have is the ID won't be filled until you update. So you need to change the order of your statements to:
GroupsDataSet.GroupsRow addedGroup = this.groupsDataSet.Groups.AddGroupsRow(groupName, this.type);
this.groupsTableAdapter.Update(this.GroupsDataSet.Groups);
this.groupsDataSet.Members.AddMembersRow(memberName, addedGroup);
this.membersTableAdapter.Update(this.GroupsDataSet.Members);
There is also a Refresh on insert setting that needs to be checked. If you look at Figure 3 in this link: (I am assuming SQL Server is the db.)
http://blogs.msdn.com/b/vsdata/archive/2009/09/14/refresh-the-primary-key-identity-column-during-insert-operation.aspx