linq to sql linking objects by multiple ID fields - c#

Im working on a project at work which is pretty much a commissioning manager and i cant seem to figure out how to link the Items table properly in linq to sql.
I have a package detail table that has (among other things)
DepartmentID, CategoryID, ItemID
And the Items table (is actually a database view as its from a different database and is read only in this app) also have these 3 fields but when i add an association with these 3 fields it doesnt add that as a property object ot the PackageDetail class
am i doing something wrong with the association? all the single ones im doing work fine...

I don't believe that Linq-to-SQL can properly model an association with a composite key:
Is it beneficial to use multicolumn (composite) primary keys when using Linq to SQL?
However, you can still load objects with composite keys in a Linq-to-SQL query using an anonymous object as the (single) key:
http://msdn.microsoft.com/en-us/library/bb399391.aspx

have marked those ID fields as Primary keys? Make sure you assign the necessary columns as primary keys and this should work fine. Hope it helps

Ensure the keys are correctly setup with primary key and foreign key relationship. If that still doesn't work, could you consider adding a new key column, rather than relying on composite key?
Last option with LINQ to SQL is usually manually updating the DBML with an XML editor. A normal single key relationship appears as follows:
<Association Name="Schedule_Profile" Member="Schedule" ThisKey="ScheduleID" Type="Schedule" IsForeignKey="true" />
Suggest you try creating the element yourself, and try setting ThisKey to a csv list of columns. The OtherKey attribute may also be of interest.

It looks like you could just use ItemId and ignore the other 2 since that is the most specific qualifier - in other words, Department and Category are fully determined by itemId.

Did you mean a query like this.
var result = from table in dbContext.table1 join table2 in dbContext.table2 join new { table.DepartmentID, table.CategoryID, table.ItemID} equals new {table2.DepartmentID, table2.CategoryID, table2.ItemID}
select table;

Related

Entity-Framework: Sort on Many-to-Many

I have two entities with a many-to-many relationship and I'm looking for a way to be able to sort the result from the tables.
In other words, when I get a row from table1 and all the corresponding records from table2 I want to be able to have a stored sort order for table2 that's specific for that row in table1.
My first thought was to add a sort column to the table that represents the relation, but to my knowledge there is no way of accessing the new column in the relation.
Does anybody have any suggestions on how to accomplish this?
As Ladislav Mrnka states, if you add the new column to the junction table, there will be a new entity "in the middle" that will make navigation much harder.
If you want to avoid this, but still be able to make the navigation as usual, you can keep the junction table and add a new table, just like the junction, with the order column added. When you need the order info, you can just join this table to get it and use it.
This new table will, of course, require some maintenance. I.e. you can create a delete on cascade for the junction+order to the junction table. And use a trigger (ooops, that's not good!) to create a new row with default order for each new created relation. So, it would be much more advisable to handle this in you business logic.
I know it's too tricky, but there's no magic solution... just choose what is more comfortable to you.
You can add new column to the junction table but the table will become a new entity so your model will now consist of three entities where and two one-to-many relations instead of two entities and single many-to-many relation.
Due to your requirement of sorting table2 results per table1 row and not globally, you have three non-elegant solutions:
The approach Ladislav suggested (with the bad looking model) - add order column, add bridge entity.
The approach JotaBe suggested (with the bad looking schema) - add an additional table and maintain both.
If the context is used only for reading (no need to change relationships) and you don't mind changing the EDMX manually after every update from DB, then you could hack the emdx and change the SSDL definition of the relationship table to an SQL query e.g.
<EntitySet Name="AS_TO_BS" EntityType="BlaBla.Store.AS_TO_BS">
<DefiningQuery>
SELECT ID1, ID2 ORDER BY ORDERVALUE
FROM AS_TO_BS
</DefiningQuery>
</EntitySet>
Instead of:
<EntitySet Name="AS_TO_BS" EntityType="BlaBla.Store.AS_TO_BS"
store:Type="Tables" Schema="MY_SCHEMA" />
See if you can relax your requirements, if not then settle on one of the three solutions.
Edit:
Another idea:
Use a view to duplicate the relationship table, then map the relationship to the view (as read only) and the order entity to the table (writable).
Thank you all for the good answers to my question. I now feel more confident about the pros and cons of the different solutions.
What I ended up doing was this: As it turns out, just adding a sort column to the relation-table doesn't affect the model, update from DB still works and the table still gets mapped as a many-to-many relation. Then I created a stored procedure that fetches the sort column from the relation-table and another stored procedure to update the sort-index of a specified record.

Setting IsPrimaryKey=true on column in table with no primary key

I'm writing a quick app using LINQ to SQL to populate a db with some test data and had a problem because one of the tables had no primary key as described by this bloke Can't Update because table has no primary key.
Taking the top answer I added the IsPrimaryKey attribute to an appropriate column and the app worked even though the I haven't changed the db table itself (i.e. there is still no primary key).
I expect it will be ok for my current intentions but are there any side effects which may come from having a table without a primary key seen as having one by the LINQ object?
(I can only think it might be a problem if I tried to read from a table (or populate to a table) with data where the 'primary key' column has the same value in more than one row).
When using an ORM framework, you can simulate keys and foreign keys at ORM level, thus "hiding and overriding" the database defined ones.
That said, that's a practice that I wouldn't recommend. Even if the model is more important than the database itself, the logical structure should always match. It is ok doing what you did if you're forced to work with a legacy database and you don't have the possibility to fix it (like adding the PK on the table). But try to walk the righteous path everytime you can :)
Tables without a PK = Pure Evil.
Basically if all the table updates go through the LINQ object you should be fine. If you have a DBA that decides to modify data directly though SQL then you can quickly run into issues if he duplicates a row with the same PK value.

