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

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.

Related

How to know which columns correspond between tables and a view

I've got a view in SQL Server, and would like to join this view with other tables, through my C# application. To accomplish this, I would need to find out which columns the respective view's fields correspond with, in the underlying table. For example, I could have a view like so:
CREATE VIEW [View A]
AS
SELECT Children.Child_ID, Social_Workers.Social_ID
FROM Children
INNER JOIN Social_Workers
ON Children.Social_ID = Social_Workers.Social_ID
I may want to join a table to the above view. To accomplish this, my C# application must somehow know which are the required foreign key and primary key fields within the relationship, thus generating SQL code like so:
SELECT [View A].Child_ID,
Sponsors.User_ID
FROM [View A]
INNER JOIN Sponsors
ON [View A].Child_ID = Sponsors.Child_ID
I have found a way to retrieve the underlying tables within the view, however I am unsure of how to approach the rest of the problem.
I think the following might help, specifically the referenced_entity_name and referenced_minor_name columns.
select * from sys.dm_sql_referenced_entities( 'dbo.ViewA', 'object' ) ;
This DMV was added in SQL Server 2008 so if you have an earlier version, no help I'm sorry.
If i right understand your requirements, you can try to use queries from Find the real column name of an alias used in a view?

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.

linq to sql linking objects by multiple ID fields

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;

Linq to SQL - "This member is defined more than once" error

I have the following linq code...
CMSDataContext dc = new CMSDataContext();
var q = from u in dc.CMSUsers
join d in dc.tblDistricts
on u.DistrictCode equals d.District into orders
select u;
District shows this error:
Ambiguity between 'tblDistrict.District' and 'tblDistrict.District'
Any ideas?
EDIT:
It turns out that I had the same table in two different dbml files. Apparently, I cannot do this. I will have to end up joining a table from one dbml file with another table from a different dbml file. If anyone can enlighten me on how to do this, I will deem it as an answer. Thanks.
If you have a FK releationship between two tables, LINQ-to-SQl will automatically create a property for it.
For example, if you Order object has a CustomerID which is a Foriegn key to the Customers table, Order will automatically have a Customer property. If you already have a Customer property, there will be a conflict.
I had he same problem. The solution was to delete .dbml file from the solution explorer.

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