Trying to do a hierarchical update results in an error "A foreign key value cannot be inserted"

I'm a bit of a noob with DAO and SQL Server and I'm running into a problem when I'm trying to insert values into two tables that have a relation. The table Photos has a gpsId field which has a foreign key relation with the id field of the GPSLocations table. I want to create a new Photos entry linked to a new GPSLocation, so the code looks something like this:
gpsRow = dataset.GPSLocations.AddGPSLocationsRow("0.0N", "3.2W");
dataset.Photos.AddPhotosRow(#"c:\path\file.jpg", gpsRow);
tableAdapterManager.UpdateAll(dataset);
However this results in the following error:
A foreign key value cannot be inserted
because a corresponding primary key
value does not exist. [ Foreign key
constraint name = photoToGps ]
I'm using SQL Server CE. Is my understanding correct that the TableAdapterManager should be handling this hierarchical update? I just dragged these tables onto the XSD view and relied on its automatic creation of the wrapper classes. Do I need to change anything about the relation (eg to make it a Foreign Key constraint)? I've noticed that under some circumstances the gps id is positive and sometimes negative, is that relevant?
EDIT:
I've also ensured that the update property is set to CASCADE, which results in the same error. Hierarchical updates are set to true and there is a foreign key constraint between the two tables in the designer.
It's just the configuration of your data set. Doubleclick the relation beween the tables in the Visual Studio's dataset designer, choose Both Relation And Foreigh Key Constraint option and in the Update Rule field choose Cascade option and that must be it.
Some information about the subject is in MSDN, you can look here http://msdn.microsoft.com/en-us/library/bb629317.aspx and go to the related topics.
I've managed to track down the source of this problem, which boils down to a limitation of SQL Server CE compared with the full SQL Server. It turns out the major hint that something wasn't right was because the ids were negative. The ids are negative in the DataSet before the row is inserted into the database, at which point it gets resolved to a positive index. The fact that it wasn't becoming a positive index happened because the TableAdapterManager normally does a batch statement of INSERT followed by a SELECT to update the id. However, SQL Server CE doesn't support batch statements, so this requires extra code to be written so that we simulate the SELECT step by responding to the RowUpdated event. This MSDN article explains the steps.
Did you enable Hierarchical Updates as described here?
Is there a foreign key constraint between the two tables (there should be a line on the XSD designer connecting them)? Since your fields are named differently it might not have been automatically added when you dragged the tables to the design surface.
Since the column photoToGps (foreign key) depends on the primary key (id), you cannot add a photoToGps unless there is a corresponding id present. So what you need to is individual updates, instead of doing an UpdateAll. First update the GPSLocations table, and then the other table. That way, you will have an id existing before you add a photoToGPS for it.

How do you use Linq to connect tables in different databases?

I'm a bit of a Linq newbie, and I couldn't find any documentation to help me with what seems to be a pretty trivial problem - so your help will be much appreciated!
I have a table Table1 in database DB1, which has a "pseudo" foreign key Table2ID to table Table2 in database DB2, on the same server. "Pseudo", because obviously I can't have an actual FK spanning two databases.
Now I'm playing around with the O/R designer, and I love the way all the relationships are generated when I bring database objects into the designer... very cool! And I want my Table1 object to have a relationship to Table2, just like it has relationships with all the "real" foreign key-related objects in DB1. But I can't bring Table2 into my db diagram, because it's in the wrong DB.
To synthesize this, I tried creating a view Table2 in DB1, which is simply select * from DB2..Table2. Aha, now I can drop a Table2 object into my diagram. I can even make a parent/child relationship between Table1 and Table2. But when I look at the generated code, Table1 still has no relationship to Table2, which I find most perplexing.
Am I missing a step somewhere? Is there a better/recommended way of doing this?
Thanks!
Later...
Along the lines of what one person suggested, I tried filling in the partial class of Table1 with all the methods required to access Table2, by copying all the structures for a related object within the same DB.
This actually worked for reads, but as soon as I tried to update or insert a record, I got an exception:
An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported.
So it looks like the designers of Linq have actually thought about this scenario, and decided that you are not allowed to connect objects in different databases. That's really a shame... :(
... and even later...
Thanks to #williammandra.com, I found that you need to create the primary key on a view manually. But there's still another problem: for some reason when you load a value from the view Table2 and set it on the new record Table1, then commit changes, it tries to insert a new record into Table2, which obviously causes a PK violation. Any idea why this happens, and how to get around it?
Views don't have primary keys (without it the O/R designer can't create the relationship). Your solution to use a view gets you halfway there.... The step you are missing is setting the "Primary Key" property to true in the O/R designer for the key field in the Table2 view. You still have to create the association manually, but once you save the dbml the relationship will show up in the generated code.
You could create two dbml's, one for each db. Then join the tables in your query:
var tb1 = DataContext1.Table1
var tb2 = DataContext2.Table2
var result = (from t1 in tb1
join t2 in tb2 on tb1.column equals tb2.column
where ...
select ...
)
You could also set tb2 = to your view rather than another datacontext...
Assuming you can access one database from the other you can do this by manually editing the .dbml file.
<Table Name="Table1.dbo.Table" Member="MemberObject">
<Table Name="Table2.dbo.Table" Member="MemberObject">
You might actually be able do this by looking at the properties of a table and changing the source.

LINQ to SQL Association - "Properties do not have matching types"

I am trying to link two fields of a given table to the same field in another table.
I have done this before so I can't work out what is wrong this time.
Anyway:
Table1
- Id (Primary)
- FK-Table2a (Nullable, foreign key relationship in DB to Table2.Id)
- FK-Table2b (Nullable, foreign key relationship in DB to Table2.Id)
Table2
- Id (Primary)
The association works for FK-Table2a but not FK-Table2b.
In fact, when I load into LINQ to SQL, it shows Table2.Id as associated to Table1.Id.
If I try and change this, or add a new association for FK-Table2b to Table2.Id it says: "Properties do not have matching types".
This also works in other projects - maybe I should just copy over the .dbml?
Any ideas?
I see this problem when I try to create one-to-one relationships where one side of the relationship is nullable (so really, one-to-zero/one). LINQ-to-SQL doesn't seem to support this so it appears we are forced to a plural relationship and a collection that will contain zero or one items. Annoying.
No idea on the cause, but I just reconstructed my .dbml from scratch and it fixed itself.
Oh for a "refresh" feature...
I had the same problem. This error appeared when I tried to link different types of fields, or when I tryied to drag-and-drop table to .dbml space, but .dbml already had contained linked tables with different types of linked fields.

Categories

Resources